aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias <[email protected]>2023-07-01 12:17:12 +0200
committerMathias <[email protected]>2023-07-03 19:33:26 +0200
commit60b2f075dcd561cdf3ff069c1cfc5d4177c1a133 (patch)
treeb3e285258cade6618d6bb14e826fee9cf0bb284a
parentd372df7ddb381571fd2964e32b486b6d1cd1ad03 (diff)
parentba4344429264fa7beb99ab19c09059c2d531716d (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into embassy-stm32/rcc-rtc-l4
-rwxr-xr-x.github/ci/doc.sh8
-rw-r--r--.vscode/settings.json6
-rw-r--r--README.md4
-rwxr-xr-xci.sh35
-rwxr-xr-xci_stable.sh4
-rw-r--r--cyw43/README.md12
-rw-r--r--cyw43/src/control.rs5
-rw-r--r--cyw43/src/fmt.rs3
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs24
-rw-r--r--embassy-boot/boot/src/firmware_updater/asynch.rs34
-rw-r--r--embassy-boot/boot/src/firmware_updater/blocking.rs32
-rw-r--r--embassy-boot/boot/src/firmware_updater/mod.rs3
-rw-r--r--embassy-boot/boot/src/lib.rs12
-rw-r--r--embassy-boot/nrf/README.md2
-rw-r--r--embassy-cortex-m/Cargo.toml45
-rw-r--r--embassy-cortex-m/src/lib.rs9
-rw-r--r--embassy-executor/src/arch/cortex_m.rs15
-rw-r--r--embassy-futures/src/block_on.rs12
-rw-r--r--embassy-futures/src/fmt.rs3
-rw-r--r--embassy-hal-common/Cargo.toml16
-rw-r--r--embassy-hal-common/build.rs (renamed from embassy-cortex-m/build.rs)0
-rw-r--r--embassy-hal-common/src/interrupt.rs (renamed from embassy-cortex-m/src/interrupt.rs)214
-rw-r--r--embassy-hal-common/src/lib.rs3
-rw-r--r--embassy-lora/src/iv.rs28
-rw-r--r--embassy-macros/Cargo.toml4
-rw-r--r--embassy-macros/src/lib.rs50
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt.rs66
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt_declare.rs21
-rw-r--r--embassy-macros/src/macros/main.rs9
-rw-r--r--embassy-macros/src/macros/mod.rs2
-rw-r--r--embassy-macros/src/macros/task.rs23
-rw-r--r--embassy-net-driver-channel/Cargo.toml11
-rw-r--r--embassy-net-driver-channel/README.md96
-rw-r--r--embassy-net-driver-channel/src/lib.rs1
-rw-r--r--embassy-net-driver/Cargo.toml11
-rw-r--r--embassy-net-driver/README.md16
-rw-r--r--embassy-net-esp-hosted/Cargo.toml20
-rw-r--r--embassy-net-esp-hosted/src/control.rs139
-rw-r--r--embassy-net-esp-hosted/src/esp_hosted_config.proto432
-rw-r--r--embassy-net-esp-hosted/src/fmt.rs257
-rw-r--r--embassy-net-esp-hosted/src/ioctl.rs123
-rw-r--r--embassy-net-esp-hosted/src/lib.rs337
-rw-r--r--embassy-net-esp-hosted/src/proto.rs652
-rw-r--r--embassy-net-w5500/src/lib.rs5
-rw-r--r--embassy-net/Cargo.toml17
-rw-r--r--embassy-net/README.md64
-rw-r--r--embassy-net/src/device.rs8
-rw-r--r--embassy-net/src/dns.rs1
-rw-r--r--embassy-net/src/lib.rs289
-rw-r--r--embassy-net/src/tcp.rs13
-rw-r--r--embassy-net/src/udp.rs2
-rw-r--r--embassy-nrf/Cargo.toml9
-rw-r--r--embassy-nrf/src/buffered_uarte.rs11
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs56
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs62
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs62
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs60
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs82
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs90
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs94
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs92
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs50
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs72
-rw-r--r--embassy-nrf/src/gpiote.rs17
-rw-r--r--embassy-nrf/src/i2s.rs14
-rw-r--r--embassy-nrf/src/lib.rs39
-rw-r--r--embassy-nrf/src/pdm.rs13
-rw-r--r--embassy-nrf/src/ppi/mod.rs15
-rw-r--r--embassy-nrf/src/pwm.rs7
-rw-r--r--embassy-nrf/src/qdec.rs12
-rw-r--r--embassy-nrf/src/qspi.rs12
-rw-r--r--embassy-nrf/src/rng.rs10
-rw-r--r--embassy-nrf/src/saadc.rs10
-rw-r--r--embassy-nrf/src/spim.rs16
-rw-r--r--embassy-nrf/src/spis.rs16
-rw-r--r--embassy-nrf/src/temp.rs10
-rw-r--r--embassy-nrf/src/time_driver.rs7
-rw-r--r--embassy-nrf/src/timer.rs5
-rw-r--r--embassy-nrf/src/twim.rs12
-rw-r--r--embassy-nrf/src/twis.rs12
-rw-r--r--embassy-nrf/src/uarte.rs117
-rw-r--r--embassy-nrf/src/usb/mod.rs12
-rw-r--r--embassy-nrf/src/usb/vbus_detect.rs12
-rw-r--r--embassy-rp/Cargo.toml18
-rw-r--r--embassy-rp/src/adc.rs146
-rw-r--r--embassy-rp/src/clocks.rs168
-rw-r--r--embassy-rp/src/critical_section_impl.rs19
-rw-r--r--embassy-rp/src/dma.rs62
-rw-r--r--embassy-rp/src/flash.rs84
-rw-r--r--embassy-rp/src/float/div.rs78
-rw-r--r--embassy-rp/src/gpio.rs179
-rw-r--r--embassy-rp/src/i2c.rs347
-rw-r--r--embassy-rp/src/interrupt.rs65
-rw-r--r--embassy-rp/src/lib.rs98
-rw-r--r--embassy-rp/src/multicore.rs62
-rw-r--r--embassy-rp/src/pio.rs468
-rw-r--r--embassy-rp/src/pwm.rs90
-rw-r--r--embassy-rp/src/reset.rs4
-rw-r--r--embassy-rp/src/rtc/mod.rs89
-rw-r--r--embassy-rp/src/spi.rs219
-rw-r--r--embassy-rp/src/timer.rs44
-rw-r--r--embassy-rp/src/uart/buffered.rs275
-rw-r--r--embassy-rp/src/uart/mod.rs317
-rw-r--r--embassy-rp/src/usb.rs307
-rw-r--r--embassy-rp/src/watchdog.rs60
-rw-r--r--embassy-stm32-wpan/Cargo.toml51
-rw-r--r--embassy-stm32-wpan/build.rs45
-rw-r--r--embassy-stm32-wpan/src/channels.rs (renamed from embassy-stm32/src/tl_mbox/channels.rs)16
-rw-r--r--embassy-stm32-wpan/src/cmd.rs104
-rw-r--r--embassy-stm32-wpan/src/consts.rs93
-rw-r--r--embassy-stm32-wpan/src/evt.rs151
-rw-r--r--embassy-stm32-wpan/src/fmt.rs (renamed from embassy-cortex-m/src/fmt.rs)3
-rw-r--r--embassy-stm32-wpan/src/lhci.rs112
-rw-r--r--embassy-stm32-wpan/src/lib.rs137
-rw-r--r--embassy-stm32-wpan/src/shci.rs375
-rw-r--r--embassy-stm32-wpan/src/sub/ble.rs96
-rw-r--r--embassy-stm32-wpan/src/sub/mac.rs113
-rw-r--r--embassy-stm32-wpan/src/sub/mm.rs80
-rw-r--r--embassy-stm32-wpan/src/sub/mod.rs6
-rw-r--r--embassy-stm32-wpan/src/sub/sys.rs87
-rw-r--r--embassy-stm32-wpan/src/tables.rs264
-rw-r--r--embassy-stm32-wpan/src/unsafe_linked_list.rs257
-rw-r--r--embassy-stm32-wpan/tl_mbox.x.in (renamed from embassy-stm32/tl_mbox.x.in)0
-rw-r--r--embassy-stm32/Cargo.toml16
-rw-r--r--embassy-stm32/build.rs27
-rw-r--r--embassy-stm32/src/adc/f1.rs92
-rw-r--r--embassy-stm32/src/adc/v1.rs50
-rw-r--r--embassy-stm32/src/adc/v2.rs87
-rw-r--r--embassy-stm32/src/adc/v3.rs192
-rw-r--r--embassy-stm32/src/adc/v4.rs172
-rw-r--r--embassy-stm32/src/can/bxcan.rs444
-rw-r--r--embassy-stm32/src/crc/v1.rs10
-rw-r--r--embassy-stm32/src/crc/v2v3.rs98
-rw-r--r--embassy-stm32/src/dac.rs278
-rw-r--r--embassy-stm32/src/dac/mod.rs570
-rw-r--r--embassy-stm32/src/dcmi.rs126
-rw-r--r--embassy-stm32/src/dma/bdma.rs97
-rw-r--r--embassy-stm32/src/dma/dma.rs92
-rw-r--r--embassy-stm32/src/dma/dmamux.rs2
-rw-r--r--embassy-stm32/src/dma/gpdma.rs33
-rw-r--r--embassy-stm32/src/dma/mod.rs2
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs403
-rw-r--r--embassy-stm32/src/eth/v1/rx_desc.rs15
-rw-r--r--embassy-stm32/src/eth/v1/tx_desc.rs11
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs29
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs441
-rw-r--r--embassy-stm32/src/exti.rs11
-rw-r--r--embassy-stm32/src/flash/asynch.rs10
-rw-r--r--embassy-stm32/src/flash/f4.rs30
-rw-r--r--embassy-stm32/src/fmc.rs8
-rw-r--r--embassy-stm32/src/gpio.rs36
-rw-r--r--embassy-stm32/src/i2c/mod.rs6
-rw-r--r--embassy-stm32/src/i2c/v1.rs168
-rw-r--r--embassy-stm32/src/i2c/v2.rs390
-rw-r--r--embassy-stm32/src/i2s.rs34
-rw-r--r--embassy-stm32/src/ipcc.rs335
-rw-r--r--embassy-stm32/src/lib.rs121
-rw-r--r--embassy-stm32/src/pwm/complementary_pwm.rs48
-rw-r--r--embassy-stm32/src/pwm/mod.rs58
-rw-r--r--embassy-stm32/src/pwm/simple_pwm.rs36
-rw-r--r--embassy-stm32/src/qspi/mod.rs238
-rw-r--r--embassy-stm32/src/rcc/c0.rs10
-rw-r--r--embassy-stm32/src/rcc/f0.rs23
-rw-r--r--embassy-stm32/src/rcc/f1.rs36
-rw-r--r--embassy-stm32/src/rcc/f2.rs2
-rw-r--r--embassy-stm32/src/rcc/f4.rs28
-rw-r--r--embassy-stm32/src/rcc/f7.rs16
-rw-r--r--embassy-stm32/src/rcc/g0.rs12
-rw-r--r--embassy-stm32/src/rcc/g4.rs409
-rw-r--r--embassy-stm32/src/rcc/h5.rs15
-rw-r--r--embassy-stm32/src/rcc/h7.rs39
-rw-r--r--embassy-stm32/src/rcc/l0.rs10
-rw-r--r--embassy-stm32/src/rcc/l1.rs6
-rw-r--r--embassy-stm32/src/rcc/l4.rs6
-rw-r--r--embassy-stm32/src/rcc/l5.rs6
-rw-r--r--embassy-stm32/src/rcc/u5.rs2
-rw-r--r--embassy-stm32/src/rng.rs46
-rw-r--r--embassy-stm32/src/rtc/datetime.rs44
-rw-r--r--embassy-stm32/src/rtc/mod.rs38
-rw-r--r--embassy-stm32/src/rtc/v2.rs230
-rw-r--r--embassy-stm32/src/rtc/v3.rs229
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs671
-rw-r--r--embassy-stm32/src/spi/mod.rs282
-rw-r--r--embassy-stm32/src/time_driver.rs28
-rw-r--r--embassy-stm32/src/timer/mod.rs70
-rw-r--r--embassy-stm32/src/tl_mbox/ble.rs64
-rw-r--r--embassy-stm32/src/tl_mbox/cmd.rs49
-rw-r--r--embassy-stm32/src/tl_mbox/consts.rs53
-rw-r--r--embassy-stm32/src/tl_mbox/evt.rs136
-rw-r--r--embassy-stm32/src/tl_mbox/ipcc.rs174
-rw-r--r--embassy-stm32/src/tl_mbox/mm.rs67
-rw-r--r--embassy-stm32/src/tl_mbox/mod.rs417
-rw-r--r--embassy-stm32/src/tl_mbox/shci.rs101
-rw-r--r--embassy-stm32/src/tl_mbox/sys.rs83
-rw-r--r--embassy-stm32/src/tl_mbox/unsafe_linked_list.rs125
-rw-r--r--embassy-stm32/src/usart/buffered.rs156
-rw-r--r--embassy-stm32/src/usart/mod.rs425
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs81
-rw-r--r--embassy-stm32/src/usb/mod.rs6
-rw-r--r--embassy-stm32/src/usb/usb.rs513
-rw-r--r--embassy-stm32/src/usb_otg/mod.rs12
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs761
-rw-r--r--embassy-stm32/src/wdg/mod.rs12
-rw-r--r--embassy-sync/src/fmt.rs3
-rw-r--r--embassy-sync/src/pipe.rs4
-rw-r--r--embassy-usb-logger/src/lib.rs2
-rw-r--r--embassy-usb/src/class/cdc_ncm/embassy_net.rs5
-rw-r--r--embassy-usb/src/class/cdc_ncm/mod.rs4
-rw-r--r--embassy-usb/src/lib.rs2
-rw-r--r--examples/boot/application/nrf/.cargo/config.toml4
-rw-r--r--examples/boot/application/nrf/Cargo.toml1
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs7
-rw-r--r--examples/boot/application/rp/.cargo/config.toml2
-rw-r--r--examples/boot/application/rp/Cargo.toml1
-rw-r--r--examples/boot/application/rp/src/bin/a.rs6
-rw-r--r--examples/boot/application/stm32f3/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml1
-rw-r--r--examples/boot/application/stm32f3/src/bin/a.rs7
-rw-r--r--examples/boot/application/stm32f7/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs13
-rw-r--r--examples/boot/application/stm32h7/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rwxr-xr-xexamples/boot/application/stm32h7/flash-boot.sh2
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs13
-rw-r--r--examples/boot/application/stm32l0/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml1
-rw-r--r--examples/boot/application/stm32l0/src/bin/a.rs17
-rw-r--r--examples/boot/application/stm32l1/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml1
-rw-r--r--examples/boot/application/stm32l1/src/bin/a.rs8
-rw-r--r--examples/boot/application/stm32l4/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml1
-rw-r--r--examples/boot/application/stm32l4/src/bin/a.rs10
-rw-r--r--examples/boot/application/stm32wl/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml1
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs12
-rw-r--r--examples/boot/bootloader/nrf/.cargo/config.toml2
-rw-r--r--examples/boot/bootloader/rp/.cargo/config.toml2
-rw-r--r--examples/nrf-rtos-trace/.cargo/config.toml4
-rw-r--r--examples/nrf52840-rtic/.cargo/config.toml9
-rw-r--r--examples/nrf52840-rtic/Cargo.toml21
-rw-r--r--examples/nrf52840-rtic/build.rs35
-rw-r--r--examples/nrf52840-rtic/memory.x7
-rw-r--r--examples/nrf52840-rtic/src/bin/blinky.rs43
-rw-r--r--examples/nrf52840/.cargo/config.toml4
-rw-r--r--examples/nrf52840/Cargo.toml22
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs16
-rw-r--r--examples/nrf52840/src/bin/nvmc.rs2
-rw-r--r--examples/nrf52840/src/bin/self_spawn.rs6
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs6
-rw-r--r--examples/nrf52840/src/bin/wdt.rs2
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs139
-rw-r--r--examples/nrf5340/.cargo/config.toml4
-rw-r--r--examples/rp/.cargo/config.toml2
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp/src/bin/button.rs5
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs6
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs6
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs6
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs6
-rw-r--r--examples/rp/src/bin/multiprio.rs18
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs4
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs6
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs59
-rw-r--r--examples/rp/src/bin/wifi_scan.rs4
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs8
-rw-r--r--examples/std/README.md23
-rw-r--r--examples/std/src/bin/net.rs4
-rw-r--r--examples/std/src/bin/net_dns.rs4
-rw-r--r--examples/std/src/bin/net_udp.rs4
-rw-r--r--examples/std/src/bin/tcp_accept.rs4
-rw-r--r--examples/stm32c0/.cargo/config.toml4
-rw-r--r--examples/stm32c0/Cargo.toml2
-rw-r--r--examples/stm32f0/.cargo/config.toml2
-rw-r--r--examples/stm32f0/Cargo.toml2
-rw-r--r--examples/stm32f0/src/bin/multiprio.rs14
-rw-r--r--examples/stm32f0/src/bin/wdg.rs4
-rw-r--r--examples/stm32f1/.cargo/config.toml4
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f2/.cargo/config.toml4
-rw-r--r--examples/stm32f2/Cargo.toml2
-rw-r--r--examples/stm32f3/.cargo/config.toml4
-rw-r--r--examples/stm32f3/Cargo.toml2
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs14
-rw-r--r--examples/stm32f4/.cargo/config.toml4
-rw-r--r--examples/stm32f4/Cargo.toml2
-rw-r--r--examples/stm32f4/src/bin/can.rs13
-rw-r--r--examples/stm32f4/src/bin/dac.rs9
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs14
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs8
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32f4/src/bin/wdt.rs8
-rw-r--r--examples/stm32f7/.cargo/config.toml4
-rw-r--r--examples/stm32f7/Cargo.toml2
-rw-r--r--examples/stm32f7/build.rs3
-rw-r--r--examples/stm32f7/src/bin/eth.rs4
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32g0/.cargo/config.toml4
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32g4/.cargo/config.toml4
-rw-r--r--examples/stm32g4/Cargo.toml3
-rw-r--r--examples/stm32g4/src/bin/pll.rs35
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs120
-rw-r--r--examples/stm32h5/.cargo/config.toml2
-rw-r--r--examples/stm32h5/Cargo.toml2
-rw-r--r--examples/stm32h5/src/bin/eth.rs4
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs8
-rw-r--r--examples/stm32h7/.cargo/config.toml2
-rw-r--r--examples/stm32h7/Cargo.toml2
-rw-r--r--examples/stm32h7/src/bin/dac.rs9
-rw-r--r--examples/stm32h7/src/bin/eth.rs4
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs4
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs54
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32h7/src/bin/wdg.rs4
-rw-r--r--examples/stm32l0/.cargo/config.toml4
-rw-r--r--examples/stm32l0/Cargo.toml2
-rw-r--r--examples/stm32l1/.cargo/config.toml4
-rw-r--r--examples/stm32l1/Cargo.toml2
-rw-r--r--examples/stm32l4/.cargo/config.toml8
-rw-r--r--examples/stm32l4/Cargo.toml4
-rw-r--r--examples/stm32l4/src/bin/adc.rs10
-rw-r--r--examples/stm32l4/src/bin/dac.rs19
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs137
-rw-r--r--examples/stm32l4/src/bin/rtc.rs1
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32l5/.cargo/config.toml4
-rw-r--r--examples/stm32l5/Cargo.toml2
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs4
-rw-r--r--examples/stm32u5/.cargo/config.toml4
-rw-r--r--examples/stm32u5/Cargo.toml2
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32wb/.cargo/config.toml4
-rw-r--r--examples/stm32wb/Cargo.toml24
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs249
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs13
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs (renamed from examples/stm32wb/src/bin/tl_mbox_tx_rx.rs)62
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_mac.rs66
-rw-r--r--examples/stm32wl/.cargo/config.toml4
-rw-r--r--examples/stm32wl/Cargo.toml2
-rw-r--r--examples/stm32wl/src/bin/lora_lorawan.rs2
-rw-r--r--examples/stm32wl/src/bin/random.rs8
-rw-r--r--tests/nrf/Cargo.toml4
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs270
-rw-r--r--tests/perf-server/Cargo.toml8
-rwxr-xr-xtests/perf-server/deploy.sh11
-rw-r--r--tests/perf-server/perf-server.service16
-rw-r--r--tests/perf-server/src/main.rs90
-rw-r--r--tests/rp/Cargo.toml10
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs260
-rw-r--r--tests/rp/src/bin/float.rs10
-rw-r--r--tests/stm32/Cargo.toml18
-rw-r--r--tests/stm32/src/bin/can.rs78
-rw-r--r--tests/stm32/src/bin/rtc.rs6
-rw-r--r--tests/stm32/src/bin/tl_mbox.rs249
-rw-r--r--tests/stm32/src/bin/usart_dma.rs29
357 files changed, 14155 insertions, 8418 deletions
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 736249368..1402e742f 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -9,12 +9,17 @@ export CARGO_TARGET_DIR=/ci/cache/target
9export BUILDER_THREADS=6 9export BUILDER_THREADS=6
10export BUILDER_COMPRESS=true 10export BUILDER_COMPRESS=true
11 11
12# force rustup to download the toolchain before starting building.
13# Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently.
14# They all see the toolchain is not installed and try to install it in parallel
15# which makes rustup very sad
16rustc --version > /dev/null
17
12docserver-builder -i ./embassy-stm32 -o crates/embassy-stm32/git.zup 18docserver-builder -i ./embassy-stm32 -o crates/embassy-stm32/git.zup
13docserver-builder -i ./embassy-boot/boot -o crates/embassy-boot/git.zup 19docserver-builder -i ./embassy-boot/boot -o crates/embassy-boot/git.zup
14docserver-builder -i ./embassy-boot/nrf -o crates/embassy-boot-nrf/git.zup 20docserver-builder -i ./embassy-boot/nrf -o crates/embassy-boot-nrf/git.zup
15docserver-builder -i ./embassy-boot/rp -o crates/embassy-boot-rp/git.zup 21docserver-builder -i ./embassy-boot/rp -o crates/embassy-boot-rp/git.zup
16docserver-builder -i ./embassy-boot/stm32 -o crates/embassy-boot-stm32/git.zup 22docserver-builder -i ./embassy-boot/stm32 -o crates/embassy-boot-stm32/git.zup
17docserver-builder -i ./embassy-cortex-m -o crates/embassy-cortex-m/git.zup
18docserver-builder -i ./embassy-embedded-hal -o crates/embassy-embedded-hal/git.zup 23docserver-builder -i ./embassy-embedded-hal -o crates/embassy-embedded-hal/git.zup
19docserver-builder -i ./embassy-executor -o crates/embassy-executor/git.zup 24docserver-builder -i ./embassy-executor -o crates/embassy-executor/git.zup
20docserver-builder -i ./embassy-futures -o crates/embassy-futures/git.zup 25docserver-builder -i ./embassy-futures -o crates/embassy-futures/git.zup
@@ -32,6 +37,7 @@ docserver-builder -i ./embassy-usb-logger -o crates/embassy-usb-logger/git.zup
32docserver-builder -i ./cyw43 -o crates/cyw43/git.zup 37docserver-builder -i ./cyw43 -o crates/cyw43/git.zup
33docserver-builder -i ./cyw43-pio -o crates/cyw43-pio/git.zup 38docserver-builder -i ./cyw43-pio -o crates/cyw43-pio/git.zup
34docserver-builder -i ./embassy-net-w5500 -o crates/embassy-net-w5500/git.zup 39docserver-builder -i ./embassy-net-w5500 -o crates/embassy-net-w5500/git.zup
40docserver-builder -i ./embassy-stm32-wpan -o crates/embassy-stm32-wpan/git.zup
35 41
36export KUBECONFIG=/ci/secrets/kubeconfig.yml 42export KUBECONFIG=/ci/secrets/kubeconfig.yml
37POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 43POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 9ef7fe1ce..725fb69d0 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -6,16 +6,16 @@
6 "rust-analyzer.check.allTargets": false, 6 "rust-analyzer.check.allTargets": false,
7 "rust-analyzer.check.noDefaultFeatures": true, 7 "rust-analyzer.check.noDefaultFeatures": true,
8 "rust-analyzer.cargo.noDefaultFeatures": true, 8 "rust-analyzer.cargo.noDefaultFeatures": true,
9 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 9 "rust-analyzer.cargo.target": "thumbv7m-none-eabi",
10 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 10 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
11 "rust-analyzer.cargo.features": [ 11 "rust-analyzer.cargo.features": [
12 "nightly", 12 ///"nightly",
13 ], 13 ],
14 "rust-analyzer.linkedProjects": [ 14 "rust-analyzer.linkedProjects": [
15 // Declare for the target you wish to develop 15 // Declare for the target you wish to develop
16 // "embassy-executor/Cargo.toml", 16 // "embassy-executor/Cargo.toml",
17 // "embassy-sync/Cargo.toml", 17 // "embassy-sync/Cargo.toml",
18 "examples/nrf52840/Cargo.toml", 18 "examples/stm32wl/Cargo.toml",
19 // "examples/nrf5340/Cargo.toml", 19 // "examples/nrf5340/Cargo.toml",
20 // "examples/nrf-rtos-trace/Cargo.toml", 20 // "examples/nrf-rtos-trace/Cargo.toml",
21 // "examples/rp/Cargo.toml", 21 // "examples/rp/Cargo.toml",
diff --git a/README.md b/README.md
index 315d247ee..b05e55aa5 100644
--- a/README.md
+++ b/README.md
@@ -99,10 +99,10 @@ Examples are found in the `examples/` folder seperated by the chip manufacturer
99 99
100### Running examples 100### Running examples
101 101
102- Install `probe-rs-cli` with defmt support. 102- Install `probe-rs`.
103 103
104```bash 104```bash
105cargo install probe-rs-cli 105cargo install probe-rs --features cli
106``` 106```
107 107
108- Change directory to the sample's base directory. For example: 108- Change directory to the sample's base directory. For example:
diff --git a/ci.sh b/ci.sh
index 3d6e28796..a03efb856 100755
--- a/ci.sh
+++ b/ci.sh
@@ -3,7 +3,7 @@
3set -euo pipefail 3set -euo pipefail
4 4
5export RUSTFLAGS=-Dwarnings 5export RUSTFLAGS=-Dwarnings
6export DEFMT_LOG=trace 6export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
7 7
8# needed by wifi examples 8# needed by wifi examples
9export WIFI_NETWORK=x 9export WIFI_NETWORK=x
@@ -25,11 +25,19 @@ cargo batch \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
26 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 26 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
27 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ 27 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
28 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \ 28 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
29 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ 29 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
30 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ 30 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
31 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \ 31 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
32 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \ 32 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \
33 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
34 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \
35 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \
36 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits,nightly \
37 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
38 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits \
39 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \
40 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits,nightly \
33 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \ 41 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
34 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \ 42 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
35 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \ 43 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
@@ -104,6 +112,7 @@ cargo batch \
104 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ 112 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
105 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ 113 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
106 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ 114 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
115 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
107 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ 116 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
108 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ 117 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
109 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ 118 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
@@ -124,16 +133,16 @@ cargo batch \
124 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ 133 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
125 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ 134 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
126 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ 135 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
127 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 --out-dir out/examples/boot/nrf --bin b \ 136 --- 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/nrf \
128 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns --out-dir out/examples/boot/nrf --bin b \ 137 --- 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/nrf \
129 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/boot/rp --bin b \ 138 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
130 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32f3 --bin b \ 139 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
131 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32f7 --bin b \ 140 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
132 --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32h7 --bin b \ 141 --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32h7 \
133 --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/boot/stm32l0 --bin b \ 142 --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \
134 --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/boot/stm32l1 --bin b \ 143 --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \
135 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32l4 --bin b \ 144 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \
136 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wl --bin b \ 145 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \
137 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 146 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
138 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 147 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
139 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ 148 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
@@ -159,4 +168,4 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
159 exit 168 exit
160fi 169fi
161 170
162teleprobe client run -r out/tests \ No newline at end of file 171teleprobe client run -r out/tests
diff --git a/ci_stable.sh b/ci_stable.sh
index a67087ffb..daae98961 100755
--- a/ci_stable.sh
+++ b/ci_stable.sh
@@ -14,9 +14,11 @@ cargo batch \
14 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ 14 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
15 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ 15 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
16 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \ 16 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
17 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \ 17 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
18 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ 18 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
19 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ 19 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
20 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
21 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \
20 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \ 22 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
21 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \ 23 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
22 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \ 24 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
diff --git a/cyw43/README.md b/cyw43/README.md
index defea489f..e4a81410d 100644
--- a/cyw43/README.md
+++ b/cyw43/README.md
@@ -1,6 +1,6 @@
1# cyw43 1# cyw43
2 2
3WIP driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). 3Rust driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver).
4 4
5## Current status 5## Current status
6 6
@@ -19,18 +19,18 @@ Working:
19TODO: 19TODO:
20 20
21- Setting a custom MAC address. 21- Setting a custom MAC address.
22- Bus sleep (unclear what the benefit is. Is it needed for IRQs? or is it just power consumption optimization?) 22- Bus sleep (for power consumption optimization)
23 23
24## Running the examples 24## Running the examples
25 25
26- `cargo install probe-rs-cli` 26- `cargo install probe-rs --features cli`
27- `cd examples/rpi-pico-w` 27- `cd examples/rp`
28### Example 1: Scan the wifi stations 28### Example 1: Scan the wifi stations
29- `cargo run --release --bin wifi_scan` 29- `cargo run --release --bin wifi_scan`
30### Example 2: Create an access point (IP and credentials in the code) 30### Example 2: Create an access point (IP and credentials in the code)
31- `cargo run --release --bin tcp_server_ap` 31- `cargo run --release --bin wifi_ap_tcp_server`
32### Example 3: Connect to an existing network and create a server 32### Example 3: Connect to an existing network and create a server
33- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release` 33- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release --bin wifi_tcp_server`
34 34
35After a few seconds, you should see that DHCP picks up an IP address like this 35After a few seconds, you should see that DHCP picks up an IP address like this
36``` 36```
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 6919d569e..c67614dd6 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -381,10 +381,7 @@ impl<'a> Control<'a> {
381 } 381 }
382 382
383 let ioctl = CancelOnDrop(self.ioctl_state); 383 let ioctl = CancelOnDrop(self.ioctl_state);
384 384 let resp_len = ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
385 ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
386 let resp_len = ioctl.0.wait_complete().await;
387
388 ioctl.defuse(); 385 ioctl.defuse();
389 386
390 resp_len 387 resp_len
diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs
index 5730447b3..9534c101c 100644
--- a/cyw43/src/fmt.rs
+++ b/cyw43/src/fmt.rs
@@ -197,9 +197,6 @@ macro_rules! unwrap {
197 } 197 }
198} 198}
199 199
200#[cfg(feature = "defmt-timestamp-uptime")]
201defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq)] 200#[derive(Debug, Copy, Clone, Eq, PartialEq)]
204pub struct NoneError; 201pub struct NoneError;
205 202
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
index 743d0c342..aecba0755 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
@@ -20,13 +20,13 @@ fn main() -> ! {
20 let led = Output::new(p.PB14, Level::Low, Speed::Low); 20 let led = Output::new(p.PB14, Level::Low, Speed::Low);
21 let mut button = Input::new(p.PC13, Pull::Up); 21 let mut button = Input::new(p.PC13, Pull::Up);
22 22
23 cortex_m::interrupt::free(|cs| unsafe { 23 cortex_m::interrupt::free(|cs| {
24 enable_interrupt(&mut button); 24 enable_interrupt(&mut button);
25 25
26 LED.borrow(cs).borrow_mut().replace(led); 26 LED.borrow(cs).borrow_mut().replace(led);
27 BUTTON.borrow(cs).borrow_mut().replace(button); 27 BUTTON.borrow(cs).borrow_mut().replace(button);
28 28
29 NVIC::unmask(pac::Interrupt::EXTI15_10); 29 unsafe { NVIC::unmask(pac::Interrupt::EXTI15_10) };
30 }); 30 });
31 31
32 loop { 32 loop {
@@ -64,25 +64,21 @@ const PORT: u8 = 2;
64const PIN: usize = 13; 64const PIN: usize = 13;
65fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool { 65fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool {
66 let exti = pac::EXTI; 66 let exti = pac::EXTI;
67 unsafe { 67 let pin = PIN;
68 let pin = PIN; 68 let lines = exti.pr(0).read();
69 let lines = exti.pr(0).read(); 69 lines.line(pin)
70 lines.line(pin)
71 }
72} 70}
73 71
74fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { 72fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
75 let exti = pac::EXTI; 73 let exti = pac::EXTI;
76 unsafe { 74 let pin = PIN;
77 let pin = PIN; 75 let mut lines = exti.pr(0).read();
78 let mut lines = exti.pr(0).read(); 76 lines.set_line(pin, true);
79 lines.set_line(pin, true); 77 exti.pr(0).write_value(lines);
80 exti.pr(0).write_value(lines);
81 }
82} 78}
83 79
84fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { 80fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
85 cortex_m::interrupt::free(|_| unsafe { 81 cortex_m::interrupt::free(|_| {
86 let rcc = pac::RCC; 82 let rcc = pac::RCC;
87 rcc.apb2enr().modify(|w| w.set_syscfgen(true)); 83 rcc.apb2enr().modify(|w| w.set_syscfgen(true));
88 84
diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs
index 0b3f88313..20731ee0a 100644
--- a/embassy-boot/boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/boot/src/firmware_updater/asynch.rs
@@ -56,6 +56,16 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> {
56 } 56 }
57 } 57 }
58 58
59 // Make sure we are running a booted firmware to avoid reverting to a bad state.
60 async fn verify_booted(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> {
61 assert_eq!(aligned.len(), STATE::WRITE_SIZE);
62 if self.get_state(aligned).await? == State::Boot {
63 Ok(())
64 } else {
65 Err(FirmwareUpdaterError::BadState)
66 }
67 }
68
59 /// Obtain the current state. 69 /// Obtain the current state.
60 /// 70 ///
61 /// This is useful to check if the bootloader has just done a swap, in order 71 /// This is useful to check if the bootloader has just done a swap, in order
@@ -98,6 +108,8 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> {
98 assert_eq!(_aligned.len(), STATE::WRITE_SIZE); 108 assert_eq!(_aligned.len(), STATE::WRITE_SIZE);
99 assert!(_update_len <= self.dfu.capacity() as u32); 109 assert!(_update_len <= self.dfu.capacity() as u32);
100 110
111 self.verify_booted(_aligned).await?;
112
101 #[cfg(feature = "ed25519-dalek")] 113 #[cfg(feature = "ed25519-dalek")]
102 { 114 {
103 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; 115 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
@@ -217,8 +229,16 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> {
217 /// # Safety 229 /// # Safety
218 /// 230 ///
219 /// Failing to meet alignment and size requirements may result in a panic. 231 /// Failing to meet alignment and size requirements may result in a panic.
220 pub async fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { 232 pub async fn write_firmware(
233 &mut self,
234 aligned: &mut [u8],
235 offset: usize,
236 data: &[u8],
237 ) -> Result<(), FirmwareUpdaterError> {
221 assert!(data.len() >= DFU::ERASE_SIZE); 238 assert!(data.len() >= DFU::ERASE_SIZE);
239 assert_eq!(aligned.len(), STATE::WRITE_SIZE);
240
241 self.verify_booted(aligned).await?;
222 242
223 self.dfu.erase(offset as u32, (offset + data.len()) as u32).await?; 243 self.dfu.erase(offset as u32, (offset + data.len()) as u32).await?;
224 244
@@ -232,7 +252,14 @@ impl<DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<DFU, STATE> {
232 /// 252 ///
233 /// Using this instead of `write_firmware` allows for an optimized API in 253 /// Using this instead of `write_firmware` allows for an optimized API in
234 /// exchange for added complexity. 254 /// exchange for added complexity.
235 pub async fn prepare_update(&mut self) -> Result<&mut DFU, FirmwareUpdaterError> { 255 ///
256 /// # Safety
257 ///
258 /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to.
259 pub async fn prepare_update(&mut self, aligned: &mut [u8]) -> Result<&mut DFU, FirmwareUpdaterError> {
260 assert_eq!(aligned.len(), STATE::WRITE_SIZE);
261 self.verify_booted(aligned).await?;
262
236 self.dfu.erase(0, self.dfu.capacity() as u32).await?; 263 self.dfu.erase(0, self.dfu.capacity() as u32).await?;
237 264
238 Ok(&mut self.dfu) 265 Ok(&mut self.dfu)
@@ -255,13 +282,14 @@ mod tests {
255 let flash = Mutex::<NoopRawMutex, _>::new(MemFlash::<131072, 4096, 8>::default()); 282 let flash = Mutex::<NoopRawMutex, _>::new(MemFlash::<131072, 4096, 8>::default());
256 let state = Partition::new(&flash, 0, 4096); 283 let state = Partition::new(&flash, 0, 4096);
257 let dfu = Partition::new(&flash, 65536, 65536); 284 let dfu = Partition::new(&flash, 65536, 65536);
285 let mut aligned = [0; 8];
258 286
259 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; 287 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
260 let mut to_write = [0; 4096]; 288 let mut to_write = [0; 4096];
261 to_write[..7].copy_from_slice(update.as_slice()); 289 to_write[..7].copy_from_slice(update.as_slice());
262 290
263 let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }); 291 let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state });
264 block_on(updater.write_firmware(0, to_write.as_slice())).unwrap(); 292 block_on(updater.write_firmware(&mut aligned, 0, to_write.as_slice())).unwrap();
265 let mut chunk_buf = [0; 2]; 293 let mut chunk_buf = [0; 2];
266 let mut hash = [0; 20]; 294 let mut hash = [0; 20];
267 block_on(updater.hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); 295 block_on(updater.hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap();
diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs
index 551150c4f..f03f53e4d 100644
--- a/embassy-boot/boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/boot/src/firmware_updater/blocking.rs
@@ -58,6 +58,16 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> {
58 } 58 }
59 } 59 }
60 60
61 // Make sure we are running a booted firmware to avoid reverting to a bad state.
62 fn verify_booted(&mut self, aligned: &mut [u8]) -> Result<(), FirmwareUpdaterError> {
63 assert_eq!(aligned.len(), STATE::WRITE_SIZE);
64 if self.get_state(aligned)? == State::Boot {
65 Ok(())
66 } else {
67 Err(FirmwareUpdaterError::BadState)
68 }
69 }
70
61 /// Obtain the current state. 71 /// Obtain the current state.
62 /// 72 ///
63 /// This is useful to check if the bootloader has just done a swap, in order 73 /// This is useful to check if the bootloader has just done a swap, in order
@@ -100,6 +110,8 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> {
100 assert_eq!(_aligned.len(), STATE::WRITE_SIZE); 110 assert_eq!(_aligned.len(), STATE::WRITE_SIZE);
101 assert!(_update_len <= self.dfu.capacity() as u32); 111 assert!(_update_len <= self.dfu.capacity() as u32);
102 112
113 self.verify_booted(_aligned)?;
114
103 #[cfg(feature = "ed25519-dalek")] 115 #[cfg(feature = "ed25519-dalek")]
104 { 116 {
105 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; 117 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
@@ -219,8 +231,15 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> {
219 /// # Safety 231 /// # Safety
220 /// 232 ///
221 /// Failing to meet alignment and size requirements may result in a panic. 233 /// Failing to meet alignment and size requirements may result in a panic.
222 pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { 234 pub fn write_firmware(
235 &mut self,
236 aligned: &mut [u8],
237 offset: usize,
238 data: &[u8],
239 ) -> Result<(), FirmwareUpdaterError> {
223 assert!(data.len() >= DFU::ERASE_SIZE); 240 assert!(data.len() >= DFU::ERASE_SIZE);
241 assert_eq!(aligned.len(), STATE::WRITE_SIZE);
242 self.verify_booted(aligned)?;
224 243
225 self.dfu.erase(offset as u32, (offset + data.len()) as u32)?; 244 self.dfu.erase(offset as u32, (offset + data.len()) as u32)?;
226 245
@@ -234,7 +253,13 @@ impl<DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<DFU, STATE> {
234 /// 253 ///
235 /// Using this instead of `write_firmware` allows for an optimized API in 254 /// Using this instead of `write_firmware` allows for an optimized API in
236 /// exchange for added complexity. 255 /// exchange for added complexity.
237 pub fn prepare_update(&mut self) -> Result<&mut DFU, FirmwareUpdaterError> { 256 ///
257 /// # Safety
258 ///
259 /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being written to.
260 pub fn prepare_update(&mut self, aligned: &mut [u8]) -> Result<&mut DFU, FirmwareUpdaterError> {
261 assert_eq!(aligned.len(), STATE::WRITE_SIZE);
262 self.verify_booted(aligned)?;
238 self.dfu.erase(0, self.dfu.capacity() as u32)?; 263 self.dfu.erase(0, self.dfu.capacity() as u32)?;
239 264
240 Ok(&mut self.dfu) 265 Ok(&mut self.dfu)
@@ -264,7 +289,8 @@ mod tests {
264 to_write[..7].copy_from_slice(update.as_slice()); 289 to_write[..7].copy_from_slice(update.as_slice());
265 290
266 let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }); 291 let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state });
267 updater.write_firmware(0, to_write.as_slice()).unwrap(); 292 let mut aligned = [0; 8];
293 updater.write_firmware(&mut aligned, 0, to_write.as_slice()).unwrap();
268 let mut chunk_buf = [0; 2]; 294 let mut chunk_buf = [0; 2];
269 let mut hash = [0; 20]; 295 let mut hash = [0; 20];
270 updater 296 updater
diff --git a/embassy-boot/boot/src/firmware_updater/mod.rs b/embassy-boot/boot/src/firmware_updater/mod.rs
index a37984a3a..55ce8f363 100644
--- a/embassy-boot/boot/src/firmware_updater/mod.rs
+++ b/embassy-boot/boot/src/firmware_updater/mod.rs
@@ -26,6 +26,8 @@ pub enum FirmwareUpdaterError {
26 Flash(NorFlashErrorKind), 26 Flash(NorFlashErrorKind),
27 /// Signature errors. 27 /// Signature errors.
28 Signature(signature::Error), 28 Signature(signature::Error),
29 /// Bad state.
30 BadState,
29} 31}
30 32
31#[cfg(feature = "defmt")] 33#[cfg(feature = "defmt")]
@@ -34,6 +36,7 @@ impl defmt::Format for FirmwareUpdaterError {
34 match self { 36 match self {
35 FirmwareUpdaterError::Flash(_) => defmt::write!(fmt, "FirmwareUpdaterError::Flash(_)"), 37 FirmwareUpdaterError::Flash(_) => defmt::write!(fmt, "FirmwareUpdaterError::Flash(_)"),
36 FirmwareUpdaterError::Signature(_) => defmt::write!(fmt, "FirmwareUpdaterError::Signature(_)"), 38 FirmwareUpdaterError::Signature(_) => defmt::write!(fmt, "FirmwareUpdaterError::Signature(_)"),
39 FirmwareUpdaterError::BadState => defmt::write!(fmt, "FirmwareUpdaterError::BadState"),
37 } 40 }
38 } 41 }
39} 42}
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 45a87bd0e..016362b86 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -51,6 +51,8 @@ impl<const N: usize> AsMut<[u8]> for AlignedBuffer<N> {
51 51
52#[cfg(test)] 52#[cfg(test)]
53mod tests { 53mod tests {
54 #![allow(unused_imports)]
55
54 use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; 56 use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
55 #[cfg(feature = "nightly")] 57 #[cfg(feature = "nightly")]
56 use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; 58 use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash;
@@ -120,9 +122,13 @@ mod tests {
120 dfu: flash.dfu(), 122 dfu: flash.dfu(),
121 state: flash.state(), 123 state: flash.state(),
122 }); 124 });
123 block_on(updater.write_firmware(0, &UPDATE)).unwrap(); 125 block_on(updater.write_firmware(&mut aligned, 0, &UPDATE)).unwrap();
124 block_on(updater.mark_updated(&mut aligned)).unwrap(); 126 block_on(updater.mark_updated(&mut aligned)).unwrap();
125 127
128 // Writing after marking updated is not allowed until marked as booted.
129 let res: Result<(), FirmwareUpdaterError> = block_on(updater.write_firmware(&mut aligned, 0, &UPDATE));
130 assert!(matches!(res, Err::<(), _>(FirmwareUpdaterError::BadState)));
131
126 let flash = flash.into_blocking(); 132 let flash = flash.into_blocking();
127 let mut bootloader = BootLoader::new(BootLoaderConfig { 133 let mut bootloader = BootLoader::new(BootLoaderConfig {
128 active: flash.active(), 134 active: flash.active(),
@@ -188,7 +194,7 @@ mod tests {
188 dfu: flash.dfu(), 194 dfu: flash.dfu(),
189 state: flash.state(), 195 state: flash.state(),
190 }); 196 });
191 block_on(updater.write_firmware(0, &UPDATE)).unwrap(); 197 block_on(updater.write_firmware(&mut aligned, 0, &UPDATE)).unwrap();
192 block_on(updater.mark_updated(&mut aligned)).unwrap(); 198 block_on(updater.mark_updated(&mut aligned)).unwrap();
193 199
194 let flash = flash.into_blocking(); 200 let flash = flash.into_blocking();
@@ -230,7 +236,7 @@ mod tests {
230 dfu: flash.dfu(), 236 dfu: flash.dfu(),
231 state: flash.state(), 237 state: flash.state(),
232 }); 238 });
233 block_on(updater.write_firmware(0, &UPDATE)).unwrap(); 239 block_on(updater.write_firmware(&mut aligned, 0, &UPDATE)).unwrap();
234 block_on(updater.mark_updated(&mut aligned)).unwrap(); 240 block_on(updater.mark_updated(&mut aligned)).unwrap();
235 241
236 let flash = flash.into_blocking(); 242 let flash = flash.into_blocking();
diff --git a/embassy-boot/nrf/README.md b/embassy-boot/nrf/README.md
index 7ce3c7021..fe581823d 100644
--- a/embassy-boot/nrf/README.md
+++ b/embassy-boot/nrf/README.md
@@ -6,7 +6,7 @@ An adaptation of `embassy-boot` for nRF.
6 6
7## Features 7## Features
8 8
9* Load applications with our without the softdevice. 9* Load applications with or without the softdevice.
10* Configure bootloader partitions based on linker script. 10* Configure bootloader partitions based on linker script.
11* Using watchdog timer to detect application failure. 11* Using watchdog timer to detect application failure.
12 12
diff --git a/embassy-cortex-m/Cargo.toml b/embassy-cortex-m/Cargo.toml
deleted file mode 100644
index 70adda7df..000000000
--- a/embassy-cortex-m/Cargo.toml
+++ /dev/null
@@ -1,45 +0,0 @@
1[package]
2name = "embassy-cortex-m"
3version = "0.1.0"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6
7[package.metadata.embassy_docs]
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-cortex-m-v$VERSION/embassy-cortex-m/src/"
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-cortex-m/src/"
10features = ["prio-bits-3"]
11flavors = [
12 { name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] },
13 { name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] },
14 { name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] },
15 { name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] },
16 { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] },
17]
18
19[features]
20default = []
21
22# Define the number of NVIC priority bits.
23prio-bits-0 = []
24prio-bits-1 = []
25prio-bits-2 = []
26prio-bits-3 = []
27prio-bits-4 = []
28prio-bits-5 = []
29prio-bits-6 = []
30prio-bits-7 = []
31prio-bits-8 = []
32
33[dependencies]
34defmt = { version = "0.3", optional = true }
35log = { version = "0.4.14", optional = true }
36
37embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
38embassy-executor = { version = "0.2.0", path = "../embassy-executor"}
39embassy-macros = { version = "0.2.0", path = "../embassy-macros"}
40embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"}
41atomic-polyfill = "1.0.1"
42critical-section = "1.1"
43cfg-if = "1.0.0"
44cortex-m = "0.7.6"
45
diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs
deleted file mode 100644
index 7bc16d3ba..000000000
--- a/embassy-cortex-m/src/lib.rs
+++ /dev/null
@@ -1,9 +0,0 @@
1//! Embassy executor and interrupt handling specific to cortex-m devices.
2#![no_std]
3#![warn(missing_docs)]
4
5// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt;
7
8pub use embassy_executor as executor;
9pub mod interrupt;
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs
index d6a55c4c7..94c8134d6 100644
--- a/embassy-executor/src/arch/cortex_m.rs
+++ b/embassy-executor/src/arch/cortex_m.rs
@@ -205,5 +205,20 @@ mod interrupt {
205 205
206 executor.spawner().make_send() 206 executor.spawner().make_send()
207 } 207 }
208
209 /// Get a SendSpawner for this executor
210 ///
211 /// This returns a [`SendSpawner`] you can use to spawn tasks on this
212 /// executor.
213 ///
214 /// This MUST only be called on an executor that has already been spawned.
215 /// The function will panic otherwise.
216 pub fn spawner(&'static self) -> crate::SendSpawner {
217 if !self.started.load(Ordering::Acquire) {
218 panic!("InterruptExecutor::spawner() called on uninitialized executor.");
219 }
220 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
221 executor.spawner().make_send()
222 }
208 } 223 }
209} 224}
diff --git a/embassy-futures/src/block_on.rs b/embassy-futures/src/block_on.rs
index da90351ec..77695216c 100644
--- a/embassy-futures/src/block_on.rs
+++ b/embassy-futures/src/block_on.rs
@@ -31,3 +31,15 @@ pub fn block_on<F: Future>(mut fut: F) -> F::Output {
31 } 31 }
32 } 32 }
33} 33}
34
35/// Poll a future once.
36pub fn poll_once<F: Future>(mut fut: F) -> Poll<F::Output> {
37 // safety: we don't move the future after this line.
38 let mut fut = unsafe { Pin::new_unchecked(&mut fut) };
39
40 let raw_waker = RawWaker::new(ptr::null(), &VTABLE);
41 let waker = unsafe { Waker::from_raw(raw_waker) };
42 let mut cx = Context::from_waker(&waker);
43
44 fut.as_mut().poll(&mut cx)
45}
diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs
index f8bb0a035..066970813 100644
--- a/embassy-futures/src/fmt.rs
+++ b/embassy-futures/src/fmt.rs
@@ -195,9 +195,6 @@ macro_rules! unwrap {
195 } 195 }
196} 196}
197 197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)] 198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError; 199pub struct NoneError;
203 200
diff --git a/embassy-hal-common/Cargo.toml b/embassy-hal-common/Cargo.toml
index e8617c02f..18c758d7b 100644
--- a/embassy-hal-common/Cargo.toml
+++ b/embassy-hal-common/Cargo.toml
@@ -6,8 +6,24 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8 8
9# Define the number of NVIC priority bits.
10prio-bits-0 = []
11prio-bits-1 = []
12prio-bits-2 = []
13prio-bits-3 = []
14prio-bits-4 = []
15prio-bits-5 = []
16prio-bits-6 = []
17prio-bits-7 = []
18prio-bits-8 = []
19
20cortex-m = ["dep:cortex-m", "dep:critical-section"]
21
9[dependencies] 22[dependencies]
10defmt = { version = "0.3", optional = true } 23defmt = { version = "0.3", optional = true }
11log = { version = "0.4.14", optional = true } 24log = { version = "0.4.14", optional = true }
12 25
13num-traits = { version = "0.2.14", default-features = false } 26num-traits = { version = "0.2.14", default-features = false }
27
28cortex-m = { version = "0.7.6", optional = true }
29critical-section = { version = "1", optional = true } \ No newline at end of file
diff --git a/embassy-cortex-m/build.rs b/embassy-hal-common/build.rs
index 6fe82b44f..6fe82b44f 100644
--- a/embassy-cortex-m/build.rs
+++ b/embassy-hal-common/build.rs
diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-hal-common/src/interrupt.rs
index 0e790eaaf..b970aa2cd 100644
--- a/embassy-cortex-m/src/interrupt.rs
+++ b/embassy-hal-common/src/interrupt.rs
@@ -2,120 +2,208 @@
2use core::mem; 2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
4 4
5use cortex_m::interrupt::InterruptNumber;
5use cortex_m::peripheral::NVIC; 6use cortex_m::peripheral::NVIC;
6 7
7/// Do not use. Used for macros and HALs only. Not covered by semver guarantees. 8/// Generate a standard `mod interrupt` for a HAL.
8#[doc(hidden)] 9#[macro_export]
9pub mod _export { 10macro_rules! interrupt_mod {
10 pub use atomic_polyfill as atomic; 11 ($($irqs:ident),* $(,)?) => {
11 pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; 12 #[cfg(feature = "rt")]
12} 13 pub use cortex_m_rt::interrupt;
13 14
14/// Interrupt handler trait. 15 /// Interrupt definitions.
15/// 16 pub mod interrupt {
16/// Drivers that need to handle interrupts implement this trait. 17 pub use $crate::interrupt::{InterruptExt, Priority};
17/// The user must ensure `on_interrupt()` is called every time the interrupt fires. 18 pub use crate::pac::Interrupt::*;
18/// Drivers must use use [`Binding`] to assert at compile time that the user has done so. 19 pub use crate::pac::Interrupt;
19pub trait Handler<I: Interrupt> {
20 /// Interrupt handler function.
21 ///
22 /// Must be called every time the `I` interrupt fires, synchronously from
23 /// the interrupt handler context.
24 ///
25 /// # Safety
26 ///
27 /// This function must ONLY be called from the interrupt handler for `I`.
28 unsafe fn on_interrupt();
29}
30 20
31/// Compile-time assertion that an interrupt has been bound to a handler. 21 /// Type-level interrupt infrastructure.
32/// 22 ///
33/// For the vast majority of cases, you should use the `bind_interrupts!` 23 /// This module contains one *type* per interrupt. This is used for checking at compile time that
34/// macro instead of writing `unsafe impl`s of this trait. 24 /// the interrupts are correctly bound to HAL drivers.
35/// 25 ///
36/// # Safety 26 /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro
37/// 27 /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate
38/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` 28 /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...)
39/// to be called every time the `I` interrupt fires. 29 pub mod typelevel {
40/// 30 use super::InterruptExt;
41/// This allows drivers to check bindings at compile-time. 31
42pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {} 32 mod sealed {
43 33 pub trait Interrupt {}
44#[derive(Clone, Copy)] 34 }
45pub(crate) struct NrWrap(pub(crate) u16); 35
46unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { 36 /// Type-level interrupt.
47 fn number(self) -> u16 { 37 ///
48 self.0 38 /// This trait is implemented for all typelevel interrupt types in this module.
49 } 39 pub trait Interrupt: sealed::Interrupt {
40
41 /// Interrupt enum variant.
42 ///
43 /// This allows going from typelevel interrupts (one type per interrupt) to
44 /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt).
45 const IRQ: super::Interrupt;
46
47 /// Enable the interrupt.
48 #[inline]
49 unsafe fn enable() {
50 Self::IRQ.enable()
51 }
52
53 /// Disable the interrupt.
54 #[inline]
55 fn disable() {
56 Self::IRQ.disable()
57 }
58
59 /// Check if interrupt is enabled.
60 #[inline]
61 fn is_enabled() -> bool {
62 Self::IRQ.is_enabled()
63 }
64
65 /// Check if interrupt is pending.
66 #[inline]
67 fn is_pending() -> bool {
68 Self::IRQ.is_pending()
69 }
70
71 /// Set interrupt pending.
72 #[inline]
73 fn pend() {
74 Self::IRQ.pend()
75 }
76
77 /// Unset interrupt pending.
78 #[inline]
79 fn unpend() {
80 Self::IRQ.unpend()
81 }
82
83 /// Get the priority of the interrupt.
84 #[inline]
85 fn get_priority() -> crate::interrupt::Priority {
86 Self::IRQ.get_priority()
87 }
88
89 /// Set the interrupt priority.
90 #[inline]
91 fn set_priority(prio: crate::interrupt::Priority) {
92 Self::IRQ.set_priority(prio)
93 }
94 }
95
96 $(
97 #[allow(non_camel_case_types)]
98 #[doc=stringify!($irqs)]
99 #[doc=" typelevel interrupt."]
100 pub enum $irqs {}
101 impl sealed::Interrupt for $irqs{}
102 impl Interrupt for $irqs {
103 const IRQ: super::Interrupt = super::Interrupt::$irqs;
104 }
105 )*
106
107 /// Interrupt handler trait.
108 ///
109 /// Drivers that need to handle interrupts implement this trait.
110 /// The user must ensure `on_interrupt()` is called every time the interrupt fires.
111 /// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
112 pub trait Handler<I: Interrupt> {
113 /// Interrupt handler function.
114 ///
115 /// Must be called every time the `I` interrupt fires, synchronously from
116 /// the interrupt handler context.
117 ///
118 /// # Safety
119 ///
120 /// This function must ONLY be called from the interrupt handler for `I`.
121 unsafe fn on_interrupt();
122 }
123
124 /// Compile-time assertion that an interrupt has been bound to a handler.
125 ///
126 /// For the vast majority of cases, you should use the `bind_interrupts!`
127 /// macro instead of writing `unsafe impl`s of this trait.
128 ///
129 /// # Safety
130 ///
131 /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
132 /// to be called every time the `I` interrupt fires.
133 ///
134 /// This allows drivers to check bindings at compile-time.
135 pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
136 }
137 }
138 };
50} 139}
51 140
52/// Represents an interrupt type that can be configured by embassy to handle 141/// Represents an interrupt type that can be configured by embassy to handle
53/// interrupts. 142/// interrupts.
54pub unsafe trait Interrupt { 143pub unsafe trait InterruptExt: InterruptNumber + Copy {
55 /// Return the NVIC interrupt number for this interrupt.
56 fn number() -> u16;
57
58 /// Enable the interrupt. 144 /// Enable the interrupt.
59 #[inline] 145 #[inline]
60 unsafe fn enable() { 146 unsafe fn enable(self) {
61 compiler_fence(Ordering::SeqCst); 147 compiler_fence(Ordering::SeqCst);
62 NVIC::unmask(NrWrap(Self::number())) 148 NVIC::unmask(self)
63 } 149 }
64 150
65 /// Disable the interrupt. 151 /// Disable the interrupt.
66 #[inline] 152 #[inline]
67 fn disable() { 153 fn disable(self) {
68 NVIC::mask(NrWrap(Self::number())); 154 NVIC::mask(self);
69 compiler_fence(Ordering::SeqCst); 155 compiler_fence(Ordering::SeqCst);
70 } 156 }
71 157
72 /// Check if interrupt is being handled. 158 /// Check if interrupt is being handled.
73 #[inline] 159 #[inline]
74 #[cfg(not(armv6m))] 160 #[cfg(not(armv6m))]
75 fn is_active() -> bool { 161 fn is_active(self) -> bool {
76 NVIC::is_active(NrWrap(Self::number())) 162 NVIC::is_active(self)
77 } 163 }
78 164
79 /// Check if interrupt is enabled. 165 /// Check if interrupt is enabled.
80 #[inline] 166 #[inline]
81 fn is_enabled() -> bool { 167 fn is_enabled(self) -> bool {
82 NVIC::is_enabled(NrWrap(Self::number())) 168 NVIC::is_enabled(self)
83 } 169 }
84 170
85 /// Check if interrupt is pending. 171 /// Check if interrupt is pending.
86 #[inline] 172 #[inline]
87 fn is_pending() -> bool { 173 fn is_pending(self) -> bool {
88 NVIC::is_pending(NrWrap(Self::number())) 174 NVIC::is_pending(self)
89 } 175 }
90 176
91 /// Set interrupt pending. 177 /// Set interrupt pending.
92 #[inline] 178 #[inline]
93 fn pend() { 179 fn pend(self) {
94 NVIC::pend(NrWrap(Self::number())) 180 NVIC::pend(self)
95 } 181 }
96 182
97 /// Unset interrupt pending. 183 /// Unset interrupt pending.
98 #[inline] 184 #[inline]
99 fn unpend() { 185 fn unpend(self) {
100 NVIC::unpend(NrWrap(Self::number())) 186 NVIC::unpend(self)
101 } 187 }
102 188
103 /// Get the priority of the interrupt. 189 /// Get the priority of the interrupt.
104 #[inline] 190 #[inline]
105 fn get_priority() -> Priority { 191 fn get_priority(self) -> Priority {
106 Priority::from(NVIC::get_priority(NrWrap(Self::number()))) 192 Priority::from(NVIC::get_priority(self))
107 } 193 }
108 194
109 /// Set the interrupt priority. 195 /// Set the interrupt priority.
110 #[inline] 196 #[inline]
111 fn set_priority(prio: Priority) { 197 fn set_priority(self, prio: Priority) {
112 critical_section::with(|_| unsafe { 198 critical_section::with(|_| unsafe {
113 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); 199 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
114 nvic.set_priority(NrWrap(Self::number()), prio.into()) 200 nvic.set_priority(self, prio.into())
115 }) 201 })
116 } 202 }
117} 203}
118 204
205unsafe impl<T: InterruptNumber + Copy> InterruptExt for T {}
206
119impl From<u8> for Priority { 207impl From<u8> for Priority {
120 fn from(priority: u8) -> Self { 208 fn from(priority: u8) -> Self {
121 unsafe { mem::transmute(priority & PRIO_MASK) } 209 unsafe { mem::transmute(priority & PRIO_MASK) }
diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs
index b2a35cd35..235964aa4 100644
--- a/embassy-hal-common/src/lib.rs
+++ b/embassy-hal-common/src/lib.rs
@@ -11,3 +11,6 @@ mod peripheral;
11pub mod ratio; 11pub mod ratio;
12pub mod ring_buffer; 12pub mod ring_buffer;
13pub use peripheral::{Peripheral, PeripheralRef}; 13pub use peripheral::{Peripheral, PeripheralRef};
14
15#[cfg(feature = "cortex-m")]
16pub mod interrupt;
diff --git a/embassy-lora/src/iv.rs b/embassy-lora/src/iv.rs
index 8d521040f..136973fe3 100644
--- a/embassy-lora/src/iv.rs
+++ b/embassy-lora/src/iv.rs
@@ -1,7 +1,7 @@
1#[cfg(feature = "stm32wl")] 1#[cfg(feature = "stm32wl")]
2use embassy_stm32::interrupt; 2use embassy_stm32::interrupt;
3#[cfg(feature = "stm32wl")] 3#[cfg(feature = "stm32wl")]
4use embassy_stm32::interrupt::*; 4use embassy_stm32::interrupt::InterruptExt;
5#[cfg(feature = "stm32wl")] 5#[cfg(feature = "stm32wl")]
6use embassy_stm32::pac; 6use embassy_stm32::pac;
7#[cfg(feature = "stm32wl")] 7#[cfg(feature = "stm32wl")]
@@ -20,9 +20,9 @@ use lora_phy::mod_traits::InterfaceVariant;
20pub struct InterruptHandler {} 20pub struct InterruptHandler {}
21 21
22#[cfg(feature = "stm32wl")] 22#[cfg(feature = "stm32wl")]
23impl interrupt::Handler<interrupt::SUBGHZ_RADIO> for InterruptHandler { 23impl interrupt::typelevel::Handler<interrupt::typelevel::SUBGHZ_RADIO> for InterruptHandler {
24 unsafe fn on_interrupt() { 24 unsafe fn on_interrupt() {
25 interrupt::SUBGHZ_RADIO::disable(); 25 interrupt::SUBGHZ_RADIO.disable();
26 IRQ_SIGNAL.signal(()); 26 IRQ_SIGNAL.signal(());
27 } 27 }
28} 28}
@@ -45,11 +45,11 @@ where
45{ 45{
46 /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination 46 /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination
47 pub fn new( 47 pub fn new(
48 _irq: impl interrupt::Binding<interrupt::SUBGHZ_RADIO, InterruptHandler>, 48 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SUBGHZ_RADIO, InterruptHandler>,
49 rf_switch_rx: Option<CTRL>, 49 rf_switch_rx: Option<CTRL>,
50 rf_switch_tx: Option<CTRL>, 50 rf_switch_tx: Option<CTRL>,
51 ) -> Result<Self, RadioError> { 51 ) -> Result<Self, RadioError> {
52 interrupt::SUBGHZ_RADIO::disable(); 52 interrupt::SUBGHZ_RADIO.disable();
53 Ok(Self { 53 Ok(Self {
54 board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board 54 board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board
55 rf_switch_rx, 55 rf_switch_rx,
@@ -68,34 +68,28 @@ where
68 } 68 }
69 async fn set_nss_low(&mut self) -> Result<(), RadioError> { 69 async fn set_nss_low(&mut self) -> Result<(), RadioError> {
70 let pwr = pac::PWR; 70 let pwr = pac::PWR;
71 unsafe { 71 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
72 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
73 }
74 Ok(()) 72 Ok(())
75 } 73 }
76 async fn set_nss_high(&mut self) -> Result<(), RadioError> { 74 async fn set_nss_high(&mut self) -> Result<(), RadioError> {
77 let pwr = pac::PWR; 75 let pwr = pac::PWR;
78 unsafe { 76 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
79 pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
80 }
81 Ok(()) 77 Ok(())
82 } 78 }
83 async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { 79 async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
84 let rcc = pac::RCC; 80 let rcc = pac::RCC;
85 unsafe { 81 rcc.csr().modify(|w| w.set_rfrst(true));
86 rcc.csr().modify(|w| w.set_rfrst(true)); 82 rcc.csr().modify(|w| w.set_rfrst(false));
87 rcc.csr().modify(|w| w.set_rfrst(false));
88 }
89 Ok(()) 83 Ok(())
90 } 84 }
91 async fn wait_on_busy(&mut self) -> Result<(), RadioError> { 85 async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
92 let pwr = pac::PWR; 86 let pwr = pac::PWR;
93 while unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY } {} 87 while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
94 Ok(()) 88 Ok(())
95 } 89 }
96 90
97 async fn await_irq(&mut self) -> Result<(), RadioError> { 91 async fn await_irq(&mut self) -> Result<(), RadioError> {
98 unsafe { interrupt::SUBGHZ_RADIO::enable() }; 92 unsafe { interrupt::SUBGHZ_RADIO.enable() };
99 IRQ_SIGNAL.wait().await; 93 IRQ_SIGNAL.wait().await;
100 Ok(()) 94 Ok(())
101 } 95 }
diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml
index 781026b99..3b8fe8b44 100644
--- a/embassy-macros/Cargo.toml
+++ b/embassy-macros/Cargo.toml
@@ -12,9 +12,9 @@ categories = [
12] 12]
13 13
14[dependencies] 14[dependencies]
15syn = { version = "1.0.76", features = ["full", "extra-traits"] } 15syn = { version = "2.0.15", features = ["full", "extra-traits"] }
16quote = "1.0.9" 16quote = "1.0.9"
17darling = "0.13.0" 17darling = "0.20.1"
18proc-macro2 = "1.0.29" 18proc-macro2 = "1.0.29"
19 19
20[lib] 20[lib]
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index d7ca1f69c..c9d58746a 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -1,11 +1,28 @@
1#![doc = include_str!("../README.md")] 1#![doc = include_str!("../README.md")]
2extern crate proc_macro; 2extern crate proc_macro;
3 3
4use darling::ast::NestedMeta;
4use proc_macro::TokenStream; 5use proc_macro::TokenStream;
5 6
6mod macros; 7mod macros;
7mod util; 8mod util;
8use macros::*; 9use macros::*;
10use syn::parse::{Parse, ParseBuffer};
11use syn::punctuated::Punctuated;
12use syn::Token;
13
14struct Args {
15 meta: Vec<NestedMeta>,
16}
17
18impl Parse for Args {
19 fn parse(input: &ParseBuffer) -> syn::Result<Self> {
20 let meta = Punctuated::<NestedMeta, Token![,]>::parse_terminated(input)?;
21 Ok(Args {
22 meta: meta.into_iter().collect(),
23 })
24 }
25}
9 26
10/// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how 27/// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how
11/// many concurrent tasks can be spawned (default is 1) for the function. 28/// many concurrent tasks can be spawned (default is 1) for the function.
@@ -39,10 +56,10 @@ use macros::*;
39/// ``` 56/// ```
40#[proc_macro_attribute] 57#[proc_macro_attribute]
41pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { 58pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
42 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 59 let args = syn::parse_macro_input!(args as Args);
43 let f = syn::parse_macro_input!(item as syn::ItemFn); 60 let f = syn::parse_macro_input!(item as syn::ItemFn);
44 61
45 task::run(args, f).unwrap_or_else(|x| x).into() 62 task::run(&args.meta, f).unwrap_or_else(|x| x).into()
46} 63}
47 64
48/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task. 65/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
@@ -65,9 +82,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
65/// ``` 82/// ```
66#[proc_macro_attribute] 83#[proc_macro_attribute]
67pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { 84pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
68 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 85 let args = syn::parse_macro_input!(args as Args);
69 let f = syn::parse_macro_input!(item as syn::ItemFn); 86 let f = syn::parse_macro_input!(item as syn::ItemFn);
70 main::run(args, f, main::cortex_m()).unwrap_or_else(|x| x).into() 87 main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into()
71} 88}
72 89
73/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. 90/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
@@ -100,9 +117,9 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
100/// ``` 117/// ```
101#[proc_macro_attribute] 118#[proc_macro_attribute]
102pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream { 119pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
103 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 120 let args = syn::parse_macro_input!(args as Args);
104 let f = syn::parse_macro_input!(item as syn::ItemFn); 121 let f = syn::parse_macro_input!(item as syn::ItemFn);
105 main::run(args.clone(), f, main::riscv(args)) 122 main::run(&args.meta, f, main::riscv(&args.meta))
106 .unwrap_or_else(|x| x) 123 .unwrap_or_else(|x| x)
107 .into() 124 .into()
108} 125}
@@ -127,9 +144,9 @@ pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
127/// ``` 144/// ```
128#[proc_macro_attribute] 145#[proc_macro_attribute]
129pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream { 146pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
130 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 147 let args = syn::parse_macro_input!(args as Args);
131 let f = syn::parse_macro_input!(item as syn::ItemFn); 148 let f = syn::parse_macro_input!(item as syn::ItemFn);
132 main::run(args, f, main::std()).unwrap_or_else(|x| x).into() 149 main::run(&args.meta, f, main::std()).unwrap_or_else(|x| x).into()
133} 150}
134 151
135/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task. 152/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task.
@@ -152,20 +169,7 @@ pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
152/// ``` 169/// ```
153#[proc_macro_attribute] 170#[proc_macro_attribute]
154pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream { 171pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
155 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 172 let args = syn::parse_macro_input!(args as Args);
156 let f = syn::parse_macro_input!(item as syn::ItemFn);
157 main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
158}
159
160#[proc_macro_attribute]
161pub fn cortex_m_interrupt(args: TokenStream, item: TokenStream) -> TokenStream {
162 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
163 let f = syn::parse_macro_input!(item as syn::ItemFn); 173 let f = syn::parse_macro_input!(item as syn::ItemFn);
164 cortex_m_interrupt::run(args, f).unwrap_or_else(|x| x).into() 174 main::run(&args.meta, f, main::wasm()).unwrap_or_else(|x| x).into()
165}
166
167#[proc_macro]
168pub fn cortex_m_interrupt_declare(item: TokenStream) -> TokenStream {
169 let name = syn::parse_macro_input!(item as syn::Ident);
170 cortex_m_interrupt_declare::run(name).unwrap_or_else(|x| x).into()
171} 175}
diff --git a/embassy-macros/src/macros/cortex_m_interrupt.rs b/embassy-macros/src/macros/cortex_m_interrupt.rs
deleted file mode 100644
index 13af8ca07..000000000
--- a/embassy-macros/src/macros/cortex_m_interrupt.rs
+++ /dev/null
@@ -1,66 +0,0 @@
1use std::iter;
2
3use darling::FromMeta;
4use proc_macro2::TokenStream;
5use quote::quote;
6use syn::{ReturnType, Type, Visibility};
7
8use crate::util::ctxt::Ctxt;
9
10#[derive(Debug, FromMeta)]
11struct Args {}
12
13pub fn run(args: syn::AttributeArgs, mut f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
14 let _args = Args::from_list(&args).map_err(|e| e.write_errors())?;
15
16 let ident = f.sig.ident.clone();
17 let ident_s = ident.to_string();
18
19 // XXX should we blacklist other attributes?
20
21 let valid_signature = f.sig.constness.is_none()
22 && f.vis == Visibility::Inherited
23 && f.sig.abi.is_none()
24 && f.sig.inputs.is_empty()
25 && f.sig.generics.params.is_empty()
26 && f.sig.generics.where_clause.is_none()
27 && f.sig.variadic.is_none()
28 && match f.sig.output {
29 ReturnType::Default => true,
30 ReturnType::Type(_, ref ty) => match **ty {
31 Type::Tuple(ref tuple) => tuple.elems.is_empty(),
32 Type::Never(..) => true,
33 _ => false,
34 },
35 };
36
37 let ctxt = Ctxt::new();
38
39 if !valid_signature {
40 ctxt.error_spanned_by(
41 &f.sig,
42 "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
43 );
44 }
45
46 ctxt.check()?;
47
48 f.block.stmts = iter::once(
49 syn::parse2(quote! {{
50 // Check that this interrupt actually exists
51 let __irq_exists_check: interrupt::#ident;
52 }})
53 .unwrap(),
54 )
55 .chain(f.block.stmts)
56 .collect();
57
58 let result = quote!(
59 #[doc(hidden)]
60 #[export_name = #ident_s]
61 #[allow(non_snake_case)]
62 #f
63 );
64
65 Ok(result)
66}
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs b/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
deleted file mode 100644
index b317482f5..000000000
--- a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
+++ /dev/null
@@ -1,21 +0,0 @@
1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3
4pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
5 let name = format_ident!("{}", name);
6 let doc = format!("{} interrupt.", name);
7
8 let result = quote! {
9 #[doc = #doc]
10 #[allow(non_camel_case_types)]
11 pub enum #name{}
12 unsafe impl ::embassy_cortex_m::interrupt::Interrupt for #name {
13 fn number() -> u16 {
14 use cortex_m::interrupt::InterruptNumber;
15 let irq = InterruptEnum::#name;
16 irq.number() as u16
17 }
18 }
19 };
20 Ok(result)
21}
diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs
index 5c099f68a..7c4d55163 100644
--- a/embassy-macros/src/macros/main.rs
+++ b/embassy-macros/src/macros/main.rs
@@ -1,3 +1,4 @@
1use darling::export::NestedMeta;
1use darling::FromMeta; 2use darling::FromMeta;
2use proc_macro2::TokenStream; 3use proc_macro2::TokenStream;
3use quote::quote; 4use quote::quote;
@@ -11,8 +12,8 @@ struct Args {
11 entry: Option<String>, 12 entry: Option<String>,
12} 13}
13 14
14pub fn riscv(args: syn::AttributeArgs) -> TokenStream { 15pub fn riscv(args: &[NestedMeta]) -> TokenStream {
15 let maybe_entry = match Args::from_list(&args) { 16 let maybe_entry = match Args::from_list(args) {
16 Ok(args) => args.entry, 17 Ok(args) => args.entry,
17 Err(e) => return e.write_errors(), 18 Err(e) => return e.write_errors(),
18 }; 19 };
@@ -77,9 +78,9 @@ pub fn std() -> TokenStream {
77 } 78 }
78} 79}
79 80
80pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> { 81pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> {
81 #[allow(unused_variables)] 82 #[allow(unused_variables)]
82 let args = Args::from_list(&args).map_err(|e| e.write_errors())?; 83 let args = Args::from_list(args).map_err(|e| e.write_errors())?;
83 84
84 let fargs = f.sig.inputs.clone(); 85 let fargs = f.sig.inputs.clone();
85 86
diff --git a/embassy-macros/src/macros/mod.rs b/embassy-macros/src/macros/mod.rs
index a5e7a50e6..572094ca6 100644
--- a/embassy-macros/src/macros/mod.rs
+++ b/embassy-macros/src/macros/mod.rs
@@ -1,4 +1,2 @@
1pub mod cortex_m_interrupt;
2pub mod cortex_m_interrupt_declare;
3pub mod main; 1pub mod main;
4pub mod task; 2pub mod task;
diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs
index 9f30cf43e..1d30434e9 100644
--- a/embassy-macros/src/macros/task.rs
+++ b/embassy-macros/src/macros/task.rs
@@ -1,20 +1,24 @@
1use darling::export::NestedMeta;
1use darling::FromMeta; 2use darling::FromMeta;
2use proc_macro2::TokenStream; 3use proc_macro2::{Span, TokenStream};
3use quote::{format_ident, quote}; 4use quote::{format_ident, quote};
4use syn::{parse_quote, ItemFn, ReturnType, Type}; 5use syn::{parse_quote, Expr, ExprLit, ItemFn, Lit, LitInt, ReturnType, Type};
5 6
6use crate::util::ctxt::Ctxt; 7use crate::util::ctxt::Ctxt;
7 8
8#[derive(Debug, FromMeta)] 9#[derive(Debug, FromMeta)]
9struct Args { 10struct Args {
10 #[darling(default)] 11 #[darling(default)]
11 pool_size: Option<usize>, 12 pool_size: Option<syn::Expr>,
12} 13}
13 14
14pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> { 15pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
15 let args = Args::from_list(&args).map_err(|e| e.write_errors())?; 16 let args = Args::from_list(args).map_err(|e| e.write_errors())?;
16 17
17 let pool_size: usize = args.pool_size.unwrap_or(1); 18 let pool_size = args.pool_size.unwrap_or(Expr::Lit(ExprLit {
19 attrs: vec![],
20 lit: Lit::Int(LitInt::new("1", Span::call_site())),
21 }));
18 22
19 let ctxt = Ctxt::new(); 23 let ctxt = Ctxt::new();
20 24
@@ -45,10 +49,6 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
45 }, 49 },
46 } 50 }
47 51
48 if pool_size < 1 {
49 ctxt.error_spanned_by(&f.sig, "pool_size must be 1 or greater");
50 }
51
52 let mut arg_names = Vec::new(); 52 let mut arg_names = Vec::new();
53 let mut fargs = f.sig.inputs.clone(); 53 let mut fargs = f.sig.inputs.clone();
54 54
@@ -82,7 +82,8 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
82 let mut task_outer: ItemFn = parse_quote! { 82 let mut task_outer: ItemFn = parse_quote! {
83 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> { 83 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
84 type Fut = impl ::core::future::Future + 'static; 84 type Fut = impl ::core::future::Future + 'static;
85 static POOL: ::embassy_executor::raw::TaskPool<Fut, #pool_size> = ::embassy_executor::raw::TaskPool::new(); 85 const POOL_SIZE: usize = #pool_size;
86 static POOL: ::embassy_executor::raw::TaskPool<Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new();
86 unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) } 87 unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
87 } 88 }
88 }; 89 };
diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml
index e475551e1..bee2e3021 100644
--- a/embassy-net-driver-channel/Cargo.toml
+++ b/embassy-net-driver-channel/Cargo.toml
@@ -2,6 +2,14 @@
2name = "embassy-net-driver-channel" 2name = "embassy-net-driver-channel"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0"
6description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
5 13
6[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-channel-v$VERSION/embassy-net-driver-channel/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-channel-v$VERSION/embassy-net-driver-channel/src/"
@@ -9,6 +17,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-d
9features = ["defmt"] 17features = ["defmt"]
10target = "thumbv7em-none-eabi" 18target = "thumbv7em-none-eabi"
11 19
20[package.metadata.docs.rs]
21features = ["defmt"]
22
12[dependencies] 23[dependencies]
13defmt = { version = "0.3", optional = true } 24defmt = { version = "0.3", optional = true }
14log = { version = "0.4.14", optional = true } 25log = { version = "0.4.14", optional = true }
diff --git a/embassy-net-driver-channel/README.md b/embassy-net-driver-channel/README.md
new file mode 100644
index 000000000..dd90e7ad2
--- /dev/null
+++ b/embassy-net-driver-channel/README.md
@@ -0,0 +1,96 @@
1# embassy-net-driver-channel
2
3This crate provides a toolkit for implementing [`embassy-net`](https://crates.io/crates/embassy-net) drivers in a
4higher level way than implementing the [`embassy-net-driver`](https://crates.io/crates/embassy-net-driver) trait directly.
5
6The `embassy-net-driver` trait is polling-based. To implement it, you must write the packet receive/transmit state machines by
7hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net`
8knows when to poll your driver again to make more progress.
9
10With `embassy-net-driver-channel`
11
12## A note about deadlocks
13
14When implementing a driver using this crate, it might be tempting to write it in the most straightforward way:
15
16```rust,ignore
17loop {
18 // Wait for either..
19 match select(
20 // ... the chip signaling an interrupt, indicating a packet is available to receive, or
21 irq_pin.wait_for_low(),
22 // ... a TX buffer becoming available, i.e. embassy-net wants to send a packet
23 tx_chan.tx_buf(),
24 ).await {
25 Either::First(_) => {
26 // a packet is ready to be received!
27 let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue
28 let n = receive_packet_over_spi(buf).await;
29 rx_chan.rx_done(n);
30 }
31 Either::Second(buf) => {
32 // a packet is ready to be sent!
33 send_packet_over_spi(buf).await;
34 tx_chan.tx_done();
35 }
36 }
37}
38```
39
40However, this code has a latent deadlock bug. The symptom is it can hang at `rx_chan.rx_buf().await` under load.
41
42The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue.
43
44The fix is to make sure to always service the TX queue while you're waiting for space to become available in the TX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available":
45
46```rust,ignore
47loop {
48 // Wait for either..
49 match select(
50 async {
51 // ... the chip signaling an interrupt, indicating a packet is available to receive
52 irq_pin.wait_for_low().await;
53 // *AND* the buffer is ready...
54 rx_chan.rx_buf().await
55 },
56 // ... or a TX buffer becoming available, i.e. embassy-net wants to send a packet
57 tx_chan.tx_buf(),
58 ).await {
59 Either::First(buf) => {
60 // a packet is ready to be received!
61 let n = receive_packet_over_spi(buf).await;
62 rx_chan.rx_done(n);
63 }
64 Either::Second(buf) => {
65 // a packet is ready to be sent!
66 send_packet_over_spi(buf).await;
67 tx_chan.tx_done();
68 }
69 }
70}
71```
72
73## Examples
74
75These `embassy-net` drivers are implemented using this crate. You can look at them for inspiration.
76
77- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W
78- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support.
79- [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip.
80- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
81
82
83## Interoperability
84
85This crate can run on any executor.
86
87
88## License
89
90This work is licensed under either of
91
92- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
93 http://www.apache.org/licenses/LICENSE-2.0)
94- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
95
96at your option.
diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs
index 0c8dcc22b..02a4c00d6 100644
--- a/embassy-net-driver-channel/src/lib.rs
+++ b/embassy-net-driver-channel/src/lib.rs
@@ -1,4 +1,5 @@
1#![no_std] 1#![no_std]
2#![doc = include_str!("../README.md")]
2 3
3// must go first! 4// must go first!
4mod fmt; 5mod fmt;
diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml
index ff6f29355..da6d9ad62 100644
--- a/embassy-net-driver/Cargo.toml
+++ b/embassy-net-driver/Cargo.toml
@@ -3,7 +3,13 @@ name = "embassy-net-driver"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6description = "Driver trait for the `embassy-net` async TCP/IP network stack."
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
7 13
8[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
9src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-v$VERSION/embassy-net-driver/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-v$VERSION/embassy-net-driver/src/"
@@ -11,5 +17,8 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-d
11features = ["defmt"] 17features = ["defmt"]
12target = "thumbv7em-none-eabi" 18target = "thumbv7em-none-eabi"
13 19
20[package.metadata.docs.rs]
21features = ["defmt"]
22
14[dependencies] 23[dependencies]
15defmt = { version = "0.3", optional = true } \ No newline at end of file 24defmt = { version = "0.3", optional = true } \ No newline at end of file
diff --git a/embassy-net-driver/README.md b/embassy-net-driver/README.md
index 84f25492d..6a757380d 100644
--- a/embassy-net-driver/README.md
+++ b/embassy-net-driver/README.md
@@ -1,5 +1,21 @@
1# embassy-net-driver 1# embassy-net-driver
2 2
3This crate contains the driver trait necessary for adding [`embassy-net`](https://crates.io/crates/embassy-net) support
4for a new hardware platform.
5
6If you want to *use* `embassy-net` with already made drivers, you should depend on the main `embassy-net` crate, not on this crate.
7
8If you are writing a driver, you should depend only on this crate, not on the main `embassy-net` crate.
9This will allow your driver to continue working for newer `embassy-net` major versions, without needing an update,
10if the driver trait has not had breaking changes.
11
12See also [`embassy-net-driver-channel`](https://crates.io/crates/embassy-net-driver-channel), which provides a higer-level API
13to construct a driver that processes packets in its own background task and communicates with the `embassy-net` task via
14packet queues for RX and TX.
15
16## Interoperability
17
18This crate can run on any executor.
3 19
4## License 20## License
5 21
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
new file mode 100644
index 000000000..a7e18ee09
--- /dev/null
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2name = "embassy-net-esp-hosted"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7defmt = { version = "0.3", optional = true }
8log = { version = "0.4.14", optional = true }
9
10embassy-time = { version = "0.1.0", path = "../embassy-time" }
11embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
12embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
13embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
14
15embedded-hal = { version = "1.0.0-alpha.10" }
16embedded-hal-async = { version = "=0.2.0-alpha.1" }
17
18noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] }
19#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }
20heapless = "0.7.16"
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
new file mode 100644
index 000000000..fce82ade7
--- /dev/null
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -0,0 +1,139 @@
1use ch::driver::LinkState;
2use defmt::Debug2Format;
3use embassy_net_driver_channel as ch;
4use heapless::String;
5
6use crate::ioctl::Shared;
7use crate::proto::{self, CtrlMsg};
8
9#[derive(Debug)]
10pub struct Error {
11 pub status: u32,
12}
13
14pub struct Control<'a> {
15 state_ch: ch::StateRunner<'a>,
16 shared: &'a Shared,
17}
18
19#[allow(unused)]
20enum WifiMode {
21 None = 0,
22 Sta = 1,
23 Ap = 2,
24 ApSta = 3,
25}
26
27impl<'a> Control<'a> {
28 pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self {
29 Self { state_ch, shared }
30 }
31
32 pub async fn init(&mut self) {
33 debug!("wait for init event...");
34 self.shared.init_wait().await;
35
36 debug!("set wifi mode");
37 self.set_wifi_mode(WifiMode::Sta as _).await;
38
39 let mac_addr = self.get_mac_addr().await;
40 debug!("mac addr: {:02x}", mac_addr);
41 self.state_ch.set_ethernet_address(mac_addr);
42 }
43
44 pub async fn join(&mut self, ssid: &str, password: &str) {
45 let req = proto::CtrlMsg {
46 msg_id: proto::CtrlMsgId::ReqConnectAp as _,
47 msg_type: proto::CtrlMsgType::Req as _,
48 payload: Some(proto::CtrlMsgPayload::ReqConnectAp(proto::CtrlMsgReqConnectAp {
49 ssid: String::from(ssid),
50 pwd: String::from(password),
51 bssid: String::new(),
52 listen_interval: 3,
53 is_wpa3_supported: false,
54 })),
55 };
56 let resp = self.ioctl(req).await;
57 let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
58 debug!("======= {:?}", Debug2Format(&resp));
59 assert_eq!(resp.resp, 0);
60 self.state_ch.set_link_state(LinkState::Up);
61 }
62
63 async fn get_mac_addr(&mut self) -> [u8; 6] {
64 let req = proto::CtrlMsg {
65 msg_id: proto::CtrlMsgId::ReqGetMacAddress as _,
66 msg_type: proto::CtrlMsgType::Req as _,
67 payload: Some(proto::CtrlMsgPayload::ReqGetMacAddress(
68 proto::CtrlMsgReqGetMacAddress {
69 mode: WifiMode::Sta as _,
70 },
71 )),
72 };
73 let resp = self.ioctl(req).await;
74 let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
75 assert_eq!(resp.resp, 0);
76
77 // WHY IS THIS A STRING? WHYYYY
78 fn nibble_from_hex(b: u8) -> u8 {
79 match b {
80 b'0'..=b'9' => b - b'0',
81 b'a'..=b'f' => b + 0xa - b'a',
82 b'A'..=b'F' => b + 0xa - b'A',
83 _ => panic!("invalid hex digit {}", b),
84 }
85 }
86
87 let mac = resp.mac.as_bytes();
88 let mut res = [0; 6];
89 assert_eq!(mac.len(), 17);
90 for (i, b) in res.iter_mut().enumerate() {
91 *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1])
92 }
93 res
94 }
95
96 async fn set_wifi_mode(&mut self, mode: u32) {
97 let req = proto::CtrlMsg {
98 msg_id: proto::CtrlMsgId::ReqSetWifiMode as _,
99 msg_type: proto::CtrlMsgType::Req as _,
100 payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })),
101 };
102 let resp = self.ioctl(req).await;
103 let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
104 assert_eq!(resp.resp, 0);
105 }
106
107 async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg {
108 debug!("ioctl req: {:?}", &req);
109
110 let mut buf = [0u8; 128];
111
112 let req_len = noproto::write(&req, &mut buf).unwrap();
113
114 struct CancelOnDrop<'a>(&'a Shared);
115
116 impl CancelOnDrop<'_> {
117 fn defuse(self) {
118 core::mem::forget(self);
119 }
120 }
121
122 impl Drop for CancelOnDrop<'_> {
123 fn drop(&mut self) {
124 self.0.ioctl_cancel();
125 }
126 }
127
128 let ioctl = CancelOnDrop(self.shared);
129
130 let resp_len = ioctl.0.ioctl(&mut buf, req_len).await;
131
132 ioctl.defuse();
133
134 let res = noproto::read(&buf[..resp_len]).unwrap();
135 debug!("ioctl resp: {:?}", &res);
136
137 res
138 }
139}
diff --git a/embassy-net-esp-hosted/src/esp_hosted_config.proto b/embassy-net-esp-hosted/src/esp_hosted_config.proto
new file mode 100644
index 000000000..aa1bfde64
--- /dev/null
+++ b/embassy-net-esp-hosted/src/esp_hosted_config.proto
@@ -0,0 +1,432 @@
1syntax = "proto3";
2
3/* Enums similar to ESP IDF */
4enum Ctrl_VendorIEType {
5 Beacon = 0;
6 Probe_req = 1;
7 Probe_resp = 2;
8 Assoc_req = 3;
9 Assoc_resp = 4;
10}
11
12enum Ctrl_VendorIEID {
13 ID_0 = 0;
14 ID_1 = 1;
15}
16
17enum Ctrl_WifiMode {
18 NONE = 0;
19 STA = 1;
20 AP = 2;
21 APSTA = 3;
22}
23
24enum Ctrl_WifiBw {
25 BW_Invalid = 0;
26 HT20 = 1;
27 HT40 = 2;
28}
29
30enum Ctrl_WifiPowerSave {
31 PS_Invalid = 0;
32 MIN_MODEM = 1;
33 MAX_MODEM = 2;
34}
35
36enum Ctrl_WifiSecProt {
37 Open = 0;
38 WEP = 1;
39 WPA_PSK = 2;
40 WPA2_PSK = 3;
41 WPA_WPA2_PSK = 4;
42 WPA2_ENTERPRISE = 5;
43 WPA3_PSK = 6;
44 WPA2_WPA3_PSK = 7;
45}
46
47/* enums for Control path */
48enum Ctrl_Status {
49 Connected = 0;
50 Not_Connected = 1;
51 No_AP_Found = 2;
52 Connection_Fail = 3;
53 Invalid_Argument = 4;
54 Out_Of_Range = 5;
55}
56
57
58enum CtrlMsgType {
59 MsgType_Invalid = 0;
60 Req = 1;
61 Resp = 2;
62 Event = 3;
63 MsgType_Max = 4;
64}
65
66enum CtrlMsgId {
67 MsgId_Invalid = 0;
68
69 /** Request Msgs **/
70 Req_Base = 100;
71
72 Req_GetMACAddress = 101;
73 Req_SetMacAddress = 102;
74 Req_GetWifiMode = 103;
75 Req_SetWifiMode = 104;
76
77 Req_GetAPScanList = 105;
78 Req_GetAPConfig = 106;
79 Req_ConnectAP = 107;
80 Req_DisconnectAP = 108;
81
82 Req_GetSoftAPConfig = 109;
83 Req_SetSoftAPVendorSpecificIE = 110;
84 Req_StartSoftAP = 111;
85 Req_GetSoftAPConnectedSTAList = 112;
86 Req_StopSoftAP = 113;
87
88 Req_SetPowerSaveMode = 114;
89 Req_GetPowerSaveMode = 115;
90
91 Req_OTABegin = 116;
92 Req_OTAWrite = 117;
93 Req_OTAEnd = 118;
94
95 Req_SetWifiMaxTxPower = 119;
96 Req_GetWifiCurrTxPower = 120;
97
98 Req_ConfigHeartbeat = 121;
99 /* Add new control path command response before Req_Max
100 * and update Req_Max */
101 Req_Max = 122;
102
103 /** Response Msgs **/
104 Resp_Base = 200;
105
106 Resp_GetMACAddress = 201;
107 Resp_SetMacAddress = 202;
108 Resp_GetWifiMode = 203;
109 Resp_SetWifiMode = 204;
110
111 Resp_GetAPScanList = 205;
112 Resp_GetAPConfig = 206;
113 Resp_ConnectAP = 207;
114 Resp_DisconnectAP = 208;
115
116 Resp_GetSoftAPConfig = 209;
117 Resp_SetSoftAPVendorSpecificIE = 210;
118 Resp_StartSoftAP = 211;
119 Resp_GetSoftAPConnectedSTAList = 212;
120 Resp_StopSoftAP = 213;
121
122 Resp_SetPowerSaveMode = 214;
123 Resp_GetPowerSaveMode = 215;
124
125 Resp_OTABegin = 216;
126 Resp_OTAWrite = 217;
127 Resp_OTAEnd = 218;
128
129 Resp_SetWifiMaxTxPower = 219;
130 Resp_GetWifiCurrTxPower = 220;
131
132 Resp_ConfigHeartbeat = 221;
133 /* Add new control path command response before Resp_Max
134 * and update Resp_Max */
135 Resp_Max = 222;
136
137 /** Event Msgs **/
138 Event_Base = 300;
139 Event_ESPInit = 301;
140 Event_Heartbeat = 302;
141 Event_StationDisconnectFromAP = 303;
142 Event_StationDisconnectFromESPSoftAP = 304;
143 /* Add new control path command notification before Event_Max
144 * and update Event_Max */
145 Event_Max = 305;
146}
147
148/* internal supporting structures for CtrlMsg */
149message ScanResult {
150 bytes ssid = 1;
151 uint32 chnl = 2;
152 int32 rssi = 3;
153 bytes bssid = 4;
154 Ctrl_WifiSecProt sec_prot = 5;
155}
156
157message ConnectedSTAList {
158 bytes mac = 1;
159 int32 rssi = 2;
160}
161
162
163/* Control path structures */
164/** Req/Resp structure **/
165message CtrlMsg_Req_GetMacAddress {
166 int32 mode = 1;
167}
168
169message CtrlMsg_Resp_GetMacAddress {
170 bytes mac = 1;
171 int32 resp = 2;
172}
173
174message CtrlMsg_Req_GetMode {
175}
176
177message CtrlMsg_Resp_GetMode {
178 int32 mode = 1;
179 int32 resp = 2;
180}
181
182message CtrlMsg_Req_SetMode {
183 int32 mode = 1;
184}
185
186message CtrlMsg_Resp_SetMode {
187 int32 resp = 1;
188}
189
190message CtrlMsg_Req_GetStatus {
191}
192
193message CtrlMsg_Resp_GetStatus {
194 int32 resp = 1;
195}
196
197message CtrlMsg_Req_SetMacAddress {
198 bytes mac = 1;
199 int32 mode = 2;
200}
201
202message CtrlMsg_Resp_SetMacAddress {
203 int32 resp = 1;
204}
205
206message CtrlMsg_Req_GetAPConfig {
207}
208
209message CtrlMsg_Resp_GetAPConfig {
210 bytes ssid = 1;
211 bytes bssid = 2;
212 int32 rssi = 3;
213 int32 chnl = 4;
214 Ctrl_WifiSecProt sec_prot = 5;
215 int32 resp = 6;
216}
217
218message CtrlMsg_Req_ConnectAP {
219 string ssid = 1;
220 string pwd = 2;
221 string bssid = 3;
222 bool is_wpa3_supported = 4;
223 int32 listen_interval = 5;
224}
225
226message CtrlMsg_Resp_ConnectAP {
227 int32 resp = 1;
228 bytes mac = 2;
229}
230
231message CtrlMsg_Req_GetSoftAPConfig {
232}
233
234message CtrlMsg_Resp_GetSoftAPConfig {
235 bytes ssid = 1;
236 bytes pwd = 2;
237 int32 chnl = 3;
238 Ctrl_WifiSecProt sec_prot = 4;
239 int32 max_conn = 5;
240 bool ssid_hidden = 6;
241 int32 bw = 7;
242 int32 resp = 8;
243}
244
245message CtrlMsg_Req_StartSoftAP {
246 string ssid = 1;
247 string pwd = 2;
248 int32 chnl = 3;
249 Ctrl_WifiSecProt sec_prot = 4;
250 int32 max_conn = 5;
251 bool ssid_hidden = 6;
252 int32 bw = 7;
253}
254
255message CtrlMsg_Resp_StartSoftAP {
256 int32 resp = 1;
257 bytes mac = 2;
258}
259
260message CtrlMsg_Req_ScanResult {
261}
262
263message CtrlMsg_Resp_ScanResult {
264 uint32 count = 1;
265 repeated ScanResult entries = 2;
266 int32 resp = 3;
267}
268
269message CtrlMsg_Req_SoftAPConnectedSTA {
270}
271
272message CtrlMsg_Resp_SoftAPConnectedSTA {
273 uint32 num = 1;
274 repeated ConnectedSTAList stations = 2;
275 int32 resp = 3;
276}
277
278message CtrlMsg_Req_OTABegin {
279}
280
281message CtrlMsg_Resp_OTABegin {
282 int32 resp = 1;
283}
284
285message CtrlMsg_Req_OTAWrite {
286 bytes ota_data = 1;
287}
288
289message CtrlMsg_Resp_OTAWrite {
290 int32 resp = 1;
291}
292
293message CtrlMsg_Req_OTAEnd {
294}
295
296message CtrlMsg_Resp_OTAEnd {
297 int32 resp = 1;
298}
299
300message CtrlMsg_Req_VendorIEData {
301 int32 element_id = 1;
302 int32 length = 2;
303 bytes vendor_oui = 3;
304 int32 vendor_oui_type = 4;
305 bytes payload = 5;
306}
307
308message CtrlMsg_Req_SetSoftAPVendorSpecificIE {
309 bool enable = 1;
310 Ctrl_VendorIEType type = 2;
311 Ctrl_VendorIEID idx = 3;
312 CtrlMsg_Req_VendorIEData vendor_ie_data = 4;
313}
314
315message CtrlMsg_Resp_SetSoftAPVendorSpecificIE {
316 int32 resp = 1;
317}
318
319message CtrlMsg_Req_SetWifiMaxTxPower {
320 int32 wifi_max_tx_power = 1;
321}
322
323message CtrlMsg_Resp_SetWifiMaxTxPower {
324 int32 resp = 1;
325}
326
327message CtrlMsg_Req_GetWifiCurrTxPower {
328}
329
330message CtrlMsg_Resp_GetWifiCurrTxPower {
331 int32 wifi_curr_tx_power = 1;
332 int32 resp = 2;
333}
334
335message CtrlMsg_Req_ConfigHeartbeat {
336 bool enable = 1;
337 int32 duration = 2;
338}
339
340message CtrlMsg_Resp_ConfigHeartbeat {
341 int32 resp = 1;
342}
343
344/** Event structure **/
345message CtrlMsg_Event_ESPInit {
346 bytes init_data = 1;
347}
348
349message CtrlMsg_Event_Heartbeat {
350 int32 hb_num = 1;
351}
352
353message CtrlMsg_Event_StationDisconnectFromAP {
354 int32 resp = 1;
355}
356
357message CtrlMsg_Event_StationDisconnectFromESPSoftAP {
358 int32 resp = 1;
359 bytes mac = 2;
360}
361
362message CtrlMsg {
363 /* msg_type could be req, resp or Event */
364 CtrlMsgType msg_type = 1;
365
366 /* msg id */
367 CtrlMsgId msg_id = 2;
368
369 /* union of all msg ids */
370 oneof payload {
371 /** Requests **/
372 CtrlMsg_Req_GetMacAddress req_get_mac_address = 101;
373 CtrlMsg_Req_SetMacAddress req_set_mac_address = 102;
374 CtrlMsg_Req_GetMode req_get_wifi_mode = 103;
375 CtrlMsg_Req_SetMode req_set_wifi_mode = 104;
376
377 CtrlMsg_Req_ScanResult req_scan_ap_list = 105;
378 CtrlMsg_Req_GetAPConfig req_get_ap_config = 106;
379 CtrlMsg_Req_ConnectAP req_connect_ap = 107;
380 CtrlMsg_Req_GetStatus req_disconnect_ap = 108;
381
382 CtrlMsg_Req_GetSoftAPConfig req_get_softap_config = 109;
383 CtrlMsg_Req_SetSoftAPVendorSpecificIE req_set_softap_vendor_specific_ie = 110;
384 CtrlMsg_Req_StartSoftAP req_start_softap = 111;
385 CtrlMsg_Req_SoftAPConnectedSTA req_softap_connected_stas_list = 112;
386 CtrlMsg_Req_GetStatus req_stop_softap = 113;
387
388 CtrlMsg_Req_SetMode req_set_power_save_mode = 114;
389 CtrlMsg_Req_GetMode req_get_power_save_mode = 115;
390
391 CtrlMsg_Req_OTABegin req_ota_begin = 116;
392 CtrlMsg_Req_OTAWrite req_ota_write = 117;
393 CtrlMsg_Req_OTAEnd req_ota_end = 118;
394
395 CtrlMsg_Req_SetWifiMaxTxPower req_set_wifi_max_tx_power = 119;
396 CtrlMsg_Req_GetWifiCurrTxPower req_get_wifi_curr_tx_power = 120;
397 CtrlMsg_Req_ConfigHeartbeat req_config_heartbeat = 121;
398
399 /** Responses **/
400 CtrlMsg_Resp_GetMacAddress resp_get_mac_address = 201;
401 CtrlMsg_Resp_SetMacAddress resp_set_mac_address = 202;
402 CtrlMsg_Resp_GetMode resp_get_wifi_mode = 203;
403 CtrlMsg_Resp_SetMode resp_set_wifi_mode = 204;
404
405 CtrlMsg_Resp_ScanResult resp_scan_ap_list = 205;
406 CtrlMsg_Resp_GetAPConfig resp_get_ap_config = 206;
407 CtrlMsg_Resp_ConnectAP resp_connect_ap = 207;
408 CtrlMsg_Resp_GetStatus resp_disconnect_ap = 208;
409
410 CtrlMsg_Resp_GetSoftAPConfig resp_get_softap_config = 209;
411 CtrlMsg_Resp_SetSoftAPVendorSpecificIE resp_set_softap_vendor_specific_ie = 210;
412 CtrlMsg_Resp_StartSoftAP resp_start_softap = 211;
413 CtrlMsg_Resp_SoftAPConnectedSTA resp_softap_connected_stas_list = 212;
414 CtrlMsg_Resp_GetStatus resp_stop_softap = 213;
415
416 CtrlMsg_Resp_SetMode resp_set_power_save_mode = 214;
417 CtrlMsg_Resp_GetMode resp_get_power_save_mode = 215;
418
419 CtrlMsg_Resp_OTABegin resp_ota_begin = 216;
420 CtrlMsg_Resp_OTAWrite resp_ota_write = 217;
421 CtrlMsg_Resp_OTAEnd resp_ota_end = 218;
422 CtrlMsg_Resp_SetWifiMaxTxPower resp_set_wifi_max_tx_power = 219;
423 CtrlMsg_Resp_GetWifiCurrTxPower resp_get_wifi_curr_tx_power = 220;
424 CtrlMsg_Resp_ConfigHeartbeat resp_config_heartbeat = 221;
425
426 /** Notifications **/
427 CtrlMsg_Event_ESPInit event_esp_init = 301;
428 CtrlMsg_Event_Heartbeat event_heartbeat = 302;
429 CtrlMsg_Event_StationDisconnectFromAP event_station_disconnect_from_AP = 303;
430 CtrlMsg_Event_StationDisconnectFromESPSoftAP event_station_disconnect_from_ESP_SoftAP = 304;
431 }
432}
diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs
new file mode 100644
index 000000000..91984bde1
--- /dev/null
+++ b/embassy-net-esp-hosted/src/fmt.rs
@@ -0,0 +1,257 @@
1#![macro_use]
2#![allow(unused_macros)]
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
9macro_rules! assert {
10 ($($x:tt)*) => {
11 {
12 #[cfg(not(feature = "defmt"))]
13 ::core::assert!($($x)*);
14 #[cfg(feature = "defmt")]
15 ::defmt::assert!($($x)*);
16 }
17 };
18}
19
20macro_rules! assert_eq {
21 ($($x:tt)*) => {
22 {
23 #[cfg(not(feature = "defmt"))]
24 ::core::assert_eq!($($x)*);
25 #[cfg(feature = "defmt")]
26 ::defmt::assert_eq!($($x)*);
27 }
28 };
29}
30
31macro_rules! assert_ne {
32 ($($x:tt)*) => {
33 {
34 #[cfg(not(feature = "defmt"))]
35 ::core::assert_ne!($($x)*);
36 #[cfg(feature = "defmt")]
37 ::defmt::assert_ne!($($x)*);
38 }
39 };
40}
41
42macro_rules! debug_assert {
43 ($($x:tt)*) => {
44 {
45 #[cfg(not(feature = "defmt"))]
46 ::core::debug_assert!($($x)*);
47 #[cfg(feature = "defmt")]
48 ::defmt::debug_assert!($($x)*);
49 }
50 };
51}
52
53macro_rules! debug_assert_eq {
54 ($($x:tt)*) => {
55 {
56 #[cfg(not(feature = "defmt"))]
57 ::core::debug_assert_eq!($($x)*);
58 #[cfg(feature = "defmt")]
59 ::defmt::debug_assert_eq!($($x)*);
60 }
61 };
62}
63
64macro_rules! debug_assert_ne {
65 ($($x:tt)*) => {
66 {
67 #[cfg(not(feature = "defmt"))]
68 ::core::debug_assert_ne!($($x)*);
69 #[cfg(feature = "defmt")]
70 ::defmt::debug_assert_ne!($($x)*);
71 }
72 };
73}
74
75macro_rules! todo {
76 ($($x:tt)*) => {
77 {
78 #[cfg(not(feature = "defmt"))]
79 ::core::todo!($($x)*);
80 #[cfg(feature = "defmt")]
81 ::defmt::todo!($($x)*);
82 }
83 };
84}
85
86#[cfg(not(feature = "defmt"))]
87macro_rules! unreachable {
88 ($($x:tt)*) => {
89 ::core::unreachable!($($x)*)
90 };
91}
92
93#[cfg(feature = "defmt")]
94macro_rules! unreachable {
95 ($($x:tt)*) => {
96 ::defmt::unreachable!($($x)*);
97 };
98}
99
100macro_rules! panic {
101 ($($x:tt)*) => {
102 {
103 #[cfg(not(feature = "defmt"))]
104 ::core::panic!($($x)*);
105 #[cfg(feature = "defmt")]
106 ::defmt::panic!($($x)*);
107 }
108 };
109}
110
111macro_rules! trace {
112 ($s:literal $(, $x:expr)* $(,)?) => {
113 {
114 #[cfg(feature = "log")]
115 ::log::trace!($s $(, $x)*);
116 #[cfg(feature = "defmt")]
117 ::defmt::trace!($s $(, $x)*);
118 #[cfg(not(any(feature = "log", feature="defmt")))]
119 let _ = ($( & $x ),*);
120 }
121 };
122}
123
124macro_rules! debug {
125 ($s:literal $(, $x:expr)* $(,)?) => {
126 {
127 #[cfg(feature = "log")]
128 ::log::debug!($s $(, $x)*);
129 #[cfg(feature = "defmt")]
130 ::defmt::debug!($s $(, $x)*);
131 #[cfg(not(any(feature = "log", feature="defmt")))]
132 let _ = ($( & $x ),*);
133 }
134 };
135}
136
137macro_rules! info {
138 ($s:literal $(, $x:expr)* $(,)?) => {
139 {
140 #[cfg(feature = "log")]
141 ::log::info!($s $(, $x)*);
142 #[cfg(feature = "defmt")]
143 ::defmt::info!($s $(, $x)*);
144 #[cfg(not(any(feature = "log", feature="defmt")))]
145 let _ = ($( & $x ),*);
146 }
147 };
148}
149
150macro_rules! warn {
151 ($s:literal $(, $x:expr)* $(,)?) => {
152 {
153 #[cfg(feature = "log")]
154 ::log::warn!($s $(, $x)*);
155 #[cfg(feature = "defmt")]
156 ::defmt::warn!($s $(, $x)*);
157 #[cfg(not(any(feature = "log", feature="defmt")))]
158 let _ = ($( & $x ),*);
159 }
160 };
161}
162
163macro_rules! error {
164 ($s:literal $(, $x:expr)* $(,)?) => {
165 {
166 #[cfg(feature = "log")]
167 ::log::error!($s $(, $x)*);
168 #[cfg(feature = "defmt")]
169 ::defmt::error!($s $(, $x)*);
170 #[cfg(not(any(feature = "log", feature="defmt")))]
171 let _ = ($( & $x ),*);
172 }
173 };
174}
175
176#[cfg(feature = "defmt")]
177macro_rules! unwrap {
178 ($($x:tt)*) => {
179 ::defmt::unwrap!($($x)*)
180 };
181}
182
183#[cfg(not(feature = "defmt"))]
184macro_rules! unwrap {
185 ($arg:expr) => {
186 match $crate::fmt::Try::into_result($arg) {
187 ::core::result::Result::Ok(t) => t,
188 ::core::result::Result::Err(e) => {
189 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
190 }
191 }
192 };
193 ($arg:expr, $($msg:expr),+ $(,)? ) => {
194 match $crate::fmt::Try::into_result($arg) {
195 ::core::result::Result::Ok(t) => t,
196 ::core::result::Result::Err(e) => {
197 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
198 }
199 }
200 }
201}
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq)]
204pub struct NoneError;
205
206pub trait Try {
207 type Ok;
208 type Error;
209 fn into_result(self) -> Result<Self::Ok, Self::Error>;
210}
211
212impl<T> Try for Option<T> {
213 type Ok = T;
214 type Error = NoneError;
215
216 #[inline]
217 fn into_result(self) -> Result<T, NoneError> {
218 self.ok_or(NoneError)
219 }
220}
221
222impl<T, E> Try for Result<T, E> {
223 type Ok = T;
224 type Error = E;
225
226 #[inline]
227 fn into_result(self) -> Self {
228 self
229 }
230}
231
232pub struct Bytes<'a>(pub &'a [u8]);
233
234impl<'a> Debug for Bytes<'a> {
235 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
236 write!(f, "{:#02x?}", self.0)
237 }
238}
239
240impl<'a> Display for Bytes<'a> {
241 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 write!(f, "{:#02x?}", self.0)
243 }
244}
245
246impl<'a> LowerHex for Bytes<'a> {
247 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
248 write!(f, "{:#02x?}", self.0)
249 }
250}
251
252#[cfg(feature = "defmt")]
253impl<'a> defmt::Format for Bytes<'a> {
254 fn format(&self, fmt: defmt::Formatter) {
255 defmt::write!(fmt, "{:02x}", self.0)
256 }
257}
diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs
new file mode 100644
index 000000000..e2a6815aa
--- /dev/null
+++ b/embassy-net-esp-hosted/src/ioctl.rs
@@ -0,0 +1,123 @@
1use core::cell::RefCell;
2use core::future::poll_fn;
3use core::task::Poll;
4
5use embassy_sync::waitqueue::WakerRegistration;
6
7use crate::fmt::Bytes;
8
9#[derive(Clone, Copy)]
10pub struct PendingIoctl {
11 pub buf: *mut [u8],
12 pub req_len: usize,
13}
14
15#[derive(Clone, Copy)]
16enum IoctlState {
17 Pending(PendingIoctl),
18 Sent { buf: *mut [u8] },
19 Done { resp_len: usize },
20}
21
22pub struct Shared(RefCell<SharedInner>);
23
24struct SharedInner {
25 ioctl: IoctlState,
26 is_init: bool,
27 control_waker: WakerRegistration,
28 runner_waker: WakerRegistration,
29}
30
31impl Shared {
32 pub fn new() -> Self {
33 Self(RefCell::new(SharedInner {
34 ioctl: IoctlState::Done { resp_len: 0 },
35 is_init: false,
36 control_waker: WakerRegistration::new(),
37 runner_waker: WakerRegistration::new(),
38 }))
39 }
40
41 pub async fn ioctl_wait_complete(&self) -> usize {
42 poll_fn(|cx| {
43 let mut this = self.0.borrow_mut();
44 if let IoctlState::Done { resp_len } = this.ioctl {
45 Poll::Ready(resp_len)
46 } else {
47 this.control_waker.register(cx.waker());
48 Poll::Pending
49 }
50 })
51 .await
52 }
53
54 pub async fn ioctl_wait_pending(&self) -> PendingIoctl {
55 let pending = poll_fn(|cx| {
56 let mut this = self.0.borrow_mut();
57 if let IoctlState::Pending(pending) = this.ioctl {
58 Poll::Ready(pending)
59 } else {
60 this.runner_waker.register(cx.waker());
61 Poll::Pending
62 }
63 })
64 .await;
65
66 self.0.borrow_mut().ioctl = IoctlState::Sent { buf: pending.buf };
67 pending
68 }
69
70 pub fn ioctl_cancel(&self) {
71 self.0.borrow_mut().ioctl = IoctlState::Done { resp_len: 0 };
72 }
73
74 pub async fn ioctl(&self, buf: &mut [u8], req_len: usize) -> usize {
75 trace!("ioctl req bytes: {:02x}", Bytes(&buf[..req_len]));
76
77 {
78 let mut this = self.0.borrow_mut();
79 this.ioctl = IoctlState::Pending(PendingIoctl { buf, req_len });
80 this.runner_waker.wake();
81 }
82
83 self.ioctl_wait_complete().await
84 }
85
86 pub fn ioctl_done(&self, response: &[u8]) {
87 let mut this = self.0.borrow_mut();
88 if let IoctlState::Sent { buf } = this.ioctl {
89 trace!("ioctl resp bytes: {:02x}", Bytes(response));
90
91 // TODO fix this
92 (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
93
94 this.ioctl = IoctlState::Done {
95 resp_len: response.len(),
96 };
97 this.control_waker.wake();
98 } else {
99 warn!("IOCTL Response but no pending Ioctl");
100 }
101 }
102
103 // // // // // // // // // // // // // // // // // // // //
104
105 pub fn init_done(&self) {
106 let mut this = self.0.borrow_mut();
107 this.is_init = true;
108 this.control_waker.wake();
109 }
110
111 pub async fn init_wait(&self) {
112 poll_fn(|cx| {
113 let mut this = self.0.borrow_mut();
114 if this.is_init {
115 Poll::Ready(())
116 } else {
117 this.control_waker.register(cx.waker());
118 Poll::Pending
119 }
120 })
121 .await
122 }
123}
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
new file mode 100644
index 000000000..44dfbe89c
--- /dev/null
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -0,0 +1,337 @@
1#![no_std]
2
3use control::Control;
4use embassy_futures::select::{select3, Either3};
5use embassy_net_driver_channel as ch;
6use embassy_time::{Duration, Instant, Timer};
7use embedded_hal::digital::{InputPin, OutputPin};
8use embedded_hal_async::digital::Wait;
9use embedded_hal_async::spi::SpiDevice;
10use ioctl::Shared;
11use proto::CtrlMsg;
12
13use crate::ioctl::PendingIoctl;
14use crate::proto::CtrlMsgPayload;
15
16mod proto;
17
18// must be first
19mod fmt;
20
21mod control;
22mod ioctl;
23
24const MTU: usize = 1514;
25
26macro_rules! impl_bytes {
27 ($t:ident) => {
28 impl $t {
29 pub const SIZE: usize = core::mem::size_of::<Self>();
30
31 #[allow(unused)]
32 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
33 unsafe { core::mem::transmute(*self) }
34 }
35
36 #[allow(unused)]
37 pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self {
38 let alignment = core::mem::align_of::<Self>();
39 assert_eq!(
40 bytes.as_ptr().align_offset(alignment),
41 0,
42 "{} is not aligned",
43 core::any::type_name::<Self>()
44 );
45 unsafe { core::mem::transmute(bytes) }
46 }
47
48 #[allow(unused)]
49 pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self {
50 let alignment = core::mem::align_of::<Self>();
51 assert_eq!(
52 bytes.as_ptr().align_offset(alignment),
53 0,
54 "{} is not aligned",
55 core::any::type_name::<Self>()
56 );
57
58 unsafe { core::mem::transmute(bytes) }
59 }
60 }
61 };
62}
63
64#[repr(C, packed)]
65#[derive(Clone, Copy, Debug, Default)]
66struct PayloadHeader {
67 /// InterfaceType on lower 4 bits, number on higher 4 bits.
68 if_type_and_num: u8,
69
70 /// Flags.
71 ///
72 /// bit 0: more fragments.
73 flags: u8,
74
75 len: u16,
76 offset: u16,
77 checksum: u16,
78 seq_num: u16,
79 reserved2: u8,
80
81 /// Packet type for HCI or PRIV interface, reserved otherwise
82 hci_priv_packet_type: u8,
83}
84impl_bytes!(PayloadHeader);
85
86#[allow(unused)]
87#[repr(u8)]
88enum InterfaceType {
89 Sta = 0,
90 Ap = 1,
91 Serial = 2,
92 Hci = 3,
93 Priv = 4,
94 Test = 5,
95}
96
97const MAX_SPI_BUFFER_SIZE: usize = 1600;
98
99pub struct State {
100 shared: Shared,
101 ch: ch::State<MTU, 4, 4>,
102}
103
104impl State {
105 pub fn new() -> Self {
106 Self {
107 shared: Shared::new(),
108 ch: ch::State::new(),
109 }
110 }
111}
112
113pub type NetDriver<'a> = ch::Device<'a, MTU>;
114
115pub async fn new<'a, SPI, IN, OUT>(
116 state: &'a mut State,
117 spi: SPI,
118 handshake: IN,
119 ready: IN,
120 reset: OUT,
121) -> (NetDriver<'a>, Control<'a>, Runner<'a, SPI, IN, OUT>)
122where
123 SPI: SpiDevice,
124 IN: InputPin + Wait,
125 OUT: OutputPin,
126{
127 let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
128 let state_ch = ch_runner.state_runner();
129
130 let mut runner = Runner {
131 ch: ch_runner,
132 shared: &state.shared,
133 next_seq: 1,
134 handshake,
135 ready,
136 reset,
137 spi,
138 };
139 runner.init().await;
140
141 (device, Control::new(state_ch, &state.shared), runner)
142}
143
144pub struct Runner<'a, SPI, IN, OUT> {
145 ch: ch::Runner<'a, MTU>,
146 shared: &'a Shared,
147
148 next_seq: u16,
149
150 spi: SPI,
151 handshake: IN,
152 ready: IN,
153 reset: OUT,
154}
155
156impl<'a, SPI, IN, OUT> Runner<'a, SPI, IN, OUT>
157where
158 SPI: SpiDevice,
159 IN: InputPin + Wait,
160 OUT: OutputPin,
161{
162 async fn init(&mut self) {}
163
164 pub async fn run(mut self) -> ! {
165 debug!("resetting...");
166 self.reset.set_low().unwrap();
167 Timer::after(Duration::from_millis(100)).await;
168 self.reset.set_high().unwrap();
169 Timer::after(Duration::from_millis(1000)).await;
170
171 let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
172 let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
173
174 loop {
175 self.handshake.wait_for_high().await.unwrap();
176
177 let ioctl = self.shared.ioctl_wait_pending();
178 let tx = self.ch.tx_buf();
179 let ev = async { self.ready.wait_for_high().await.unwrap() };
180
181 match select3(ioctl, tx, ev).await {
182 Either3::First(PendingIoctl { buf, req_len }) => {
183 tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02");
184 tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes());
185 tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]);
186
187 let mut header = PayloadHeader {
188 if_type_and_num: InterfaceType::Serial as _,
189 len: (req_len + 14) as _,
190 offset: PayloadHeader::SIZE as _,
191 seq_num: self.next_seq,
192 ..Default::default()
193 };
194 self.next_seq = self.next_seq.wrapping_add(1);
195
196 // Calculate checksum
197 tx_buf[0..12].copy_from_slice(&header.to_bytes());
198 header.checksum = checksum(&tx_buf[..26 + req_len]);
199 tx_buf[0..12].copy_from_slice(&header.to_bytes());
200 }
201 Either3::Second(packet) => {
202 tx_buf[12..][..packet.len()].copy_from_slice(packet);
203
204 let mut header = PayloadHeader {
205 if_type_and_num: InterfaceType::Sta as _,
206 len: packet.len() as _,
207 offset: PayloadHeader::SIZE as _,
208 seq_num: self.next_seq,
209 ..Default::default()
210 };
211 self.next_seq = self.next_seq.wrapping_add(1);
212
213 // Calculate checksum
214 tx_buf[0..12].copy_from_slice(&header.to_bytes());
215 header.checksum = checksum(&tx_buf[..12 + packet.len()]);
216 tx_buf[0..12].copy_from_slice(&header.to_bytes());
217
218 self.ch.tx_done();
219 }
220 Either3::Third(()) => {
221 tx_buf[..PayloadHeader::SIZE].fill(0);
222 }
223 }
224
225 if tx_buf[0] != 0 {
226 trace!("tx: {:02x}", &tx_buf[..40]);
227 }
228
229 self.spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
230
231 // The esp-hosted firmware deasserts the HANSHAKE pin a few us AFTER ending the SPI transfer
232 // If we check it again too fast, we'll see it's high from the previous transfer, and if we send it
233 // data it will get lost.
234 // Make sure we check it after 100us at minimum.
235 let delay_until = Instant::now() + Duration::from_micros(100);
236 self.handle_rx(&mut rx_buf);
237 Timer::at(delay_until).await;
238 }
239 }
240
241 fn handle_rx(&mut self, buf: &mut [u8]) {
242 trace!("rx: {:02x}", &buf[..40]);
243
244 let buf_len = buf.len();
245 let h = PayloadHeader::from_bytes_mut((&mut buf[..PayloadHeader::SIZE]).try_into().unwrap());
246
247 if h.len == 0 || h.offset as usize != PayloadHeader::SIZE {
248 return;
249 }
250
251 let payload_len = h.len as usize;
252 if buf_len < PayloadHeader::SIZE + payload_len {
253 warn!("rx: len too big");
254 return;
255 }
256
257 let if_type_and_num = h.if_type_and_num;
258 let want_checksum = h.checksum;
259 h.checksum = 0;
260 let got_checksum = checksum(&buf[..PayloadHeader::SIZE + payload_len]);
261 if want_checksum != got_checksum {
262 warn!("rx: bad checksum. Got {:04x}, want {:04x}", got_checksum, want_checksum);
263 return;
264 }
265
266 let payload = &mut buf[PayloadHeader::SIZE..][..payload_len];
267
268 match if_type_and_num & 0x0f {
269 // STA
270 0 => match self.ch.try_rx_buf() {
271 Some(buf) => {
272 buf[..payload.len()].copy_from_slice(payload);
273 self.ch.rx_done(payload.len())
274 }
275 None => warn!("failed to push rxd packet to the channel."),
276 },
277 // serial
278 2 => {
279 trace!("serial rx: {:02x}", payload);
280 if payload.len() < 14 {
281 warn!("serial rx: too short");
282 return;
283 }
284
285 let is_event = match &payload[..12] {
286 b"\x01\x08\x00ctrlResp\x02" => false,
287 b"\x01\x08\x00ctrlEvnt\x02" => true,
288 _ => {
289 warn!("serial rx: bad tlv");
290 return;
291 }
292 };
293
294 let len = u16::from_le_bytes(payload[12..14].try_into().unwrap()) as usize;
295 if payload.len() < 14 + len {
296 warn!("serial rx: too short 2");
297 return;
298 }
299 let data = &payload[14..][..len];
300
301 if is_event {
302 self.handle_event(data);
303 } else {
304 self.shared.ioctl_done(data);
305 }
306 }
307 _ => warn!("unknown iftype {}", if_type_and_num),
308 }
309 }
310
311 fn handle_event(&self, data: &[u8]) {
312 let Ok(event) = noproto::read::<CtrlMsg>(data) else {
313 warn!("failed to parse event");
314 return
315 };
316
317 debug!("event: {:?}", &event);
318
319 let Some(payload) = &event.payload else {
320 warn!("event without payload?");
321 return
322 };
323
324 match payload {
325 CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(),
326 _ => {}
327 }
328 }
329}
330
331fn checksum(buf: &[u8]) -> u16 {
332 let mut res = 0u16;
333 for &b in buf {
334 res = res.wrapping_add(b as _);
335 }
336 res
337}
diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs
new file mode 100644
index 000000000..8ceb1579d
--- /dev/null
+++ b/embassy-net-esp-hosted/src/proto.rs
@@ -0,0 +1,652 @@
1use heapless::{String, Vec};
2
3/// internal supporting structures for CtrlMsg
4
5#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub struct ScanResult {
8 #[noproto(tag = "1")]
9 pub ssid: String<32>,
10 #[noproto(tag = "2")]
11 pub chnl: u32,
12 #[noproto(tag = "3")]
13 pub rssi: u32,
14 #[noproto(tag = "4")]
15 pub bssid: String<32>,
16 #[noproto(tag = "5")]
17 pub sec_prot: CtrlWifiSecProt,
18}
19
20#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct ConnectedStaList {
23 #[noproto(tag = "1")]
24 pub mac: String<32>,
25 #[noproto(tag = "2")]
26 pub rssi: u32,
27}
28/// * Req/Resp structure *
29
30#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub struct CtrlMsgReqGetMacAddress {
33 #[noproto(tag = "1")]
34 pub mode: u32,
35}
36
37#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39pub struct CtrlMsgRespGetMacAddress {
40 #[noproto(tag = "1")]
41 pub mac: String<32>,
42 #[noproto(tag = "2")]
43 pub resp: u32,
44}
45
46#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub struct CtrlMsgReqGetMode {}
49
50#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52pub struct CtrlMsgRespGetMode {
53 #[noproto(tag = "1")]
54 pub mode: u32,
55 #[noproto(tag = "2")]
56 pub resp: u32,
57}
58
59#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61pub struct CtrlMsgReqSetMode {
62 #[noproto(tag = "1")]
63 pub mode: u32,
64}
65
66#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
68pub struct CtrlMsgRespSetMode {
69 #[noproto(tag = "1")]
70 pub resp: u32,
71}
72
73#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub struct CtrlMsgReqGetStatus {}
76
77#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79pub struct CtrlMsgRespGetStatus {
80 #[noproto(tag = "1")]
81 pub resp: u32,
82}
83
84#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub struct CtrlMsgReqSetMacAddress {
87 #[noproto(tag = "1")]
88 pub mac: String<32>,
89 #[noproto(tag = "2")]
90 pub mode: u32,
91}
92
93#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95pub struct CtrlMsgRespSetMacAddress {
96 #[noproto(tag = "1")]
97 pub resp: u32,
98}
99
100#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub struct CtrlMsgReqGetApConfig {}
103
104#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub struct CtrlMsgRespGetApConfig {
107 #[noproto(tag = "1")]
108 pub ssid: String<32>,
109 #[noproto(tag = "2")]
110 pub bssid: String<32>,
111 #[noproto(tag = "3")]
112 pub rssi: u32,
113 #[noproto(tag = "4")]
114 pub chnl: u32,
115 #[noproto(tag = "5")]
116 pub sec_prot: CtrlWifiSecProt,
117 #[noproto(tag = "6")]
118 pub resp: u32,
119}
120
121#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
122#[cfg_attr(feature = "defmt", derive(defmt::Format))]
123pub struct CtrlMsgReqConnectAp {
124 #[noproto(tag = "1")]
125 pub ssid: String<32>,
126 #[noproto(tag = "2")]
127 pub pwd: String<32>,
128 #[noproto(tag = "3")]
129 pub bssid: String<32>,
130 #[noproto(tag = "4")]
131 pub is_wpa3_supported: bool,
132 #[noproto(tag = "5")]
133 pub listen_interval: u32,
134}
135
136#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
137#[cfg_attr(feature = "defmt", derive(defmt::Format))]
138pub struct CtrlMsgRespConnectAp {
139 #[noproto(tag = "1")]
140 pub resp: u32,
141 #[noproto(tag = "2")]
142 pub mac: String<32>,
143}
144
145#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
146#[cfg_attr(feature = "defmt", derive(defmt::Format))]
147pub struct CtrlMsgReqGetSoftApConfig {}
148
149#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151pub struct CtrlMsgRespGetSoftApConfig {
152 #[noproto(tag = "1")]
153 pub ssid: String<32>,
154 #[noproto(tag = "2")]
155 pub pwd: String<32>,
156 #[noproto(tag = "3")]
157 pub chnl: u32,
158 #[noproto(tag = "4")]
159 pub sec_prot: CtrlWifiSecProt,
160 #[noproto(tag = "5")]
161 pub max_conn: u32,
162 #[noproto(tag = "6")]
163 pub ssid_hidden: bool,
164 #[noproto(tag = "7")]
165 pub bw: u32,
166 #[noproto(tag = "8")]
167 pub resp: u32,
168}
169
170#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
171#[cfg_attr(feature = "defmt", derive(defmt::Format))]
172pub struct CtrlMsgReqStartSoftAp {
173 #[noproto(tag = "1")]
174 pub ssid: String<32>,
175 #[noproto(tag = "2")]
176 pub pwd: String<32>,
177 #[noproto(tag = "3")]
178 pub chnl: u32,
179 #[noproto(tag = "4")]
180 pub sec_prot: CtrlWifiSecProt,
181 #[noproto(tag = "5")]
182 pub max_conn: u32,
183 #[noproto(tag = "6")]
184 pub ssid_hidden: bool,
185 #[noproto(tag = "7")]
186 pub bw: u32,
187}
188
189#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
190#[cfg_attr(feature = "defmt", derive(defmt::Format))]
191pub struct CtrlMsgRespStartSoftAp {
192 #[noproto(tag = "1")]
193 pub resp: u32,
194 #[noproto(tag = "2")]
195 pub mac: String<32>,
196}
197
198#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
199#[cfg_attr(feature = "defmt", derive(defmt::Format))]
200pub struct CtrlMsgReqScanResult {}
201
202#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
203#[cfg_attr(feature = "defmt", derive(defmt::Format))]
204pub struct CtrlMsgRespScanResult {
205 #[noproto(tag = "1")]
206 pub count: u32,
207 #[noproto(repeated, tag = "2")]
208 pub entries: Vec<ScanResult, 16>,
209 #[noproto(tag = "3")]
210 pub resp: u32,
211}
212
213#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
214#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub struct CtrlMsgReqSoftApConnectedSta {}
216
217#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
218#[cfg_attr(feature = "defmt", derive(defmt::Format))]
219pub struct CtrlMsgRespSoftApConnectedSta {
220 #[noproto(tag = "1")]
221 pub num: u32,
222 #[noproto(repeated, tag = "2")]
223 pub stations: Vec<ConnectedStaList, 16>,
224 #[noproto(tag = "3")]
225 pub resp: u32,
226}
227
228#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
229#[cfg_attr(feature = "defmt", derive(defmt::Format))]
230pub struct CtrlMsgReqOtaBegin {}
231
232#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
233#[cfg_attr(feature = "defmt", derive(defmt::Format))]
234pub struct CtrlMsgRespOtaBegin {
235 #[noproto(tag = "1")]
236 pub resp: u32,
237}
238
239#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
240#[cfg_attr(feature = "defmt", derive(defmt::Format))]
241pub struct CtrlMsgReqOtaWrite {
242 #[noproto(tag = "1")]
243 pub ota_data: Vec<u8, 1024>,
244}
245
246#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
247#[cfg_attr(feature = "defmt", derive(defmt::Format))]
248pub struct CtrlMsgRespOtaWrite {
249 #[noproto(tag = "1")]
250 pub resp: u32,
251}
252
253#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
254#[cfg_attr(feature = "defmt", derive(defmt::Format))]
255pub struct CtrlMsgReqOtaEnd {}
256
257#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
258#[cfg_attr(feature = "defmt", derive(defmt::Format))]
259pub struct CtrlMsgRespOtaEnd {
260 #[noproto(tag = "1")]
261 pub resp: u32,
262}
263
264#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
265#[cfg_attr(feature = "defmt", derive(defmt::Format))]
266pub struct CtrlMsgReqVendorIeData {
267 #[noproto(tag = "1")]
268 pub element_id: u32,
269 #[noproto(tag = "2")]
270 pub length: u32,
271 #[noproto(tag = "3")]
272 pub vendor_oui: Vec<u8, 8>,
273 #[noproto(tag = "4")]
274 pub vendor_oui_type: u32,
275 #[noproto(tag = "5")]
276 pub payload: Vec<u8, 64>,
277}
278
279#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
280#[cfg_attr(feature = "defmt", derive(defmt::Format))]
281pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
282 #[noproto(tag = "1")]
283 pub enable: bool,
284 #[noproto(tag = "2")]
285 pub r#type: CtrlVendorIeType,
286 #[noproto(tag = "3")]
287 pub idx: CtrlVendorIeid,
288 #[noproto(optional, tag = "4")]
289 pub vendor_ie_data: Option<CtrlMsgReqVendorIeData>,
290}
291
292#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
293#[cfg_attr(feature = "defmt", derive(defmt::Format))]
294pub struct CtrlMsgRespSetSoftApVendorSpecificIe {
295 #[noproto(tag = "1")]
296 pub resp: u32,
297}
298
299#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
300#[cfg_attr(feature = "defmt", derive(defmt::Format))]
301pub struct CtrlMsgReqSetWifiMaxTxPower {
302 #[noproto(tag = "1")]
303 pub wifi_max_tx_power: u32,
304}
305
306#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
307#[cfg_attr(feature = "defmt", derive(defmt::Format))]
308pub struct CtrlMsgRespSetWifiMaxTxPower {
309 #[noproto(tag = "1")]
310 pub resp: u32,
311}
312
313#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
314#[cfg_attr(feature = "defmt", derive(defmt::Format))]
315pub struct CtrlMsgReqGetWifiCurrTxPower {}
316
317#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
318#[cfg_attr(feature = "defmt", derive(defmt::Format))]
319pub struct CtrlMsgRespGetWifiCurrTxPower {
320 #[noproto(tag = "1")]
321 pub wifi_curr_tx_power: u32,
322 #[noproto(tag = "2")]
323 pub resp: u32,
324}
325
326#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
327#[cfg_attr(feature = "defmt", derive(defmt::Format))]
328pub struct CtrlMsgReqConfigHeartbeat {
329 #[noproto(tag = "1")]
330 pub enable: bool,
331 #[noproto(tag = "2")]
332 pub duration: u32,
333}
334
335#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
336#[cfg_attr(feature = "defmt", derive(defmt::Format))]
337pub struct CtrlMsgRespConfigHeartbeat {
338 #[noproto(tag = "1")]
339 pub resp: u32,
340}
341/// * Event structure *
342
343#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
344#[cfg_attr(feature = "defmt", derive(defmt::Format))]
345pub struct CtrlMsgEventEspInit {
346 #[noproto(tag = "1")]
347 pub init_data: Vec<u8, 64>,
348}
349
350#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
351#[cfg_attr(feature = "defmt", derive(defmt::Format))]
352pub struct CtrlMsgEventHeartbeat {
353 #[noproto(tag = "1")]
354 pub hb_num: u32,
355}
356
357#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
358#[cfg_attr(feature = "defmt", derive(defmt::Format))]
359pub struct CtrlMsgEventStationDisconnectFromAp {
360 #[noproto(tag = "1")]
361 pub resp: u32,
362}
363
364#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
365#[cfg_attr(feature = "defmt", derive(defmt::Format))]
366pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
367 #[noproto(tag = "1")]
368 pub resp: u32,
369 #[noproto(tag = "2")]
370 pub mac: String<32>,
371}
372
373#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
374#[cfg_attr(feature = "defmt", derive(defmt::Format))]
375pub struct CtrlMsg {
376 /// msg_type could be req, resp or Event
377 #[noproto(tag = "1")]
378 pub msg_type: CtrlMsgType,
379 /// msg id
380 #[noproto(tag = "2")]
381 pub msg_id: CtrlMsgId,
382 /// union of all msg ids
383 #[noproto(
384 oneof,
385 tags = "101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 301, 302, 303, 304"
386 )]
387 pub payload: Option<CtrlMsgPayload>,
388}
389
390/// union of all msg ids
391#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)]
392#[cfg_attr(feature = "defmt", derive(defmt::Format))]
393pub enum CtrlMsgPayload {
394 /// * Requests *
395 #[noproto(tag = "101")]
396 ReqGetMacAddress(CtrlMsgReqGetMacAddress),
397 #[noproto(tag = "102")]
398 ReqSetMacAddress(CtrlMsgReqSetMacAddress),
399 #[noproto(tag = "103")]
400 ReqGetWifiMode(CtrlMsgReqGetMode),
401 #[noproto(tag = "104")]
402 ReqSetWifiMode(CtrlMsgReqSetMode),
403 #[noproto(tag = "105")]
404 ReqScanApList(CtrlMsgReqScanResult),
405 #[noproto(tag = "106")]
406 ReqGetApConfig(CtrlMsgReqGetApConfig),
407 #[noproto(tag = "107")]
408 ReqConnectAp(CtrlMsgReqConnectAp),
409 #[noproto(tag = "108")]
410 ReqDisconnectAp(CtrlMsgReqGetStatus),
411 #[noproto(tag = "109")]
412 ReqGetSoftapConfig(CtrlMsgReqGetSoftApConfig),
413 #[noproto(tag = "110")]
414 ReqSetSoftapVendorSpecificIe(CtrlMsgReqSetSoftApVendorSpecificIe),
415 #[noproto(tag = "111")]
416 ReqStartSoftap(CtrlMsgReqStartSoftAp),
417 #[noproto(tag = "112")]
418 ReqSoftapConnectedStasList(CtrlMsgReqSoftApConnectedSta),
419 #[noproto(tag = "113")]
420 ReqStopSoftap(CtrlMsgReqGetStatus),
421 #[noproto(tag = "114")]
422 ReqSetPowerSaveMode(CtrlMsgReqSetMode),
423 #[noproto(tag = "115")]
424 ReqGetPowerSaveMode(CtrlMsgReqGetMode),
425 #[noproto(tag = "116")]
426 ReqOtaBegin(CtrlMsgReqOtaBegin),
427 #[noproto(tag = "117")]
428 ReqOtaWrite(CtrlMsgReqOtaWrite),
429 #[noproto(tag = "118")]
430 ReqOtaEnd(CtrlMsgReqOtaEnd),
431 #[noproto(tag = "119")]
432 ReqSetWifiMaxTxPower(CtrlMsgReqSetWifiMaxTxPower),
433 #[noproto(tag = "120")]
434 ReqGetWifiCurrTxPower(CtrlMsgReqGetWifiCurrTxPower),
435 #[noproto(tag = "121")]
436 ReqConfigHeartbeat(CtrlMsgReqConfigHeartbeat),
437 /// * Responses *
438 #[noproto(tag = "201")]
439 RespGetMacAddress(CtrlMsgRespGetMacAddress),
440 #[noproto(tag = "202")]
441 RespSetMacAddress(CtrlMsgRespSetMacAddress),
442 #[noproto(tag = "203")]
443 RespGetWifiMode(CtrlMsgRespGetMode),
444 #[noproto(tag = "204")]
445 RespSetWifiMode(CtrlMsgRespSetMode),
446 #[noproto(tag = "205")]
447 RespScanApList(CtrlMsgRespScanResult),
448 #[noproto(tag = "206")]
449 RespGetApConfig(CtrlMsgRespGetApConfig),
450 #[noproto(tag = "207")]
451 RespConnectAp(CtrlMsgRespConnectAp),
452 #[noproto(tag = "208")]
453 RespDisconnectAp(CtrlMsgRespGetStatus),
454 #[noproto(tag = "209")]
455 RespGetSoftapConfig(CtrlMsgRespGetSoftApConfig),
456 #[noproto(tag = "210")]
457 RespSetSoftapVendorSpecificIe(CtrlMsgRespSetSoftApVendorSpecificIe),
458 #[noproto(tag = "211")]
459 RespStartSoftap(CtrlMsgRespStartSoftAp),
460 #[noproto(tag = "212")]
461 RespSoftapConnectedStasList(CtrlMsgRespSoftApConnectedSta),
462 #[noproto(tag = "213")]
463 RespStopSoftap(CtrlMsgRespGetStatus),
464 #[noproto(tag = "214")]
465 RespSetPowerSaveMode(CtrlMsgRespSetMode),
466 #[noproto(tag = "215")]
467 RespGetPowerSaveMode(CtrlMsgRespGetMode),
468 #[noproto(tag = "216")]
469 RespOtaBegin(CtrlMsgRespOtaBegin),
470 #[noproto(tag = "217")]
471 RespOtaWrite(CtrlMsgRespOtaWrite),
472 #[noproto(tag = "218")]
473 RespOtaEnd(CtrlMsgRespOtaEnd),
474 #[noproto(tag = "219")]
475 RespSetWifiMaxTxPower(CtrlMsgRespSetWifiMaxTxPower),
476 #[noproto(tag = "220")]
477 RespGetWifiCurrTxPower(CtrlMsgRespGetWifiCurrTxPower),
478 #[noproto(tag = "221")]
479 RespConfigHeartbeat(CtrlMsgRespConfigHeartbeat),
480 /// * Notifications *
481 #[noproto(tag = "301")]
482 EventEspInit(CtrlMsgEventEspInit),
483 #[noproto(tag = "302")]
484 EventHeartbeat(CtrlMsgEventHeartbeat),
485 #[noproto(tag = "303")]
486 EventStationDisconnectFromAp(CtrlMsgEventStationDisconnectFromAp),
487 #[noproto(tag = "304")]
488 EventStationDisconnectFromEspSoftAp(CtrlMsgEventStationDisconnectFromEspSoftAp),
489}
490
491/// Enums similar to ESP IDF
492#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
493#[repr(u32)]
494#[cfg_attr(feature = "defmt", derive(defmt::Format))]
495pub enum CtrlVendorIeType {
496 #[default]
497 Beacon = 0,
498 ProbeReq = 1,
499 ProbeResp = 2,
500 AssocReq = 3,
501 AssocResp = 4,
502}
503
504#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
505#[repr(u32)]
506#[cfg_attr(feature = "defmt", derive(defmt::Format))]
507pub enum CtrlVendorIeid {
508 #[default]
509 Id0 = 0,
510 Id1 = 1,
511}
512
513#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
514#[repr(u32)]
515#[cfg_attr(feature = "defmt", derive(defmt::Format))]
516pub enum CtrlWifiMode {
517 #[default]
518 None = 0,
519 Sta = 1,
520 Ap = 2,
521 Apsta = 3,
522}
523
524#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
525#[repr(u32)]
526#[cfg_attr(feature = "defmt", derive(defmt::Format))]
527pub enum CtrlWifiBw {
528 #[default]
529 BwInvalid = 0,
530 Ht20 = 1,
531 Ht40 = 2,
532}
533
534#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
535#[repr(u32)]
536#[cfg_attr(feature = "defmt", derive(defmt::Format))]
537pub enum CtrlWifiPowerSave {
538 #[default]
539 PsInvalid = 0,
540 MinModem = 1,
541 MaxModem = 2,
542}
543
544#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
545#[repr(u32)]
546#[cfg_attr(feature = "defmt", derive(defmt::Format))]
547pub enum CtrlWifiSecProt {
548 #[default]
549 Open = 0,
550 Wep = 1,
551 WpaPsk = 2,
552 Wpa2Psk = 3,
553 WpaWpa2Psk = 4,
554 Wpa2Enterprise = 5,
555 Wpa3Psk = 6,
556 Wpa2Wpa3Psk = 7,
557}
558
559/// enums for Control path
560#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
561#[repr(u32)]
562#[cfg_attr(feature = "defmt", derive(defmt::Format))]
563pub enum CtrlStatus {
564 #[default]
565 Connected = 0,
566 NotConnected = 1,
567 NoApFound = 2,
568 ConnectionFail = 3,
569 InvalidArgument = 4,
570 OutOfRange = 5,
571}
572
573#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
574#[repr(u32)]
575#[cfg_attr(feature = "defmt", derive(defmt::Format))]
576pub enum CtrlMsgType {
577 #[default]
578 MsgTypeInvalid = 0,
579 Req = 1,
580 Resp = 2,
581 Event = 3,
582 MsgTypeMax = 4,
583}
584
585#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
586#[repr(u32)]
587#[cfg_attr(feature = "defmt", derive(defmt::Format))]
588pub enum CtrlMsgId {
589 #[default]
590 MsgIdInvalid = 0,
591 /// * Request Msgs *
592 ReqBase = 100,
593 ReqGetMacAddress = 101,
594 ReqSetMacAddress = 102,
595 ReqGetWifiMode = 103,
596 ReqSetWifiMode = 104,
597 ReqGetApScanList = 105,
598 ReqGetApConfig = 106,
599 ReqConnectAp = 107,
600 ReqDisconnectAp = 108,
601 ReqGetSoftApConfig = 109,
602 ReqSetSoftApVendorSpecificIe = 110,
603 ReqStartSoftAp = 111,
604 ReqGetSoftApConnectedStaList = 112,
605 ReqStopSoftAp = 113,
606 ReqSetPowerSaveMode = 114,
607 ReqGetPowerSaveMode = 115,
608 ReqOtaBegin = 116,
609 ReqOtaWrite = 117,
610 ReqOtaEnd = 118,
611 ReqSetWifiMaxTxPower = 119,
612 ReqGetWifiCurrTxPower = 120,
613 ReqConfigHeartbeat = 121,
614 /// Add new control path command response before Req_Max
615 /// and update Req_Max
616 ReqMax = 122,
617 /// * Response Msgs *
618 RespBase = 200,
619 RespGetMacAddress = 201,
620 RespSetMacAddress = 202,
621 RespGetWifiMode = 203,
622 RespSetWifiMode = 204,
623 RespGetApScanList = 205,
624 RespGetApConfig = 206,
625 RespConnectAp = 207,
626 RespDisconnectAp = 208,
627 RespGetSoftApConfig = 209,
628 RespSetSoftApVendorSpecificIe = 210,
629 RespStartSoftAp = 211,
630 RespGetSoftApConnectedStaList = 212,
631 RespStopSoftAp = 213,
632 RespSetPowerSaveMode = 214,
633 RespGetPowerSaveMode = 215,
634 RespOtaBegin = 216,
635 RespOtaWrite = 217,
636 RespOtaEnd = 218,
637 RespSetWifiMaxTxPower = 219,
638 RespGetWifiCurrTxPower = 220,
639 RespConfigHeartbeat = 221,
640 /// Add new control path command response before Resp_Max
641 /// and update Resp_Max
642 RespMax = 222,
643 /// * Event Msgs *
644 EventBase = 300,
645 EventEspInit = 301,
646 EventHeartbeat = 302,
647 EventStationDisconnectFromAp = 303,
648 EventStationDisconnectFromEspSoftAp = 304,
649 /// Add new control path command notification before Event_Max
650 /// and update Event_Max
651 EventMax = 305,
652}
diff --git a/embassy-net-w5500/src/lib.rs b/embassy-net-w5500/src/lib.rs
index 6821373e3..efd9bed66 100644
--- a/embassy-net-w5500/src/lib.rs
+++ b/embassy-net-w5500/src/lib.rs
@@ -1,5 +1,6 @@
1//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip.
1#![no_std] 2#![no_std]
2/// [`embassy-net`](crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. 3
3mod device; 4mod device;
4mod socket; 5mod socket;
5mod spi; 6mod spi;
@@ -77,7 +78,7 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
77 } 78 }
78} 79}
79 80
80/// Obtain a driver for using the W5500 with [`embassy-net`](crates.io/crates/embassy-net). 81/// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net).
81pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>( 82pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>(
82 mac_addr: [u8; 6], 83 mac_addr: [u8; 6],
83 state: &'a mut State<N_RX, N_TX>, 84 state: &'a mut State<N_RX, N_TX>,
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 0a47c5d94..e89039daa 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -3,7 +3,13 @@ name = "embassy-net"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6description = "Async TCP/IP network stack for embedded systems"
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
7 13
8[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
9src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
@@ -26,7 +32,8 @@ unstable-traits = []
26udp = ["smoltcp/socket-udp"] 32udp = ["smoltcp/socket-udp"]
27tcp = ["smoltcp/socket-tcp"] 33tcp = ["smoltcp/socket-tcp"]
28dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] 34dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
29dhcpv4 = ["medium-ethernet", "smoltcp/socket-dhcpv4"] 35dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
36proto-ipv4 = ["smoltcp/proto-ipv4"]
30proto-ipv6 = ["smoltcp/proto-ipv6"] 37proto-ipv6 = ["smoltcp/proto-ipv6"]
31medium-ethernet = ["smoltcp/medium-ethernet"] 38medium-ethernet = ["smoltcp/medium-ethernet"]
32medium-ip = ["smoltcp/medium-ip"] 39medium-ip = ["smoltcp/medium-ip"]
@@ -37,14 +44,12 @@ igmp = ["smoltcp/proto-igmp"]
37defmt = { version = "0.3", optional = true } 44defmt = { version = "0.3", optional = true }
38log = { version = "0.4.14", optional = true } 45log = { version = "0.4.14", optional = true }
39 46
40smoltcp = { version = "0.9.0", default-features = false, features = [ 47smoltcp = { version = "0.10.0", default-features = false, features = [
41 "proto-ipv4",
42 "socket", 48 "socket",
43 "async", 49 "async",
44]} 50] }
45 51
46embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 52embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
47embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
48embassy-time = { version = "0.1.0", path = "../embassy-time" } 53embassy-time = { version = "0.1.0", path = "../embassy-time" }
49embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 54embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
50embedded-io = { version = "0.4.0", optional = true } 55embedded-io = { version = "0.4.0", optional = true }
diff --git a/embassy-net/README.md b/embassy-net/README.md
index 470926c58..48f9fd832 100644
--- a/embassy-net/README.md
+++ b/embassy-net/README.md
@@ -1,30 +1,56 @@
1# embassy-net 1# embassy-net
2 2
3embassy-net contains an async network API based on smoltcp and embassy, designed 3`embassy-net` is a no-std no-alloc async network stack, designed for embedded systems.
4for embedded systems.
5 4
6## Running the example 5It builds on [`smoltcp`](https://github.com/smoltcp-rs/smoltcp). It provides a higher-level and more opinionated
6API. It glues together the components provided by `smoltcp`, handling the low-level details with defaults and
7memory management designed to work well for embedded systems, aiiming for a more "Just Works" experience.
7 8
8First, create the tap0 interface. You only need to do this once. 9## Features
9 10
10```sh 11- IPv4, IPv6
11sudo ip tuntap add name tap0 mode tap user $USER 12- Ethernet and bare-IP mediums.
12sudo ip link set tap0 up 13- TCP, UDP, DNS, DHCPv4, IGMPv4
13sudo ip addr add 192.168.69.100/24 dev tap0 14- TCP sockets implement the `embedded-io` async traits.
14sudo ip -6 addr add fe80::100/64 dev tap0
15sudo ip -6 addr add fdaa::100/64 dev tap0
16sudo ip -6 route add fe80::/64 dev tap0
17sudo ip -6 route add fdaa::/64 dev tap0
18```
19 15
20Second, have something listening there. For example `nc -l 8000` 16See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and
17unimplemented features of the network protocols.
21 18
22Then run the example located in the `examples` folder: 19## Hardware support
23 20
24```sh 21- [`esp-wifi`](https://github.com/esp-rs/esp-wifi) for WiFi support on bare-metal ESP32 chips. Maintained by Espressif.
25cd $EMBASSY_ROOT/examples/std/ 22- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W
26cargo run --bin net -- --static-ip 23- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support.
27``` 24- [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5).
25- [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip.
26- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
27
28## Examples
29
30- For usage with Embassy HALs and network chip drivers, search [here](https://github.com/embassy-rs/embassy/tree/main/examples) for `eth` or `wifi`.
31- The [`esp-wifi` repo](https://github.com/esp-rs/esp-wifi) has examples for use on bare-metal ESP32 chips.
32- For usage on `std` platforms, see [the `std` examples](https://github.com/embassy-rs/embassy/tree/main/examples/std/src/bin)
33
34## Adding support for new hardware
35
36To add `embassy-net` support for new hardware (i.e. a new Ethernet or WiFi chip, or
37an Ethernet/WiFi MCU peripheral), you have to implement the [`embassy-net-driver`](https://crates.io/crates/embassy-net-driver)
38traits.
39
40Alternatively, [`embassy-net-driver-channel`](https://crates.io/crates/embassy-net-driver-channel) provides a higer-level API
41to construct a driver that processes packets in its own background task and communicates with the `embassy-net` task via
42packet queues for RX and TX.
43
44Drivers should depend only on `embassy-net-driver` or `embassy-net-driver-channel`. Never on the main `embassy-net` crate.
45This allows existing drivers to continue working for newer `embassy-net` major versions, without needing an update, if the driver
46trait has not had breaking changes.
47
48## Interoperability
49
50This crate can run on any executor.
51
52[`embassy-time`](https://crates.io/crates/embassy-net-driver) is used for timekeeping and timeouts. You must
53link an `embassy-time` driver in your project to use this crate.
28 54
29## License 55## License
30 56
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs
index 5daa00544..4513c86d3 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/device.rs
@@ -51,15 +51,19 @@ where
51 Medium::Ethernet => phy::Medium::Ethernet, 51 Medium::Ethernet => phy::Medium::Ethernet,
52 #[cfg(feature = "medium-ip")] 52 #[cfg(feature = "medium-ip")]
53 Medium::Ip => phy::Medium::Ip, 53 Medium::Ip => phy::Medium::Ip,
54 #[allow(unreachable_patterns)]
54 _ => panic!( 55 _ => panic!(
55 "Unsupported medium {:?}. MAke sure to enable it in embassy-net's Cargo features.", 56 "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
56 caps.medium 57 caps.medium
57 ), 58 ),
58 }; 59 };
59 smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4); 60 smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
60 smolcaps.checksum.tcp = convert(caps.checksum.tcp); 61 smolcaps.checksum.tcp = convert(caps.checksum.tcp);
61 smolcaps.checksum.udp = convert(caps.checksum.udp); 62 smolcaps.checksum.udp = convert(caps.checksum.udp);
62 smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4); 63 #[cfg(feature = "proto-ipv4")]
64 {
65 smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4);
66 }
63 #[cfg(feature = "proto-ipv6")] 67 #[cfg(feature = "proto-ipv6")]
64 { 68 {
65 smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6); 69 smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6);
diff --git a/embassy-net/src/dns.rs b/embassy-net/src/dns.rs
index 3fd235b2c..94f75f108 100644
--- a/embassy-net/src/dns.rs
+++ b/embassy-net/src/dns.rs
@@ -88,6 +88,7 @@ where
88 let addrs = self.query(host, qtype).await?; 88 let addrs = self.query(host, qtype).await?;
89 if let Some(first) = addrs.get(0) { 89 if let Some(first) = addrs.get(0) {
90 Ok(match first { 90 Ok(match first {
91 #[cfg(feature = "proto-ipv4")]
91 IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()), 92 IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()),
92 #[cfg(feature = "proto-ipv6")] 93 #[cfg(feature = "proto-ipv6")]
93 IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()), 94 IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()),
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index bccbad521..840d7a09a 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -34,7 +34,9 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
34pub use smoltcp::wire::IpListenEndpoint; 34pub use smoltcp::wire::IpListenEndpoint;
35#[cfg(feature = "medium-ethernet")] 35#[cfg(feature = "medium-ethernet")]
36pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; 36pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
37pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; 37pub use smoltcp::wire::{IpAddress, IpCidr};
38#[cfg(feature = "proto-ipv4")]
39pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
38#[cfg(feature = "proto-ipv6")] 40#[cfg(feature = "proto-ipv6")]
39pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; 41pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
40 42
@@ -55,7 +57,7 @@ pub struct StackResources<const SOCK: usize> {
55 57
56impl<const SOCK: usize> StackResources<SOCK> { 58impl<const SOCK: usize> StackResources<SOCK> {
57 /// Create a new set of stack resources. 59 /// Create a new set of stack resources.
58 pub fn new() -> Self { 60 pub const fn new() -> Self {
59 #[cfg(feature = "dns")] 61 #[cfg(feature = "dns")]
60 const INIT: Option<dns::DnsQuery> = None; 62 const INIT: Option<dns::DnsQuery> = None;
61 Self { 63 Self {
@@ -67,8 +69,9 @@ impl<const SOCK: usize> StackResources<SOCK> {
67} 69}
68 70
69/// Static IP address configuration. 71/// Static IP address configuration.
72#[cfg(feature = "proto-ipv4")]
70#[derive(Debug, Clone, PartialEq, Eq)] 73#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct StaticConfig { 74pub struct StaticConfigV4 {
72 /// IP address and subnet mask. 75 /// IP address and subnet mask.
73 pub address: Ipv4Cidr, 76 pub address: Ipv4Cidr,
74 /// Default gateway. 77 /// Default gateway.
@@ -77,6 +80,18 @@ pub struct StaticConfig {
77 pub dns_servers: Vec<Ipv4Address, 3>, 80 pub dns_servers: Vec<Ipv4Address, 3>,
78} 81}
79 82
83/// Static IPv6 address configuration
84#[cfg(feature = "proto-ipv6")]
85#[derive(Debug, Clone, PartialEq, Eq)]
86pub struct StaticConfigV6 {
87 /// IP address and subnet mask.
88 pub address: Ipv6Cidr,
89 /// Default gateway.
90 pub gateway: Option<Ipv6Address>,
91 /// DNS servers.
92 pub dns_servers: Vec<Ipv6Address, 3>,
93}
94
80/// DHCP configuration. 95/// DHCP configuration.
81#[cfg(feature = "dhcpv4")] 96#[cfg(feature = "dhcpv4")]
82#[derive(Debug, Clone, PartialEq, Eq)] 97#[derive(Debug, Clone, PartialEq, Eq)]
@@ -112,12 +127,71 @@ impl Default for DhcpConfig {
112} 127}
113 128
114/// Network stack configuration. 129/// Network stack configuration.
115pub enum Config { 130pub struct Config {
116 /// Use a static IP address configuration. 131 /// IPv4 configuration
117 Static(StaticConfig), 132 #[cfg(feature = "proto-ipv4")]
133 pub ipv4: ConfigV4,
134 /// IPv6 configuration
135 #[cfg(feature = "proto-ipv6")]
136 pub ipv6: ConfigV6,
137}
138
139impl Config {
140 /// IPv4 configuration with static addressing.
141 #[cfg(feature = "proto-ipv4")]
142 pub fn ipv4_static(config: StaticConfigV4) -> Self {
143 Self {
144 ipv4: ConfigV4::Static(config),
145 #[cfg(feature = "proto-ipv6")]
146 ipv6: ConfigV6::None,
147 }
148 }
149
150 /// IPv6 configuration with static addressing.
151 #[cfg(feature = "proto-ipv6")]
152 pub fn ipv6_static(config: StaticConfigV6) -> Self {
153 Self {
154 #[cfg(feature = "proto-ipv4")]
155 ipv4: ConfigV4::None,
156 ipv6: ConfigV6::Static(config),
157 }
158 }
159
160 /// IPv6 configuration with dynamic addressing.
161 ///
162 /// # Example
163 /// ```rust
164 /// let _cfg = Config::dhcpv4(Default::default());
165 /// ```
166 #[cfg(feature = "dhcpv4")]
167 pub fn dhcpv4(config: DhcpConfig) -> Self {
168 Self {
169 ipv4: ConfigV4::Dhcp(config),
170 #[cfg(feature = "proto-ipv6")]
171 ipv6: ConfigV6::None,
172 }
173 }
174}
175
176/// Network stack IPv4 configuration.
177#[cfg(feature = "proto-ipv4")]
178pub enum ConfigV4 {
179 /// Use a static IPv4 address configuration.
180 Static(StaticConfigV4),
118 /// Use DHCP to obtain an IP address configuration. 181 /// Use DHCP to obtain an IP address configuration.
119 #[cfg(feature = "dhcpv4")] 182 #[cfg(feature = "dhcpv4")]
120 Dhcp(DhcpConfig), 183 Dhcp(DhcpConfig),
184 /// Do not configure IPv6.
185 None,
186}
187
188/// Network stack IPv6 configuration.
189#[cfg(feature = "proto-ipv6")]
190pub enum ConfigV6 {
191 /// Use a static IPv6 address configuration.
192 Static(StaticConfigV6),
193 /// Do not configure IPv6.
194 None,
121} 195}
122 196
123/// A network stack. 197/// A network stack.
@@ -131,7 +205,10 @@ pub struct Stack<D: Driver> {
131struct Inner<D: Driver> { 205struct Inner<D: Driver> {
132 device: D, 206 device: D,
133 link_up: bool, 207 link_up: bool,
134 config: Option<StaticConfig>, 208 #[cfg(feature = "proto-ipv4")]
209 static_v4: Option<StaticConfigV4>,
210 #[cfg(feature = "proto-ipv6")]
211 static_v6: Option<StaticConfigV6>,
135 #[cfg(feature = "dhcpv4")] 212 #[cfg(feature = "dhcpv4")]
136 dhcp_socket: Option<SocketHandle>, 213 dhcp_socket: Option<SocketHandle>,
137 #[cfg(feature = "dns")] 214 #[cfg(feature = "dns")]
@@ -158,12 +235,19 @@ impl<D: Driver + 'static> Stack<D> {
158 #[cfg(feature = "medium-ethernet")] 235 #[cfg(feature = "medium-ethernet")]
159 let medium = device.capabilities().medium; 236 let medium = device.capabilities().medium;
160 237
161 let mut iface_cfg = smoltcp::iface::Config::new(); 238 let hardware_addr = match medium {
239 #[cfg(feature = "medium-ethernet")]
240 Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())),
241 #[cfg(feature = "medium-ip")]
242 Medium::Ip => HardwareAddress::Ip,
243 #[allow(unreachable_patterns)]
244 _ => panic!(
245 "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
246 medium
247 ),
248 };
249 let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr);
162 iface_cfg.random_seed = random_seed; 250 iface_cfg.random_seed = random_seed;
163 #[cfg(feature = "medium-ethernet")]
164 if medium == Medium::Ethernet {
165 iface_cfg.hardware_addr = Some(HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())));
166 }
167 251
168 let iface = Interface::new( 252 let iface = Interface::new(
169 iface_cfg, 253 iface_cfg,
@@ -171,6 +255,7 @@ impl<D: Driver + 'static> Stack<D> {
171 inner: &mut device, 255 inner: &mut device,
172 cx: None, 256 cx: None,
173 }, 257 },
258 instant_to_smoltcp(Instant::now()),
174 ); 259 );
175 260
176 let sockets = SocketSet::new(&mut resources.sockets[..]); 261 let sockets = SocketSet::new(&mut resources.sockets[..]);
@@ -187,7 +272,10 @@ impl<D: Driver + 'static> Stack<D> {
187 let mut inner = Inner { 272 let mut inner = Inner {
188 device, 273 device,
189 link_up: false, 274 link_up: false,
190 config: None, 275 #[cfg(feature = "proto-ipv4")]
276 static_v4: None,
277 #[cfg(feature = "proto-ipv6")]
278 static_v6: None,
191 #[cfg(feature = "dhcpv4")] 279 #[cfg(feature = "dhcpv4")]
192 dhcp_socket: None, 280 dhcp_socket: None,
193 #[cfg(feature = "dns")] 281 #[cfg(feature = "dns")]
@@ -199,17 +287,26 @@ impl<D: Driver + 'static> Stack<D> {
199 dns_waker: WakerRegistration::new(), 287 dns_waker: WakerRegistration::new(),
200 }; 288 };
201 289
202 match config { 290 #[cfg(feature = "proto-ipv4")]
203 Config::Static(config) => { 291 match config.ipv4 {
204 inner.apply_config(&mut socket, config); 292 ConfigV4::Static(config) => {
293 inner.apply_config_v4(&mut socket, config);
205 } 294 }
206 #[cfg(feature = "dhcpv4")] 295 #[cfg(feature = "dhcpv4")]
207 Config::Dhcp(config) => { 296 ConfigV4::Dhcp(config) => {
208 let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); 297 let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new();
209 inner.apply_dhcp_config(&mut dhcp_socket, config); 298 inner.apply_dhcp_config(&mut dhcp_socket, config);
210 let handle = socket.sockets.add(dhcp_socket); 299 let handle = socket.sockets.add(dhcp_socket);
211 inner.dhcp_socket = Some(handle); 300 inner.dhcp_socket = Some(handle);
212 } 301 }
302 ConfigV4::None => {}
303 }
304 #[cfg(feature = "proto-ipv6")]
305 match config.ipv6 {
306 ConfigV6::Static(config) => {
307 inner.apply_config_v6(&mut socket, config);
308 }
309 ConfigV6::None => {}
213 } 310 }
214 311
215 Self { 312 Self {
@@ -239,12 +336,40 @@ impl<D: Driver + 'static> Stack<D> {
239 /// Get whether the network stack has a valid IP configuration. 336 /// Get whether the network stack has a valid IP configuration.
240 /// This is true if the network stack has a static IP configuration or if DHCP has completed 337 /// This is true if the network stack has a static IP configuration or if DHCP has completed
241 pub fn is_config_up(&self) -> bool { 338 pub fn is_config_up(&self) -> bool {
242 self.with(|_s, i| i.config.is_some()) 339 let v4_up;
340 let v6_up;
341
342 #[cfg(feature = "proto-ipv4")]
343 {
344 v4_up = self.config_v4().is_some();
345 }
346 #[cfg(not(feature = "proto-ipv4"))]
347 {
348 v4_up = false;
349 }
350
351 #[cfg(feature = "proto-ipv6")]
352 {
353 v6_up = self.config_v6().is_some();
354 }
355 #[cfg(not(feature = "proto-ipv6"))]
356 {
357 v6_up = false;
358 }
359
360 v4_up || v6_up
243 } 361 }
244 362
245 /// Get the current IP configuration. 363 /// Get the current IPv4 configuration.
246 pub fn config(&self) -> Option<StaticConfig> { 364 #[cfg(feature = "proto-ipv4")]
247 self.with(|_s, i| i.config.clone()) 365 pub fn config_v4(&self) -> Option<StaticConfigV4> {
366 self.with(|_s, i| i.static_v4.clone())
367 }
368
369 /// Get the current IPv6 configuration.
370 #[cfg(feature = "proto-ipv6")]
371 pub fn config_v6(&self) -> Option<StaticConfigV6> {
372 self.with(|_s, i| i.static_v6.clone())
248 } 373 }
249 374
250 /// Run the network stack. 375 /// Run the network stack.
@@ -264,6 +389,7 @@ impl<D: Driver + 'static> Stack<D> {
264 pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> { 389 pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
265 // For A and AAAA queries we try detect whether `name` is just an IP address 390 // For A and AAAA queries we try detect whether `name` is just an IP address
266 match qtype { 391 match qtype {
392 #[cfg(feature = "proto-ipv4")]
267 dns::DnsQueryType::A => { 393 dns::DnsQueryType::A => {
268 if let Ok(ip) = name.parse().map(IpAddress::Ipv4) { 394 if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
269 return Ok([ip].into_iter().collect()); 395 return Ok([ip].into_iter().collect());
@@ -293,7 +419,29 @@ impl<D: Driver + 'static> Stack<D> {
293 }) 419 })
294 .await?; 420 .await?;
295 421
296 use embassy_hal_common::drop::OnDrop; 422 #[must_use = "to delay the drop handler invocation to the end of the scope"]
423 struct OnDrop<F: FnOnce()> {
424 f: core::mem::MaybeUninit<F>,
425 }
426
427 impl<F: FnOnce()> OnDrop<F> {
428 fn new(f: F) -> Self {
429 Self {
430 f: core::mem::MaybeUninit::new(f),
431 }
432 }
433
434 fn defuse(self) {
435 core::mem::forget(self)
436 }
437 }
438
439 impl<F: FnOnce()> Drop for OnDrop<F> {
440 fn drop(&mut self) {
441 unsafe { self.f.as_ptr().read()() }
442 }
443 }
444
297 let drop = OnDrop::new(|| { 445 let drop = OnDrop::new(|| {
298 self.with_mut(|s, i| { 446 self.with_mut(|s, i| {
299 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); 447 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
@@ -374,7 +522,8 @@ impl SocketStack {
374} 522}
375 523
376impl<D: Driver + 'static> Inner<D> { 524impl<D: Driver + 'static> Inner<D> {
377 fn apply_config(&mut self, s: &mut SocketStack, config: StaticConfig) { 525 #[cfg(feature = "proto-ipv4")]
526 fn apply_config_v4(&mut self, s: &mut SocketStack, config: StaticConfigV4) {
378 #[cfg(feature = "medium-ethernet")] 527 #[cfg(feature = "medium-ethernet")]
379 let medium = self.device.capabilities().medium; 528 let medium = self.device.capabilities().medium;
380 529
@@ -403,14 +552,86 @@ impl<D: Driver + 'static> Inner<D> {
403 debug!(" DNS server {}: {}", i, s); 552 debug!(" DNS server {}: {}", i, s);
404 } 553 }
405 554
555 self.static_v4 = Some(config);
556
406 #[cfg(feature = "dns")] 557 #[cfg(feature = "dns")]
407 { 558 {
408 let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket); 559 self.update_dns_servers(s)
409 let servers: Vec<IpAddress, 3> = config.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)).collect();
410 socket.update_servers(&servers[..]);
411 } 560 }
561 }
412 562
413 self.config = Some(config) 563 /// Replaces the current IPv6 static configuration with a newly supplied config.
564 #[cfg(feature = "proto-ipv6")]
565 fn apply_config_v6(&mut self, s: &mut SocketStack, config: StaticConfigV6) {
566 #[cfg(feature = "medium-ethernet")]
567 let medium = self.device.capabilities().medium;
568
569 debug!("Acquired IPv6 configuration:");
570
571 debug!(" IP address: {}", config.address);
572 s.iface.update_ip_addrs(|addrs| {
573 if addrs.is_empty() {
574 addrs.push(IpCidr::Ipv6(config.address)).unwrap();
575 } else {
576 addrs[0] = IpCidr::Ipv6(config.address);
577 }
578 });
579
580 #[cfg(feature = "medium-ethernet")]
581 if Medium::Ethernet == medium {
582 if let Some(gateway) = config.gateway {
583 debug!(" Default gateway: {}", gateway);
584 s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap();
585 } else {
586 debug!(" Default gateway: None");
587 s.iface.routes_mut().remove_default_ipv6_route();
588 }
589 }
590 for (i, s) in config.dns_servers.iter().enumerate() {
591 debug!(" DNS server {}: {}", i, s);
592 }
593
594 self.static_v6 = Some(config);
595
596 #[cfg(feature = "dns")]
597 {
598 self.update_dns_servers(s)
599 }
600 }
601
602 #[cfg(feature = "dns")]
603 fn update_dns_servers(&mut self, s: &mut SocketStack) {
604 let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket);
605
606 let servers_v4;
607 #[cfg(feature = "proto-ipv4")]
608 {
609 servers_v4 = self
610 .static_v4
611 .iter()
612 .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)));
613 };
614 #[cfg(not(feature = "proto-ipv4"))]
615 {
616 servers_v4 = core::iter::empty();
617 }
618
619 let servers_v6;
620 #[cfg(feature = "proto-ipv6")]
621 {
622 servers_v6 = self
623 .static_v6
624 .iter()
625 .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv6(*c)));
626 }
627 #[cfg(not(feature = "proto-ipv6"))]
628 {
629 servers_v6 = core::iter::empty();
630 }
631
632 // Prefer the v6 DNS servers over the v4 servers
633 let servers: Vec<IpAddress, 6> = servers_v6.chain(servers_v4).collect();
634 socket.update_servers(&servers[..]);
414 } 635 }
415 636
416 #[cfg(feature = "dhcpv4")] 637 #[cfg(feature = "dhcpv4")]
@@ -430,9 +651,15 @@ impl<D: Driver + 'static> Inner<D> {
430 s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear()); 651 s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear());
431 #[cfg(feature = "medium-ethernet")] 652 #[cfg(feature = "medium-ethernet")]
432 if medium == Medium::Ethernet { 653 if medium == Medium::Ethernet {
433 s.iface.routes_mut().remove_default_ipv4_route(); 654 #[cfg(feature = "proto-ipv4")]
655 {
656 s.iface.routes_mut().remove_default_ipv4_route();
657 }
658 }
659 #[cfg(feature = "proto-ipv4")]
660 {
661 self.static_v4 = None
434 } 662 }
435 self.config = None
436 } 663 }
437 664
438 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { 665 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
@@ -470,12 +697,12 @@ impl<D: Driver + 'static> Inner<D> {
470 None => {} 697 None => {}
471 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), 698 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
472 Some(dhcpv4::Event::Configured(config)) => { 699 Some(dhcpv4::Event::Configured(config)) => {
473 let config = StaticConfig { 700 let config = StaticConfigV4 {
474 address: config.address, 701 address: config.address,
475 gateway: config.router, 702 gateway: config.router,
476 dns_servers: config.dns_servers, 703 dns_servers: config.dns_servers,
477 }; 704 };
478 self.apply_config(s, config) 705 self.apply_config_v4(s, config)
479 } 706 }
480 } 707 }
481 } else if old_link_up { 708 } else if old_link_up {
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 7babb5293..367675b13 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -278,10 +278,18 @@ impl<'a> TcpSocket<'a> {
278 self.io.with(|s, _| s.may_send()) 278 self.io.with(|s, _| s.may_send())
279 } 279 }
280 280
281 /// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer. 281 /// return whether the recieve half of the full-duplex connection is open.
282 /// This function returns true if it’s possible to receive data from the remote endpoint.
283 /// It will return true while there is data in the receive buffer, and if there isn’t,
284 /// as long as the remote endpoint has not closed the connection.
282 pub fn may_recv(&self) -> bool { 285 pub fn may_recv(&self) -> bool {
283 self.io.with(|s, _| s.may_recv()) 286 self.io.with(|s, _| s.may_recv())
284 } 287 }
288
289 /// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer.
290 pub fn can_recv(&self) -> bool {
291 self.io.with(|s, _| s.can_recv())
292 }
285} 293}
286 294
287impl<'a> Drop for TcpSocket<'a> { 295impl<'a> Drop for TcpSocket<'a> {
@@ -472,7 +480,10 @@ pub mod client {
472 Self: 'a, 480 Self: 'a,
473 { 481 {
474 let addr: crate::IpAddress = match remote.ip() { 482 let addr: crate::IpAddress = match remote.ip() {
483 #[cfg(feature = "proto-ipv4")]
475 IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())), 484 IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())),
485 #[cfg(not(feature = "proto-ipv4"))]
486 IpAddr::V4(_) => panic!("ipv4 support not enabled"),
476 #[cfg(feature = "proto-ipv6")] 487 #[cfg(feature = "proto-ipv6")]
477 IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())), 488 IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())),
478 #[cfg(not(feature = "proto-ipv6"))] 489 #[cfg(not(feature = "proto-ipv6"))]
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index c9843cfe8..36f8d06f2 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -104,7 +104,7 @@ impl<'a> UdpSocket<'a> {
104 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> { 104 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> {
105 poll_fn(move |cx| { 105 poll_fn(move |cx| {
106 self.with_mut(|s, _| match s.recv_slice(buf) { 106 self.with_mut(|s, _| match s.recv_slice(buf) {
107 Ok(x) => Poll::Ready(Ok(x)), 107 Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))),
108 // No data ready 108 // No data ready
109 Err(udp::RecvError::Exhausted) => { 109 Err(udp::RecvError::Exhausted) => {
110 s.register_recv_waker(cx.waker()); 110 s.register_recv_waker(cx.waker());
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 83900d4d0..3e858f854 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -16,7 +16,8 @@ flavors = [
16] 16]
17 17
18[features] 18[features]
19default = [ 19default = ["rt"]
20rt = [
20 "nrf52805-pac?/rt", 21 "nrf52805-pac?/rt",
21 "nrf52810-pac?/rt", 22 "nrf52810-pac?/rt",
22 "nrf52811-pac?/rt", 23 "nrf52811-pac?/rt",
@@ -31,7 +32,7 @@ default = [
31 32
32time = ["dep:embassy-time"] 33time = ["dep:embassy-time"]
33 34
34defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"] 35defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
35 36
36# Enable nightly-only features 37# Enable nightly-only features
37nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"] 38nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"]
@@ -90,11 +91,9 @@ _dppi = []
90_gpio-p1 = [] 91_gpio-p1 = []
91 92
92[dependencies] 93[dependencies]
93embassy-executor = { version = "0.2.0", path = "../embassy-executor", optional = true }
94embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } 94embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
95embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 95embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
96embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]} 96embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-3"] }
97embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
98embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 97embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
99embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } 98embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
100 99
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index b4fe2d874..9bc1c1e7a 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -15,7 +15,6 @@ use core::slice;
15use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; 15use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
16use core::task::Poll; 16use core::task::Poll;
17 17
18use embassy_cortex_m::interrupt::Interrupt;
19use embassy_hal_common::atomic_ring_buffer::RingBuffer; 18use embassy_hal_common::atomic_ring_buffer::RingBuffer;
20use embassy_hal_common::{into_ref, PeripheralRef}; 19use embassy_hal_common::{into_ref, PeripheralRef};
21use embassy_sync::waitqueue::AtomicWaker; 20use embassy_sync::waitqueue::AtomicWaker;
@@ -24,13 +23,13 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
24 23
25use crate::gpio::sealed::Pin; 24use crate::gpio::sealed::Pin;
26use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 25use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
27use crate::interrupt::{self}; 26use crate::interrupt::typelevel::Interrupt;
28use crate::ppi::{ 27use crate::ppi::{
29 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, 28 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
30}; 29};
31use crate::timer::{Instance as TimerInstance, Timer}; 30use crate::timer::{Instance as TimerInstance, Timer};
32use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; 31use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
33use crate::{pac, Peripheral}; 32use crate::{interrupt, pac, Peripheral};
34 33
35mod sealed { 34mod sealed {
36 use super::*; 35 use super::*;
@@ -77,7 +76,7 @@ pub struct InterruptHandler<U: UarteInstance> {
77 _phantom: PhantomData<U>, 76 _phantom: PhantomData<U>,
78} 77}
79 78
80impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> { 79impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for InterruptHandler<U> {
81 unsafe fn on_interrupt() { 80 unsafe fn on_interrupt() {
82 //trace!("irq: start"); 81 //trace!("irq: start");
83 let r = U::regs(); 82 let r = U::regs();
@@ -202,7 +201,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
202 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, 201 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
203 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, 202 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
204 ppi_group: impl Peripheral<P = impl Group> + 'd, 203 ppi_group: impl Peripheral<P = impl Group> + 'd,
205 _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, 204 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
206 rxd: impl Peripheral<P = impl GpioPin> + 'd, 205 rxd: impl Peripheral<P = impl GpioPin> + 'd,
207 txd: impl Peripheral<P = impl GpioPin> + 'd, 206 txd: impl Peripheral<P = impl GpioPin> + 'd,
208 config: Config, 207 config: Config,
@@ -237,7 +236,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
237 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, 236 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
238 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, 237 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
239 ppi_group: impl Peripheral<P = impl Group> + 'd, 238 ppi_group: impl Peripheral<P = impl Group> + 'd,
240 _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, 239 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
241 rxd: impl Peripheral<P = impl GpioPin> + 'd, 240 rxd: impl Peripheral<P = impl GpioPin> + 'd,
242 txd: impl Peripheral<P = impl GpioPin> + 'd, 241 txd: impl Peripheral<P = impl GpioPin> + 'd,
243 cts: impl Peripheral<P = impl GpioPin> + 'd, 242 cts: impl Peripheral<P = impl GpioPin> + 'd,
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index e406c081b..8776000c8 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -208,33 +208,29 @@ impl_ppi_channel!(PPI_CH31, 31 => static);
208impl_saadc_input!(P0_04, ANALOG_INPUT2); 208impl_saadc_input!(P0_04, ANALOG_INPUT2);
209impl_saadc_input!(P0_05, ANALOG_INPUT3); 209impl_saadc_input!(P0_05, ANALOG_INPUT3);
210 210
211pub mod irqs { 211embassy_hal_common::interrupt_mod!(
212 use embassy_cortex_m::interrupt::_export::declare; 212 POWER_CLOCK,
213 213 RADIO,
214 use crate::pac::Interrupt as InterruptEnum; 214 UARTE0_UART0,
215 215 TWIM0_TWIS0_TWI0,
216 declare!(POWER_CLOCK); 216 SPIM0_SPIS0_SPI0,
217 declare!(RADIO); 217 GPIOTE,
218 declare!(UARTE0_UART0); 218 SAADC,
219 declare!(TWIM0_TWIS0_TWI0); 219 TIMER0,
220 declare!(SPIM0_SPIS0_SPI0); 220 TIMER1,
221 declare!(GPIOTE); 221 TIMER2,
222 declare!(SAADC); 222 RTC0,
223 declare!(TIMER0); 223 TEMP,
224 declare!(TIMER1); 224 RNG,
225 declare!(TIMER2); 225 ECB,
226 declare!(RTC0); 226 CCM_AAR,
227 declare!(TEMP); 227 WDT,
228 declare!(RNG); 228 RTC1,
229 declare!(ECB); 229 QDEC,
230 declare!(CCM_AAR); 230 SWI0_EGU0,
231 declare!(WDT); 231 SWI1_EGU1,
232 declare!(RTC1); 232 SWI2,
233 declare!(QDEC); 233 SWI3,
234 declare!(SWI0_EGU0); 234 SWI4,
235 declare!(SWI1_EGU1); 235 SWI5,
236 declare!(SWI2); 236);
237 declare!(SWI3);
238 declare!(SWI4);
239 declare!(SWI5);
240}
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index 153795e54..5519e8953 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -234,36 +234,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
234impl_saadc_input!(P0_30, ANALOG_INPUT6); 234impl_saadc_input!(P0_30, ANALOG_INPUT6);
235impl_saadc_input!(P0_31, ANALOG_INPUT7); 235impl_saadc_input!(P0_31, ANALOG_INPUT7);
236 236
237pub mod irqs { 237embassy_hal_common::interrupt_mod!(
238 use embassy_cortex_m::interrupt::_export::declare; 238 POWER_CLOCK,
239 239 RADIO,
240 use crate::pac::Interrupt as InterruptEnum; 240 UARTE0_UART0,
241 241 TWIM0_TWIS0_TWI0,
242 declare!(POWER_CLOCK); 242 SPIM0_SPIS0_SPI0,
243 declare!(RADIO); 243 GPIOTE,
244 declare!(UARTE0_UART0); 244 SAADC,
245 declare!(TWIM0_TWIS0_TWI0); 245 TIMER0,
246 declare!(SPIM0_SPIS0_SPI0); 246 TIMER1,
247 declare!(GPIOTE); 247 TIMER2,
248 declare!(SAADC); 248 RTC0,
249 declare!(TIMER0); 249 TEMP,
250 declare!(TIMER1); 250 RNG,
251 declare!(TIMER2); 251 ECB,
252 declare!(RTC0); 252 CCM_AAR,
253 declare!(TEMP); 253 WDT,
254 declare!(RNG); 254 RTC1,
255 declare!(ECB); 255 QDEC,
256 declare!(CCM_AAR); 256 COMP,
257 declare!(WDT); 257 SWI0_EGU0,
258 declare!(RTC1); 258 SWI1_EGU1,
259 declare!(QDEC); 259 SWI2,
260 declare!(COMP); 260 SWI3,
261 declare!(SWI0_EGU0); 261 SWI4,
262 declare!(SWI1_EGU1); 262 SWI5,
263 declare!(SWI2); 263 PWM0,
264 declare!(SWI3); 264 PDM,
265 declare!(SWI4); 265);
266 declare!(SWI5);
267 declare!(PWM0);
268 declare!(PDM);
269}
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index a7a7cf58c..d5367c59a 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -236,36 +236,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
236impl_saadc_input!(P0_30, ANALOG_INPUT6); 236impl_saadc_input!(P0_30, ANALOG_INPUT6);
237impl_saadc_input!(P0_31, ANALOG_INPUT7); 237impl_saadc_input!(P0_31, ANALOG_INPUT7);
238 238
239pub mod irqs { 239embassy_hal_common::interrupt_mod!(
240 use embassy_cortex_m::interrupt::_export::declare; 240 POWER_CLOCK,
241 241 RADIO,
242 use crate::pac::Interrupt as InterruptEnum; 242 UARTE0_UART0,
243 243 TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0,
244 declare!(POWER_CLOCK); 244 SPIM1_SPIS1_SPI1,
245 declare!(RADIO); 245 GPIOTE,
246 declare!(UARTE0_UART0); 246 SAADC,
247 declare!(TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 247 TIMER0,
248 declare!(SPIM1_SPIS1_SPI1); 248 TIMER1,
249 declare!(GPIOTE); 249 TIMER2,
250 declare!(SAADC); 250 RTC0,
251 declare!(TIMER0); 251 TEMP,
252 declare!(TIMER1); 252 RNG,
253 declare!(TIMER2); 253 ECB,
254 declare!(RTC0); 254 CCM_AAR,
255 declare!(TEMP); 255 WDT,
256 declare!(RNG); 256 RTC1,
257 declare!(ECB); 257 QDEC,
258 declare!(CCM_AAR); 258 COMP,
259 declare!(WDT); 259 SWI0_EGU0,
260 declare!(RTC1); 260 SWI1_EGU1,
261 declare!(QDEC); 261 SWI2,
262 declare!(COMP); 262 SWI3,
263 declare!(SWI0_EGU0); 263 SWI4,
264 declare!(SWI1_EGU1); 264 SWI5,
265 declare!(SWI2); 265 PWM0,
266 declare!(SWI3); 266 PDM,
267 declare!(SWI4); 267);
268 declare!(SWI5);
269 declare!(PWM0);
270 declare!(PDM);
271}
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index 14a1b8cc9..785170447 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -224,35 +224,31 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
224impl_ppi_channel!(PPI_CH30, 30 => static); 224impl_ppi_channel!(PPI_CH30, 30 => static);
225impl_ppi_channel!(PPI_CH31, 31 => static); 225impl_ppi_channel!(PPI_CH31, 31 => static);
226 226
227pub mod irqs { 227embassy_hal_common::interrupt_mod!(
228 use embassy_cortex_m::interrupt::_export::declare; 228 POWER_CLOCK,
229 229 RADIO,
230 use crate::pac::Interrupt as InterruptEnum; 230 UARTE0_UART0,
231 231 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
232 declare!(POWER_CLOCK); 232 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
233 declare!(RADIO); 233 GPIOTE,
234 declare!(UARTE0_UART0); 234 TIMER0,
235 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 235 TIMER1,
236 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 236 TIMER2,
237 declare!(GPIOTE); 237 RTC0,
238 declare!(TIMER0); 238 TEMP,
239 declare!(TIMER1); 239 RNG,
240 declare!(TIMER2); 240 ECB,
241 declare!(RTC0); 241 CCM_AAR,
242 declare!(TEMP); 242 WDT,
243 declare!(RNG); 243 RTC1,
244 declare!(ECB); 244 QDEC,
245 declare!(CCM_AAR); 245 COMP,
246 declare!(WDT); 246 SWI0_EGU0,
247 declare!(RTC1); 247 SWI1_EGU1,
248 declare!(QDEC); 248 SWI2_EGU2,
249 declare!(COMP); 249 SWI3_EGU3,
250 declare!(SWI0_EGU0); 250 SWI4_EGU4,
251 declare!(SWI1_EGU1); 251 SWI5_EGU5,
252 declare!(SWI2_EGU2); 252 TIMER3,
253 declare!(SWI3_EGU3); 253 USBD,
254 declare!(SWI4_EGU4); 254);
255 declare!(SWI5_EGU5);
256 declare!(TIMER3);
257 declare!(USBD);
258}
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index 83ecd0deb..b77564a5c 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -263,46 +263,42 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
263 263
264impl_i2s!(I2S, I2S, I2S); 264impl_i2s!(I2S, I2S, I2S);
265 265
266pub mod irqs { 266embassy_hal_common::interrupt_mod!(
267 use embassy_cortex_m::interrupt::_export::declare; 267 POWER_CLOCK,
268 268 RADIO,
269 use crate::pac::Interrupt as InterruptEnum; 269 UARTE0_UART0,
270 270 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
271 declare!(POWER_CLOCK); 271 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
272 declare!(RADIO); 272 NFCT,
273 declare!(UARTE0_UART0); 273 GPIOTE,
274 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 274 SAADC,
275 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 275 TIMER0,
276 declare!(NFCT); 276 TIMER1,
277 declare!(GPIOTE); 277 TIMER2,
278 declare!(SAADC); 278 RTC0,
279 declare!(TIMER0); 279 TEMP,
280 declare!(TIMER1); 280 RNG,
281 declare!(TIMER2); 281 ECB,
282 declare!(RTC0); 282 CCM_AAR,
283 declare!(TEMP); 283 WDT,
284 declare!(RNG); 284 RTC1,
285 declare!(ECB); 285 QDEC,
286 declare!(CCM_AAR); 286 COMP_LPCOMP,
287 declare!(WDT); 287 SWI0_EGU0,
288 declare!(RTC1); 288 SWI1_EGU1,
289 declare!(QDEC); 289 SWI2_EGU2,
290 declare!(COMP_LPCOMP); 290 SWI3_EGU3,
291 declare!(SWI0_EGU0); 291 SWI4_EGU4,
292 declare!(SWI1_EGU1); 292 SWI5_EGU5,
293 declare!(SWI2_EGU2); 293 TIMER3,
294 declare!(SWI3_EGU3); 294 TIMER4,
295 declare!(SWI4_EGU4); 295 PWM0,
296 declare!(SWI5_EGU5); 296 PDM,
297 declare!(TIMER3); 297 MWU,
298 declare!(TIMER4); 298 PWM1,
299 declare!(PWM0); 299 PWM2,
300 declare!(PDM); 300 SPIM2_SPIS2_SPI2,
301 declare!(MWU); 301 RTC2,
302 declare!(PWM1); 302 FPU,
303 declare!(PWM2); 303 I2S,
304 declare!(SPIM2_SPIS2_SPI2); 304);
305 declare!(RTC2);
306 declare!(FPU);
307 declare!(I2S);
308}
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 5e5db04de..bff7f4ebb 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -306,50 +306,46 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
306 306
307impl_i2s!(I2S, I2S, I2S); 307impl_i2s!(I2S, I2S, I2S);
308 308
309pub mod irqs { 309embassy_hal_common::interrupt_mod!(
310 use embassy_cortex_m::interrupt::_export::declare; 310 POWER_CLOCK,
311 311 RADIO,
312 use crate::pac::Interrupt as InterruptEnum; 312 UARTE0_UART0,
313 313 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
314 declare!(POWER_CLOCK); 314 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
315 declare!(RADIO); 315 NFCT,
316 declare!(UARTE0_UART0); 316 GPIOTE,
317 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 317 SAADC,
318 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 318 TIMER0,
319 declare!(NFCT); 319 TIMER1,
320 declare!(GPIOTE); 320 TIMER2,
321 declare!(SAADC); 321 RTC0,
322 declare!(TIMER0); 322 TEMP,
323 declare!(TIMER1); 323 RNG,
324 declare!(TIMER2); 324 ECB,
325 declare!(RTC0); 325 CCM_AAR,
326 declare!(TEMP); 326 WDT,
327 declare!(RNG); 327 RTC1,
328 declare!(ECB); 328 QDEC,
329 declare!(CCM_AAR); 329 COMP_LPCOMP,
330 declare!(WDT); 330 SWI0_EGU0,
331 declare!(RTC1); 331 SWI1_EGU1,
332 declare!(QDEC); 332 SWI2_EGU2,
333 declare!(COMP_LPCOMP); 333 SWI3_EGU3,
334 declare!(SWI0_EGU0); 334 SWI4_EGU4,
335 declare!(SWI1_EGU1); 335 SWI5_EGU5,
336 declare!(SWI2_EGU2); 336 TIMER3,
337 declare!(SWI3_EGU3); 337 TIMER4,
338 declare!(SWI4_EGU4); 338 PWM0,
339 declare!(SWI5_EGU5); 339 PDM,
340 declare!(TIMER3); 340 MWU,
341 declare!(TIMER4); 341 PWM1,
342 declare!(PWM0); 342 PWM2,
343 declare!(PDM); 343 SPIM2_SPIS2_SPI2,
344 declare!(MWU); 344 RTC2,
345 declare!(PWM1); 345 FPU,
346 declare!(PWM2); 346 USBD,
347 declare!(SPIM2_SPIS2_SPI2); 347 UARTE1,
348 declare!(RTC2); 348 PWM3,
349 declare!(FPU); 349 SPIM3,
350 declare!(USBD); 350 I2S,
351 declare!(UARTE1); 351);
352 declare!(PWM3);
353 declare!(SPIM3);
354 declare!(I2S);
355}
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index f6d33f85c..9b0050823 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -311,52 +311,48 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
311 311
312impl_i2s!(I2S, I2S, I2S); 312impl_i2s!(I2S, I2S, I2S);
313 313
314pub mod irqs { 314embassy_hal_common::interrupt_mod!(
315 use embassy_cortex_m::interrupt::_export::declare; 315 POWER_CLOCK,
316 316 RADIO,
317 use crate::pac::Interrupt as InterruptEnum; 317 UARTE0_UART0,
318 318 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
319 declare!(POWER_CLOCK); 319 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
320 declare!(RADIO); 320 NFCT,
321 declare!(UARTE0_UART0); 321 GPIOTE,
322 declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 322 SAADC,
323 declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 323 TIMER0,
324 declare!(NFCT); 324 TIMER1,
325 declare!(GPIOTE); 325 TIMER2,
326 declare!(SAADC); 326 RTC0,
327 declare!(TIMER0); 327 TEMP,
328 declare!(TIMER1); 328 RNG,
329 declare!(TIMER2); 329 ECB,
330 declare!(RTC0); 330 CCM_AAR,
331 declare!(TEMP); 331 WDT,
332 declare!(RNG); 332 RTC1,
333 declare!(ECB); 333 QDEC,
334 declare!(CCM_AAR); 334 COMP_LPCOMP,
335 declare!(WDT); 335 SWI0_EGU0,
336 declare!(RTC1); 336 SWI1_EGU1,
337 declare!(QDEC); 337 SWI2_EGU2,
338 declare!(COMP_LPCOMP); 338 SWI3_EGU3,
339 declare!(SWI0_EGU0); 339 SWI4_EGU4,
340 declare!(SWI1_EGU1); 340 SWI5_EGU5,
341 declare!(SWI2_EGU2); 341 TIMER3,
342 declare!(SWI3_EGU3); 342 TIMER4,
343 declare!(SWI4_EGU4); 343 PWM0,
344 declare!(SWI5_EGU5); 344 PDM,
345 declare!(TIMER3); 345 MWU,
346 declare!(TIMER4); 346 PWM1,
347 declare!(PWM0); 347 PWM2,
348 declare!(PDM); 348 SPIM2_SPIS2_SPI2,
349 declare!(MWU); 349 RTC2,
350 declare!(PWM1); 350 FPU,
351 declare!(PWM2); 351 USBD,
352 declare!(SPIM2_SPIS2_SPI2); 352 UARTE1,
353 declare!(RTC2); 353 QSPI,
354 declare!(FPU); 354 CRYPTOCELL,
355 declare!(USBD); 355 PWM3,
356 declare!(UARTE1); 356 SPIM3,
357 declare!(QSPI); 357 I2S,
358 declare!(CRYPTOCELL); 358);
359 declare!(PWM3);
360 declare!(SPIM3);
361 declare!(I2S);
362}
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 34f96800f..410ae921c 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -5,6 +5,8 @@ pub mod pac {
5 // The nRF5340 has a secure and non-secure (NS) mode. 5 // The nRF5340 has a secure and non-secure (NS) mode.
6 // To avoid cfg spam, we remove _ns or _s suffixes here. 6 // To avoid cfg spam, we remove _ns or _s suffixes here.
7 7
8 pub use nrf5340_app_pac::NVIC_PRIO_BITS;
9
8 #[doc(no_inline)] 10 #[doc(no_inline)]
9 pub use nrf5340_app_pac::{ 11 pub use nrf5340_app_pac::{
10 interrupt, 12 interrupt,
@@ -504,50 +506,46 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5);
504impl_saadc_input!(P0_19, ANALOG_INPUT6); 506impl_saadc_input!(P0_19, ANALOG_INPUT6);
505impl_saadc_input!(P0_20, ANALOG_INPUT7); 507impl_saadc_input!(P0_20, ANALOG_INPUT7);
506 508
507pub mod irqs { 509embassy_hal_common::interrupt_mod!(
508 use embassy_cortex_m::interrupt::_export::declare; 510 FPU,
509 511 CACHE,
510 use crate::pac::Interrupt as InterruptEnum; 512 SPU,
511 513 CLOCK_POWER,
512 declare!(FPU); 514 SERIAL0,
513 declare!(CACHE); 515 SERIAL1,
514 declare!(SPU); 516 SPIM4,
515 declare!(CLOCK_POWER); 517 SERIAL2,
516 declare!(SERIAL0); 518 SERIAL3,
517 declare!(SERIAL1); 519 GPIOTE0,
518 declare!(SPIM4); 520 SAADC,
519 declare!(SERIAL2); 521 TIMER0,
520 declare!(SERIAL3); 522 TIMER1,
521 declare!(GPIOTE0); 523 TIMER2,
522 declare!(SAADC); 524 RTC0,
523 declare!(TIMER0); 525 RTC1,
524 declare!(TIMER1); 526 WDT0,
525 declare!(TIMER2); 527 WDT1,
526 declare!(RTC0); 528 COMP_LPCOMP,
527 declare!(RTC1); 529 EGU0,
528 declare!(WDT0); 530 EGU1,
529 declare!(WDT1); 531 EGU2,
530 declare!(COMP_LPCOMP); 532 EGU3,
531 declare!(EGU0); 533 EGU4,
532 declare!(EGU1); 534 EGU5,
533 declare!(EGU2); 535 PWM0,
534 declare!(EGU3); 536 PWM1,
535 declare!(EGU4); 537 PWM2,
536 declare!(EGU5); 538 PWM3,
537 declare!(PWM0); 539 PDM0,
538 declare!(PWM1); 540 I2S0,
539 declare!(PWM2); 541 IPC,
540 declare!(PWM3); 542 QSPI,
541 declare!(PDM0); 543 NFCT,
542 declare!(I2S0); 544 GPIOTE1,
543 declare!(IPC); 545 QDEC0,
544 declare!(QSPI); 546 QDEC1,
545 declare!(NFCT); 547 USBD,
546 declare!(GPIOTE1); 548 USBREGULATOR,
547 declare!(QDEC0); 549 KMU,
548 declare!(QDEC1); 550 CRYPTOCELL,
549 declare!(USBD); 551);
550 declare!(USBREGULATOR);
551 declare!(KMU);
552 declare!(CRYPTOCELL);
553}
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index 1e59528cb..6ac783085 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -5,6 +5,8 @@ pub mod pac {
5 // The nRF5340 has a secure and non-secure (NS) mode. 5 // The nRF5340 has a secure and non-secure (NS) mode.
6 // To avoid cfg spam, we remove _ns or _s suffixes here. 6 // To avoid cfg spam, we remove _ns or _s suffixes here.
7 7
8 pub use nrf5340_net_pac::NVIC_PRIO_BITS;
9
8 #[doc(no_inline)] 10 #[doc(no_inline)]
9 pub use nrf5340_net_pac::{ 11 pub use nrf5340_net_pac::{
10 interrupt, 12 interrupt,
@@ -340,29 +342,25 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable);
340impl_ppi_channel!(PPI_CH30, 30 => configurable); 342impl_ppi_channel!(PPI_CH30, 30 => configurable);
341impl_ppi_channel!(PPI_CH31, 31 => configurable); 343impl_ppi_channel!(PPI_CH31, 31 => configurable);
342 344
343pub mod irqs { 345embassy_hal_common::interrupt_mod!(
344 use embassy_cortex_m::interrupt::_export::declare; 346 CLOCK_POWER,
345 347 RADIO,
346 use crate::pac::Interrupt as InterruptEnum; 348 RNG,
347 349 GPIOTE,
348 declare!(CLOCK_POWER); 350 WDT,
349 declare!(RADIO); 351 TIMER0,
350 declare!(RNG); 352 ECB,
351 declare!(GPIOTE); 353 AAR_CCM,
352 declare!(WDT); 354 TEMP,
353 declare!(TIMER0); 355 RTC0,
354 declare!(ECB); 356 IPC,
355 declare!(AAR_CCM); 357 SERIAL0,
356 declare!(TEMP); 358 EGU0,
357 declare!(RTC0); 359 RTC1,
358 declare!(IPC); 360 TIMER1,
359 declare!(SERIAL0); 361 TIMER2,
360 declare!(EGU0); 362 SWI0,
361 declare!(RTC1); 363 SWI1,
362 declare!(TIMER1); 364 SWI2,
363 declare!(TIMER2); 365 SWI3,
364 declare!(SWI0); 366);
365 declare!(SWI1);
366 declare!(SWI2);
367 declare!(SWI3);
368}
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index d2b45114f..67ea032ff 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -5,6 +5,8 @@ pub mod pac {
5 // The nRF9160 has a secure and non-secure (NS) mode. 5 // The nRF9160 has a secure and non-secure (NS) mode.
6 // To avoid cfg spam, we remove _ns or _s suffixes here. 6 // To avoid cfg spam, we remove _ns or _s suffixes here.
7 7
8 pub use nrf9160_pac::NVIC_PRIO_BITS;
9
8 #[doc(no_inline)] 10 #[doc(no_inline)]
9 pub use nrf9160_pac::{ 11 pub use nrf9160_pac::{
10 interrupt, 12 interrupt,
@@ -366,40 +368,36 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5);
366impl_saadc_input!(P0_19, ANALOG_INPUT6); 368impl_saadc_input!(P0_19, ANALOG_INPUT6);
367impl_saadc_input!(P0_20, ANALOG_INPUT7); 369impl_saadc_input!(P0_20, ANALOG_INPUT7);
368 370
369pub mod irqs { 371embassy_hal_common::interrupt_mod!(
370 use embassy_cortex_m::interrupt::_export::declare; 372 SPU,
371 373 CLOCK_POWER,
372 use crate::pac::Interrupt as InterruptEnum; 374 UARTE0_SPIM0_SPIS0_TWIM0_TWIS0,
373 375 UARTE1_SPIM1_SPIS1_TWIM1_TWIS1,
374 declare!(SPU); 376 UARTE2_SPIM2_SPIS2_TWIM2_TWIS2,
375 declare!(CLOCK_POWER); 377 UARTE3_SPIM3_SPIS3_TWIM3_TWIS3,
376 declare!(UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); 378 GPIOTE0,
377 declare!(UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); 379 SAADC,
378 declare!(UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); 380 TIMER0,
379 declare!(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); 381 TIMER1,
380 declare!(GPIOTE0); 382 TIMER2,
381 declare!(SAADC); 383 RTC0,
382 declare!(TIMER0); 384 RTC1,
383 declare!(TIMER1); 385 WDT,
384 declare!(TIMER2); 386 EGU0,
385 declare!(RTC0); 387 EGU1,
386 declare!(RTC1); 388 EGU2,
387 declare!(WDT); 389 EGU3,
388 declare!(EGU0); 390 EGU4,
389 declare!(EGU1); 391 EGU5,
390 declare!(EGU2); 392 PWM0,
391 declare!(EGU3); 393 PWM1,
392 declare!(EGU4); 394 PWM2,
393 declare!(EGU5); 395 PDM,
394 declare!(PWM0); 396 PWM3,
395 declare!(PWM1); 397 I2S,
396 declare!(PWM2); 398 IPC,
397 declare!(PDM); 399 FPU,
398 declare!(PWM3); 400 GPIOTE1,
399 declare!(I2S); 401 KMU,
400 declare!(IPC); 402 CRYPTOCELL,
401 declare!(FPU); 403);
402 declare!(GPIOTE1);
403 declare!(KMU);
404 declare!(CRYPTOCELL);
405}
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 2ec5220a7..21d0d9564 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
9 9
10use crate::gpio::sealed::Pin as _; 10use crate::gpio::sealed::Pin as _;
11use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; 11use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin};
12use crate::interrupt::Interrupt; 12use crate::interrupt::InterruptExt;
13use crate::ppi::{Event, Task}; 13use crate::ppi::{Event, Task};
14use crate::{interrupt, pac, peripherals}; 14use crate::{interrupt, pac, peripherals};
15 15
@@ -75,15 +75,15 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
75 75
76 // Enable interrupts 76 // Enable interrupts
77 #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] 77 #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
78 type Irq = interrupt::GPIOTE0; 78 let irq = interrupt::GPIOTE0;
79 #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] 79 #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
80 type Irq = interrupt::GPIOTE1; 80 let irq = interrupt::GPIOTE1;
81 #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] 81 #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))]
82 type Irq = interrupt::GPIOTE; 82 let irq = interrupt::GPIOTE;
83 83
84 Irq::unpend(); 84 irq.unpend();
85 Irq::set_priority(irq_prio); 85 irq.set_priority(irq_prio);
86 unsafe { Irq::enable() }; 86 unsafe { irq.enable() };
87 87
88 let g = regs(); 88 let g = regs();
89 g.events_port.write(|w| w); 89 g.events_port.write(|w| w);
@@ -91,18 +91,21 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
91} 91}
92 92
93#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] 93#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
94#[cfg(feature = "rt")]
94#[interrupt] 95#[interrupt]
95fn GPIOTE0() { 96fn GPIOTE0() {
96 unsafe { handle_gpiote_interrupt() }; 97 unsafe { handle_gpiote_interrupt() };
97} 98}
98 99
99#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] 100#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
101#[cfg(feature = "rt")]
100#[interrupt] 102#[interrupt]
101fn GPIOTE1() { 103fn GPIOTE1() {
102 unsafe { handle_gpiote_interrupt() }; 104 unsafe { handle_gpiote_interrupt() };
103} 105}
104 106
105#[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] 107#[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))]
108#[cfg(feature = "rt")]
106#[interrupt] 109#[interrupt]
107fn GPIOTE() { 110fn GPIOTE() {
108 unsafe { handle_gpiote_interrupt() }; 111 unsafe { handle_gpiote_interrupt() };
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index 13db77d3b..fea38c4c0 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -13,10 +13,10 @@ use embassy_hal_common::drop::OnDrop;
13use embassy_hal_common::{into_ref, PeripheralRef}; 13use embassy_hal_common::{into_ref, PeripheralRef};
14 14
15use crate::gpio::{AnyPin, Pin as GpioPin}; 15use crate::gpio::{AnyPin, Pin as GpioPin};
16use crate::interrupt::{self, Interrupt}; 16use crate::interrupt::typelevel::Interrupt;
17use crate::pac::i2s::RegisterBlock; 17use crate::pac::i2s::RegisterBlock;
18use crate::util::{slice_in_ram_or, slice_ptr_parts}; 18use crate::util::{slice_in_ram_or, slice_ptr_parts};
19use crate::{Peripheral, EASY_DMA_SIZE}; 19use crate::{interrupt, Peripheral, EASY_DMA_SIZE};
20 20
21/// Type alias for `MultiBuffering` with 2 buffers. 21/// Type alias for `MultiBuffering` with 2 buffers.
22pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>; 22pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
@@ -367,7 +367,7 @@ pub struct InterruptHandler<T: Instance> {
367 _phantom: PhantomData<T>, 367 _phantom: PhantomData<T>,
368} 368}
369 369
370impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 370impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
371 unsafe fn on_interrupt() { 371 unsafe fn on_interrupt() {
372 let device = Device::<T>::new(); 372 let device = Device::<T>::new();
373 let s = T::state(); 373 let s = T::state();
@@ -408,7 +408,7 @@ impl<'d, T: Instance> I2S<'d, T> {
408 /// Create a new I2S in master mode 408 /// Create a new I2S in master mode
409 pub fn new_master( 409 pub fn new_master(
410 i2s: impl Peripheral<P = T> + 'd, 410 i2s: impl Peripheral<P = T> + 'd,
411 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 411 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
412 mck: impl Peripheral<P = impl GpioPin> + 'd, 412 mck: impl Peripheral<P = impl GpioPin> + 'd,
413 sck: impl Peripheral<P = impl GpioPin> + 'd, 413 sck: impl Peripheral<P = impl GpioPin> + 'd,
414 lrck: impl Peripheral<P = impl GpioPin> + 'd, 414 lrck: impl Peripheral<P = impl GpioPin> + 'd,
@@ -431,7 +431,7 @@ impl<'d, T: Instance> I2S<'d, T> {
431 /// Create a new I2S in slave mode 431 /// Create a new I2S in slave mode
432 pub fn new_slave( 432 pub fn new_slave(
433 i2s: impl Peripheral<P = T> + 'd, 433 i2s: impl Peripheral<P = T> + 'd,
434 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 434 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
435 sck: impl Peripheral<P = impl GpioPin> + 'd, 435 sck: impl Peripheral<P = impl GpioPin> + 'd,
436 lrck: impl Peripheral<P = impl GpioPin> + 'd, 436 lrck: impl Peripheral<P = impl GpioPin> + 'd,
437 config: Config, 437 config: Config,
@@ -1173,7 +1173,7 @@ pub(crate) mod sealed {
1173/// I2S peripheral instance. 1173/// I2S peripheral instance.
1174pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 1174pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
1175 /// Interrupt for this peripheral. 1175 /// Interrupt for this peripheral.
1176 type Interrupt: Interrupt; 1176 type Interrupt: interrupt::typelevel::Interrupt;
1177} 1177}
1178 1178
1179macro_rules! impl_i2s { 1179macro_rules! impl_i2s {
@@ -1188,7 +1188,7 @@ macro_rules! impl_i2s {
1188 } 1188 }
1189 } 1189 }
1190 impl crate::i2s::Instance for peripherals::$type { 1190 impl crate::i2s::Instance for peripherals::$type {
1191 type Interrupt = crate::interrupt::$irq; 1191 type Interrupt = crate::interrupt::typelevel::$irq;
1192 } 1192 }
1193 }; 1193 };
1194} 1194}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 6b57c2545..d23759f9d 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -93,21 +93,14 @@ pub mod wdt;
93#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] 93#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
94mod chip; 94mod chip;
95 95
96pub mod interrupt { 96/// Macro to bind interrupts to handlers.
97 //! Interrupt definitions and macros to bind them. 97///
98 pub use cortex_m::interrupt::{CriticalSection, Mutex}; 98/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
99 pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, Priority}; 99/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
100 100/// prove at compile-time that the right interrupts have been bound.
101 pub use crate::chip::irqs::*; 101// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
102 102#[macro_export]
103 /// Macro to bind interrupts to handlers. 103macro_rules! bind_interrupts {
104 ///
105 /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
106 /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
107 /// prove at compile-time that the right interrupts have been bound.
108 // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
109 #[macro_export]
110 macro_rules! bind_interrupts {
111 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 104 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
112 $vis struct $name; 105 $vis struct $name;
113 106
@@ -116,17 +109,16 @@ pub mod interrupt {
116 #[no_mangle] 109 #[no_mangle]
117 unsafe extern "C" fn $irq() { 110 unsafe extern "C" fn $irq() {
118 $( 111 $(
119 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); 112 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
120 )* 113 )*
121 } 114 }
122 115
123 $( 116 $(
124 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} 117 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
125 )* 118 )*
126 )* 119 )*
127 }; 120 };
128 } 121 }
129}
130 122
131// Reexports 123// Reexports
132 124
@@ -135,10 +127,11 @@ pub use chip::pac;
135#[cfg(not(feature = "unstable-pac"))] 127#[cfg(not(feature = "unstable-pac"))]
136pub(crate) use chip::pac; 128pub(crate) use chip::pac;
137pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; 129pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
138pub use embassy_cortex_m::executor;
139pub use embassy_cortex_m::interrupt::_export::interrupt;
140pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 130pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
141 131
132pub use crate::chip::interrupt;
133pub use crate::pac::NVIC_PRIO_BITS;
134
142pub mod config { 135pub mod config {
143 //! Configuration options used when initializing the HAL. 136 //! Configuration options used when initializing the HAL.
144 137
@@ -417,13 +410,13 @@ pub fn init(config: config::Config) -> Peripherals {
417 warn!( 410 warn!(
418 "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\ 411 "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\
419 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ 412 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
420 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." 413 To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
421 ); 414 );
422 #[cfg(feature = "reset-pin-as-gpio")] 415 #[cfg(feature = "reset-pin-as-gpio")]
423 warn!( 416 warn!(
424 "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\ 417 "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\
425 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ 418 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
426 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." 419 To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
427 ); 420 );
428 } 421 }
429 } 422 }
@@ -439,7 +432,7 @@ pub fn init(config: config::Config) -> Peripherals {
439 warn!( 432 warn!(
440 "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\ 433 "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\
441 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ 434 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
442 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." 435 To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
443 ); 436 );
444 } 437 }
445 } 438 }
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index 9df685a26..0e30f7002 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -6,7 +6,6 @@ use core::marker::PhantomData;
6use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_cortex_m::interrupt::Interrupt;
10use embassy_hal_common::drop::OnDrop; 9use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::{into_ref, PeripheralRef}; 10use embassy_hal_common::{into_ref, PeripheralRef};
12use futures::future::poll_fn; 11use futures::future::poll_fn;
@@ -14,15 +13,15 @@ use futures::future::poll_fn;
14use crate::chip::EASY_DMA_SIZE; 13use crate::chip::EASY_DMA_SIZE;
15use crate::gpio::sealed::Pin; 14use crate::gpio::sealed::Pin;
16use crate::gpio::{AnyPin, Pin as GpioPin}; 15use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::interrupt::{self}; 16use crate::interrupt::typelevel::Interrupt;
18use crate::Peripheral; 17use crate::{interrupt, Peripheral};
19 18
20/// Interrupt handler. 19/// Interrupt handler.
21pub struct InterruptHandler<T: Instance> { 20pub struct InterruptHandler<T: Instance> {
22 _phantom: PhantomData<T>, 21 _phantom: PhantomData<T>,
23} 22}
24 23
25impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 24impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
26 unsafe fn on_interrupt() { 25 unsafe fn on_interrupt() {
27 T::regs().intenclr.write(|w| w.end().clear()); 26 T::regs().intenclr.write(|w| w.end().clear());
28 T::state().waker.wake(); 27 T::state().waker.wake();
@@ -53,7 +52,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
53 /// Create PDM driver 52 /// Create PDM driver
54 pub fn new( 53 pub fn new(
55 pdm: impl Peripheral<P = T> + 'd, 54 pdm: impl Peripheral<P = T> + 'd,
56 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 55 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
57 clk: impl Peripheral<P = impl GpioPin> + 'd, 56 clk: impl Peripheral<P = impl GpioPin> + 'd,
58 din: impl Peripheral<P = impl GpioPin> + 'd, 57 din: impl Peripheral<P = impl GpioPin> + 'd,
59 config: Config, 58 config: Config,
@@ -274,7 +273,7 @@ pub(crate) mod sealed {
274/// PDM peripheral instance. 273/// PDM peripheral instance.
275pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 274pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
276 /// Interrupt for this peripheral. 275 /// Interrupt for this peripheral.
277 type Interrupt: Interrupt; 276 type Interrupt: interrupt::typelevel::Interrupt;
278} 277}
279 278
280macro_rules! impl_pdm { 279macro_rules! impl_pdm {
@@ -289,7 +288,7 @@ macro_rules! impl_pdm {
289 } 288 }
290 } 289 }
291 impl crate::pdm::Instance for peripherals::$type { 290 impl crate::pdm::Instance for peripherals::$type {
292 type Interrupt = crate::interrupt::$irq; 291 type Interrupt = crate::interrupt::typelevel::$irq;
293 } 292 }
294 }; 293 };
295} 294}
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 7c18da6ee..76757a248 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -137,6 +137,11 @@ impl Task {
137 Self(ptr) 137 Self(ptr)
138 } 138 }
139 139
140 /// Triggers this task.
141 pub fn trigger(&mut self) {
142 unsafe { self.0.as_ptr().write_volatile(1) };
143 }
144
140 pub(crate) fn from_reg<T>(reg: &T) -> Self { 145 pub(crate) fn from_reg<T>(reg: &T) -> Self {
141 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) 146 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
142 } 147 }
@@ -173,6 +178,16 @@ impl Event {
173 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) 178 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
174 } 179 }
175 180
181 /// Describes whether this Event is currently in a triggered state.
182 pub fn is_triggered(&self) -> bool {
183 unsafe { self.0.as_ptr().read_volatile() == 1 }
184 }
185
186 /// Clear the current register's triggered state, reverting it to 0.
187 pub fn clear(&mut self) {
188 unsafe { self.0.as_ptr().write_volatile(0) };
189 }
190
176 /// Address of publish register for this event. 191 /// Address of publish register for this event.
177 #[cfg(feature = "_dppi")] 192 #[cfg(feature = "_dppi")]
178 pub fn publish_reg(&self) -> *mut u32 { 193 pub fn publish_reg(&self) -> *mut u32 {
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 708f23104..363a255d5 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -8,10 +8,9 @@ use embassy_hal_common::{into_ref, PeripheralRef};
8 8
9use crate::gpio::sealed::Pin as _; 9use crate::gpio::sealed::Pin as _;
10use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; 10use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
11use crate::interrupt::Interrupt;
12use crate::ppi::{Event, Task}; 11use crate::ppi::{Event, Task};
13use crate::util::slice_in_ram_or; 12use crate::util::slice_in_ram_or;
14use crate::{pac, Peripheral}; 13use crate::{interrupt, pac, Peripheral};
15 14
16/// SimplePwm is the traditional pwm interface you're probably used to, allowing 15/// SimplePwm is the traditional pwm interface you're probably used to, allowing
17/// to simply set a duty cycle across up to four channels. 16/// to simply set a duty cycle across up to four channels.
@@ -843,7 +842,7 @@ pub(crate) mod sealed {
843/// PWM peripheral instance. 842/// PWM peripheral instance.
844pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 843pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
845 /// Interrupt for this peripheral. 844 /// Interrupt for this peripheral.
846 type Interrupt: Interrupt; 845 type Interrupt: interrupt::typelevel::Interrupt;
847} 846}
848 847
849macro_rules! impl_pwm { 848macro_rules! impl_pwm {
@@ -854,7 +853,7 @@ macro_rules! impl_pwm {
854 } 853 }
855 } 854 }
856 impl crate::pwm::Instance for peripherals::$type { 855 impl crate::pwm::Instance for peripherals::$type {
857 type Interrupt = crate::interrupt::$irq; 856 type Interrupt = crate::interrupt::typelevel::$irq;
858 } 857 }
859 }; 858 };
860} 859}
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 5761d04e1..8bac87d37 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -10,7 +10,7 @@ use embassy_hal_common::{into_ref, PeripheralRef};
10 10
11use crate::gpio::sealed::Pin as _; 11use crate::gpio::sealed::Pin as _;
12use crate::gpio::{AnyPin, Pin as GpioPin}; 12use crate::gpio::{AnyPin, Pin as GpioPin};
13use crate::interrupt::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::{interrupt, Peripheral}; 14use crate::{interrupt, Peripheral};
15 15
16/// Quadrature decoder driver. 16/// Quadrature decoder driver.
@@ -50,7 +50,7 @@ pub struct InterruptHandler<T: Instance> {
50 _phantom: PhantomData<T>, 50 _phantom: PhantomData<T>,
51} 51}
52 52
53impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 53impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
54 unsafe fn on_interrupt() { 54 unsafe fn on_interrupt() {
55 T::regs().intenclr.write(|w| w.reportrdy().clear()); 55 T::regs().intenclr.write(|w| w.reportrdy().clear());
56 T::state().waker.wake(); 56 T::state().waker.wake();
@@ -61,7 +61,7 @@ impl<'d, T: Instance> Qdec<'d, T> {
61 /// Create a new QDEC. 61 /// Create a new QDEC.
62 pub fn new( 62 pub fn new(
63 qdec: impl Peripheral<P = T> + 'd, 63 qdec: impl Peripheral<P = T> + 'd,
64 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 64 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
65 a: impl Peripheral<P = impl GpioPin> + 'd, 65 a: impl Peripheral<P = impl GpioPin> + 'd,
66 b: impl Peripheral<P = impl GpioPin> + 'd, 66 b: impl Peripheral<P = impl GpioPin> + 'd,
67 config: Config, 67 config: Config,
@@ -73,7 +73,7 @@ impl<'d, T: Instance> Qdec<'d, T> {
73 /// Create a new QDEC, with a pin for LED output. 73 /// Create a new QDEC, with a pin for LED output.
74 pub fn new_with_led( 74 pub fn new_with_led(
75 qdec: impl Peripheral<P = T> + 'd, 75 qdec: impl Peripheral<P = T> + 'd,
76 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 76 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
77 a: impl Peripheral<P = impl GpioPin> + 'd, 77 a: impl Peripheral<P = impl GpioPin> + 'd,
78 b: impl Peripheral<P = impl GpioPin> + 'd, 78 b: impl Peripheral<P = impl GpioPin> + 'd,
79 led: impl Peripheral<P = impl GpioPin> + 'd, 79 led: impl Peripheral<P = impl GpioPin> + 'd,
@@ -271,7 +271,7 @@ pub(crate) mod sealed {
271/// qdec peripheral instance. 271/// qdec peripheral instance.
272pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 272pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
273 /// Interrupt for this peripheral. 273 /// Interrupt for this peripheral.
274 type Interrupt: Interrupt; 274 type Interrupt: interrupt::typelevel::Interrupt;
275} 275}
276 276
277macro_rules! impl_qdec { 277macro_rules! impl_qdec {
@@ -286,7 +286,7 @@ macro_rules! impl_qdec {
286 } 286 }
287 } 287 }
288 impl crate::qdec::Instance for peripherals::$type { 288 impl crate::qdec::Instance for peripherals::$type {
289 type Interrupt = crate::interrupt::$irq; 289 type Interrupt = crate::interrupt::typelevel::$irq;
290 } 290 }
291 }; 291 };
292} 292}
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 3f48568b3..baefc7967 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -12,12 +12,12 @@ use embassy_hal_common::{into_ref, PeripheralRef};
12use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 12use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
13 13
14use crate::gpio::{self, Pin as GpioPin}; 14use crate::gpio::{self, Pin as GpioPin};
15use crate::interrupt::{self, Interrupt}; 15use crate::interrupt::typelevel::Interrupt;
16pub use crate::pac::qspi::ifconfig0::{ 16pub use crate::pac::qspi::ifconfig0::{
17 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, 17 ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
18}; 18};
19pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; 19pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
20use crate::Peripheral; 20use crate::{interrupt, Peripheral};
21 21
22/// Deep power-down config. 22/// Deep power-down config.
23pub struct DeepPowerDownConfig { 23pub struct DeepPowerDownConfig {
@@ -120,7 +120,7 @@ pub struct InterruptHandler<T: Instance> {
120 _phantom: PhantomData<T>, 120 _phantom: PhantomData<T>,
121} 121}
122 122
123impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 123impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
124 unsafe fn on_interrupt() { 124 unsafe fn on_interrupt() {
125 let r = T::regs(); 125 let r = T::regs();
126 let s = T::state(); 126 let s = T::state();
@@ -143,7 +143,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
143 /// Create a new QSPI driver. 143 /// Create a new QSPI driver.
144 pub fn new( 144 pub fn new(
145 qspi: impl Peripheral<P = T> + 'd, 145 qspi: impl Peripheral<P = T> + 'd,
146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 146 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
147 sck: impl Peripheral<P = impl GpioPin> + 'd, 147 sck: impl Peripheral<P = impl GpioPin> + 'd,
148 csn: impl Peripheral<P = impl GpioPin> + 'd, 148 csn: impl Peripheral<P = impl GpioPin> + 'd,
149 io0: impl Peripheral<P = impl GpioPin> + 'd, 149 io0: impl Peripheral<P = impl GpioPin> + 'd,
@@ -644,7 +644,7 @@ pub(crate) mod sealed {
644/// QSPI peripheral instance. 644/// QSPI peripheral instance.
645pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 645pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
646 /// Interrupt for this peripheral. 646 /// Interrupt for this peripheral.
647 type Interrupt: Interrupt; 647 type Interrupt: interrupt::typelevel::Interrupt;
648} 648}
649 649
650macro_rules! impl_qspi { 650macro_rules! impl_qspi {
@@ -659,7 +659,7 @@ macro_rules! impl_qspi {
659 } 659 }
660 } 660 }
661 impl crate::qspi::Instance for peripherals::$type { 661 impl crate::qspi::Instance for peripherals::$type {
662 type Interrupt = crate::interrupt::$irq; 662 type Interrupt = crate::interrupt::typelevel::$irq;
663 } 663 }
664 }; 664 };
665} 665}
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index 7e9b35481..923b8b467 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -12,7 +12,7 @@ use embassy_hal_common::drop::OnDrop;
12use embassy_hal_common::{into_ref, PeripheralRef}; 12use embassy_hal_common::{into_ref, PeripheralRef};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14 14
15use crate::interrupt::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
16use crate::{interrupt, Peripheral}; 16use crate::{interrupt, Peripheral};
17 17
18/// Interrupt handler. 18/// Interrupt handler.
@@ -20,7 +20,7 @@ pub struct InterruptHandler<T: Instance> {
20 _phantom: PhantomData<T>, 20 _phantom: PhantomData<T>,
21} 21}
22 22
23impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 23impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
24 unsafe fn on_interrupt() { 24 unsafe fn on_interrupt() {
25 let s = T::state(); 25 let s = T::state();
26 let r = T::regs(); 26 let r = T::regs();
@@ -89,7 +89,7 @@ impl<'d, T: Instance> Rng<'d, T> {
89 /// The synchronous API is safe. 89 /// The synchronous API is safe.
90 pub fn new( 90 pub fn new(
91 rng: impl Peripheral<P = T> + 'd, 91 rng: impl Peripheral<P = T> + 'd,
92 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 92 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
93 ) -> Self { 93 ) -> Self {
94 into_ref!(rng); 94 into_ref!(rng);
95 95
@@ -255,7 +255,7 @@ pub(crate) mod sealed {
255/// RNG peripheral instance. 255/// RNG peripheral instance.
256pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 256pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
257 /// Interrupt for this peripheral. 257 /// Interrupt for this peripheral.
258 type Interrupt: Interrupt; 258 type Interrupt: interrupt::typelevel::Interrupt;
259} 259}
260 260
261macro_rules! impl_rng { 261macro_rules! impl_rng {
@@ -270,7 +270,7 @@ macro_rules! impl_rng {
270 } 270 }
271 } 271 }
272 impl crate::rng::Instance for peripherals::$type { 272 impl crate::rng::Instance for peripherals::$type {
273 type Interrupt = crate::interrupt::$irq; 273 type Interrupt = crate::interrupt::typelevel::$irq;
274 } 274 }
275 }; 275 };
276} 276}
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 39764e380..cf3fb9993 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -6,7 +6,6 @@ use core::future::poll_fn;
6use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_cortex_m::interrupt::Interrupt;
10use embassy_hal_common::drop::OnDrop; 9use embassy_hal_common::drop::OnDrop;
11use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; 10use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
@@ -18,6 +17,7 @@ use saadc::oversample::OVERSAMPLE_A;
18use saadc::resolution::VAL_A; 17use saadc::resolution::VAL_A;
19 18
20use self::sealed::Input as _; 19use self::sealed::Input as _;
20use crate::interrupt::InterruptExt;
21use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; 21use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
22use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 22use crate::timer::{Frequency, Instance as TimerInstance, Timer};
23use crate::{interrupt, pac, peripherals, Peripheral}; 23use crate::{interrupt, pac, peripherals, Peripheral};
@@ -33,7 +33,7 @@ pub struct InterruptHandler {
33 _private: (), 33 _private: (),
34} 34}
35 35
36impl interrupt::Handler<interrupt::SAADC> for InterruptHandler { 36impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler {
37 unsafe fn on_interrupt() { 37 unsafe fn on_interrupt() {
38 let r = unsafe { &*SAADC::ptr() }; 38 let r = unsafe { &*SAADC::ptr() };
39 39
@@ -144,7 +144,7 @@ impl<'d, const N: usize> Saadc<'d, N> {
144 /// Create a new SAADC driver. 144 /// Create a new SAADC driver.
145 pub fn new( 145 pub fn new(
146 saadc: impl Peripheral<P = peripherals::SAADC> + 'd, 146 saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
147 _irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd, 147 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SAADC, InterruptHandler> + 'd,
148 config: Config, 148 config: Config,
149 channel_configs: [ChannelConfig; N], 149 channel_configs: [ChannelConfig; N],
150 ) -> Self { 150 ) -> Self {
@@ -189,8 +189,8 @@ impl<'d, const N: usize> Saadc<'d, N> {
189 // Disable all events interrupts 189 // Disable all events interrupts
190 r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); 190 r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
191 191
192 interrupt::SAADC::unpend(); 192 interrupt::SAADC.unpend();
193 unsafe { interrupt::SAADC::enable() }; 193 unsafe { interrupt::SAADC.enable() };
194 194
195 Self { _p: saadc } 195 Self { _p: saadc }
196 } 196 }
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index bb9cda323..66bbd1a8f 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -15,9 +15,9 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
15use crate::chip::FORCE_COPY_BUFFER_SIZE; 15use crate::chip::FORCE_COPY_BUFFER_SIZE;
16use crate::gpio::sealed::Pin as _; 16use crate::gpio::sealed::Pin as _;
17use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 17use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
18use crate::interrupt::{self, Interrupt}; 18use crate::interrupt::typelevel::Interrupt;
19use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 19use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
20use crate::{pac, Peripheral}; 20use crate::{interrupt, pac, Peripheral};
21 21
22/// SPIM error 22/// SPIM error
23#[derive(Debug, Clone, Copy, PartialEq, Eq)] 23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -63,7 +63,7 @@ pub struct InterruptHandler<T: Instance> {
63 _phantom: PhantomData<T>, 63 _phantom: PhantomData<T>,
64} 64}
65 65
66impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 66impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
67 unsafe fn on_interrupt() { 67 unsafe fn on_interrupt() {
68 let r = T::regs(); 68 let r = T::regs();
69 let s = T::state(); 69 let s = T::state();
@@ -84,7 +84,7 @@ impl<'d, T: Instance> Spim<'d, T> {
84 /// Create a new SPIM driver. 84 /// Create a new SPIM driver.
85 pub fn new( 85 pub fn new(
86 spim: impl Peripheral<P = T> + 'd, 86 spim: impl Peripheral<P = T> + 'd,
87 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 87 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
88 sck: impl Peripheral<P = impl GpioPin> + 'd, 88 sck: impl Peripheral<P = impl GpioPin> + 'd,
89 miso: impl Peripheral<P = impl GpioPin> + 'd, 89 miso: impl Peripheral<P = impl GpioPin> + 'd,
90 mosi: impl Peripheral<P = impl GpioPin> + 'd, 90 mosi: impl Peripheral<P = impl GpioPin> + 'd,
@@ -103,7 +103,7 @@ impl<'d, T: Instance> Spim<'d, T> {
103 /// Create a new SPIM driver, capable of TX only (MOSI only). 103 /// Create a new SPIM driver, capable of TX only (MOSI only).
104 pub fn new_txonly( 104 pub fn new_txonly(
105 spim: impl Peripheral<P = T> + 'd, 105 spim: impl Peripheral<P = T> + 'd,
106 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 106 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
107 sck: impl Peripheral<P = impl GpioPin> + 'd, 107 sck: impl Peripheral<P = impl GpioPin> + 'd,
108 mosi: impl Peripheral<P = impl GpioPin> + 'd, 108 mosi: impl Peripheral<P = impl GpioPin> + 'd,
109 config: Config, 109 config: Config,
@@ -115,7 +115,7 @@ impl<'d, T: Instance> Spim<'d, T> {
115 /// Create a new SPIM driver, capable of RX only (MISO only). 115 /// Create a new SPIM driver, capable of RX only (MISO only).
116 pub fn new_rxonly( 116 pub fn new_rxonly(
117 spim: impl Peripheral<P = T> + 'd, 117 spim: impl Peripheral<P = T> + 'd,
118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 118 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
119 sck: impl Peripheral<P = impl GpioPin> + 'd, 119 sck: impl Peripheral<P = impl GpioPin> + 'd,
120 miso: impl Peripheral<P = impl GpioPin> + 'd, 120 miso: impl Peripheral<P = impl GpioPin> + 'd,
121 config: Config, 121 config: Config,
@@ -408,7 +408,7 @@ pub(crate) mod sealed {
408/// SPIM peripheral instance 408/// SPIM peripheral instance
409pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 409pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
410 /// Interrupt for this peripheral. 410 /// Interrupt for this peripheral.
411 type Interrupt: Interrupt; 411 type Interrupt: interrupt::typelevel::Interrupt;
412} 412}
413 413
414macro_rules! impl_spim { 414macro_rules! impl_spim {
@@ -423,7 +423,7 @@ macro_rules! impl_spim {
423 } 423 }
424 } 424 }
425 impl crate::spim::Instance for peripherals::$type { 425 impl crate::spim::Instance for peripherals::$type {
426 type Interrupt = crate::interrupt::$irq; 426 type Interrupt = crate::interrupt::typelevel::$irq;
427 } 427 }
428 }; 428 };
429} 429}
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index a1d6803ed..aa438415a 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -13,9 +13,9 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
13use crate::chip::FORCE_COPY_BUFFER_SIZE; 13use crate::chip::FORCE_COPY_BUFFER_SIZE;
14use crate::gpio::sealed::Pin as _; 14use crate::gpio::sealed::Pin as _;
15use crate::gpio::{self, AnyPin, Pin as GpioPin}; 15use crate::gpio::{self, AnyPin, Pin as GpioPin};
16use crate::interrupt::{self, Interrupt}; 16use crate::interrupt::typelevel::Interrupt;
17use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 17use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
18use crate::{pac, Peripheral}; 18use crate::{interrupt, pac, Peripheral};
19 19
20/// SPIS error 20/// SPIS error
21#[derive(Debug, Clone, Copy, PartialEq, Eq)] 21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> {
68 _phantom: PhantomData<T>, 68 _phantom: PhantomData<T>,
69} 69}
70 70
71impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 71impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
72 unsafe fn on_interrupt() { 72 unsafe fn on_interrupt() {
73 let r = T::regs(); 73 let r = T::regs();
74 let s = T::state(); 74 let s = T::state();
@@ -94,7 +94,7 @@ impl<'d, T: Instance> Spis<'d, T> {
94 /// Create a new SPIS driver. 94 /// Create a new SPIS driver.
95 pub fn new( 95 pub fn new(
96 spis: impl Peripheral<P = T> + 'd, 96 spis: impl Peripheral<P = T> + 'd,
97 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 97 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
98 cs: impl Peripheral<P = impl GpioPin> + 'd, 98 cs: impl Peripheral<P = impl GpioPin> + 'd,
99 sck: impl Peripheral<P = impl GpioPin> + 'd, 99 sck: impl Peripheral<P = impl GpioPin> + 'd,
100 miso: impl Peripheral<P = impl GpioPin> + 'd, 100 miso: impl Peripheral<P = impl GpioPin> + 'd,
@@ -115,7 +115,7 @@ impl<'d, T: Instance> Spis<'d, T> {
115 /// Create a new SPIS driver, capable of TX only (MISO only). 115 /// Create a new SPIS driver, capable of TX only (MISO only).
116 pub fn new_txonly( 116 pub fn new_txonly(
117 spis: impl Peripheral<P = T> + 'd, 117 spis: impl Peripheral<P = T> + 'd,
118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 118 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
119 cs: impl Peripheral<P = impl GpioPin> + 'd, 119 cs: impl Peripheral<P = impl GpioPin> + 'd,
120 sck: impl Peripheral<P = impl GpioPin> + 'd, 120 sck: impl Peripheral<P = impl GpioPin> + 'd,
121 miso: impl Peripheral<P = impl GpioPin> + 'd, 121 miso: impl Peripheral<P = impl GpioPin> + 'd,
@@ -128,7 +128,7 @@ impl<'d, T: Instance> Spis<'d, T> {
128 /// Create a new SPIS driver, capable of RX only (MOSI only). 128 /// Create a new SPIS driver, capable of RX only (MOSI only).
129 pub fn new_rxonly( 129 pub fn new_rxonly(
130 spis: impl Peripheral<P = T> + 'd, 130 spis: impl Peripheral<P = T> + 'd,
131 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 131 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
132 cs: impl Peripheral<P = impl GpioPin> + 'd, 132 cs: impl Peripheral<P = impl GpioPin> + 'd,
133 sck: impl Peripheral<P = impl GpioPin> + 'd, 133 sck: impl Peripheral<P = impl GpioPin> + 'd,
134 mosi: impl Peripheral<P = impl GpioPin> + 'd, 134 mosi: impl Peripheral<P = impl GpioPin> + 'd,
@@ -480,7 +480,7 @@ pub(crate) mod sealed {
480/// SPIS peripheral instance 480/// SPIS peripheral instance
481pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 481pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
482 /// Interrupt for this peripheral. 482 /// Interrupt for this peripheral.
483 type Interrupt: Interrupt; 483 type Interrupt: interrupt::typelevel::Interrupt;
484} 484}
485 485
486macro_rules! impl_spis { 486macro_rules! impl_spis {
@@ -495,7 +495,7 @@ macro_rules! impl_spis {
495 } 495 }
496 } 496 }
497 impl crate::spis::Instance for peripherals::$type { 497 impl crate::spis::Instance for peripherals::$type {
498 type Interrupt = crate::interrupt::$irq; 498 type Interrupt = crate::interrupt::typelevel::$irq;
499 } 499 }
500 }; 500 };
501} 501}
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index 8a127efc5..491e92c04 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -8,7 +8,7 @@ use embassy_hal_common::{into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
9use fixed::types::I30F2; 9use fixed::types::I30F2;
10 10
11use crate::interrupt::Interrupt; 11use crate::interrupt::InterruptExt;
12use crate::peripherals::TEMP; 12use crate::peripherals::TEMP;
13use crate::{interrupt, pac, Peripheral}; 13use crate::{interrupt, pac, Peripheral};
14 14
@@ -17,7 +17,7 @@ pub struct InterruptHandler {
17 _private: (), 17 _private: (),
18} 18}
19 19
20impl interrupt::Handler<interrupt::TEMP> for InterruptHandler { 20impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler {
21 unsafe fn on_interrupt() { 21 unsafe fn on_interrupt() {
22 let r = unsafe { &*pac::TEMP::PTR }; 22 let r = unsafe { &*pac::TEMP::PTR };
23 r.intenclr.write(|w| w.datardy().clear()); 23 r.intenclr.write(|w| w.datardy().clear());
@@ -36,13 +36,13 @@ impl<'d> Temp<'d> {
36 /// Create a new temperature sensor driver. 36 /// Create a new temperature sensor driver.
37 pub fn new( 37 pub fn new(
38 _peri: impl Peripheral<P = TEMP> + 'd, 38 _peri: impl Peripheral<P = TEMP> + 'd,
39 _irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd, 39 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::TEMP, InterruptHandler> + 'd,
40 ) -> Self { 40 ) -> Self {
41 into_ref!(_peri); 41 into_ref!(_peri);
42 42
43 // Enable interrupt that signals temperature values 43 // Enable interrupt that signals temperature values
44 interrupt::TEMP::unpend(); 44 interrupt::TEMP.unpend();
45 unsafe { interrupt::TEMP::enable() }; 45 unsafe { interrupt::TEMP.enable() };
46 46
47 Self { _peri } 47 Self { _peri }
48 } 48 }
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 4feff8a75..f1ab4f8fd 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -7,7 +7,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; 7use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
8use embassy_time::driver::{AlarmHandle, Driver}; 8use embassy_time::driver::{AlarmHandle, Driver};
9 9
10use crate::interrupt::Interrupt; 10use crate::interrupt::InterruptExt;
11use crate::{interrupt, pac}; 11use crate::{interrupt, pac};
12 12
13fn rtc() -> &'static pac::rtc0::RegisterBlock { 13fn rtc() -> &'static pac::rtc0::RegisterBlock {
@@ -142,8 +142,8 @@ impl RtcDriver {
142 // Wait for clear 142 // Wait for clear
143 while r.counter.read().bits() != 0 {} 143 while r.counter.read().bits() != 0 {}
144 144
145 interrupt::RTC1::set_priority(irq_prio); 145 interrupt::RTC1.set_priority(irq_prio);
146 unsafe { interrupt::RTC1::enable() }; 146 unsafe { interrupt::RTC1.enable() };
147 } 147 }
148 148
149 fn on_interrupt(&self) { 149 fn on_interrupt(&self) {
@@ -295,6 +295,7 @@ impl Driver for RtcDriver {
295 } 295 }
296} 296}
297 297
298#[cfg(feature = "rt")]
298#[interrupt] 299#[interrupt]
299fn RTC1() { 300fn RTC1() {
300 DRIVER.on_interrupt() 301 DRIVER.on_interrupt()
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 2a0e16a50..dc3757856 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -8,7 +8,6 @@
8 8
9use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
10 10
11use crate::interrupt::Interrupt;
12use crate::ppi::{Event, Task}; 11use crate::ppi::{Event, Task};
13use crate::{pac, Peripheral}; 12use crate::{pac, Peripheral};
14 13
@@ -29,7 +28,7 @@ pub(crate) mod sealed {
29/// Basic Timer instance. 28/// Basic Timer instance.
30pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 29pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
31 /// Interrupt for this peripheral. 30 /// Interrupt for this peripheral.
32 type Interrupt: Interrupt; 31 type Interrupt: crate::interrupt::typelevel::Interrupt;
33} 32}
34 33
35/// Extended timer instance. 34/// Extended timer instance.
@@ -44,7 +43,7 @@ macro_rules! impl_timer {
44 } 43 }
45 } 44 }
46 impl crate::timer::Instance for peripherals::$type { 45 impl crate::timer::Instance for peripherals::$type {
47 type Interrupt = crate::interrupt::$irq; 46 type Interrupt = crate::interrupt::typelevel::$irq;
48 } 47 }
49 }; 48 };
50 ($type:ident, $pac_type:ident, $irq:ident) => { 49 ($type:ident, $pac_type:ident, $irq:ident) => {
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index dea398a67..2ad0d19b1 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -16,9 +16,9 @@ use embassy_time::{Duration, Instant};
16 16
17use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 17use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
18use crate::gpio::Pin as GpioPin; 18use crate::gpio::Pin as GpioPin;
19use crate::interrupt::{self, Interrupt}; 19use crate::interrupt::typelevel::Interrupt;
20use crate::util::{slice_in_ram, slice_in_ram_or}; 20use crate::util::{slice_in_ram, slice_in_ram_or};
21use crate::{gpio, pac, Peripheral}; 21use crate::{gpio, interrupt, pac, Peripheral};
22 22
23/// TWI frequency 23/// TWI frequency
24#[derive(Clone, Copy)] 24#[derive(Clone, Copy)]
@@ -98,7 +98,7 @@ pub struct InterruptHandler<T: Instance> {
98 _phantom: PhantomData<T>, 98 _phantom: PhantomData<T>,
99} 99}
100 100
101impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 101impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
102 unsafe fn on_interrupt() { 102 unsafe fn on_interrupt() {
103 let r = T::regs(); 103 let r = T::regs();
104 let s = T::state(); 104 let s = T::state();
@@ -123,7 +123,7 @@ impl<'d, T: Instance> Twim<'d, T> {
123 /// Create a new TWI driver. 123 /// Create a new TWI driver.
124 pub fn new( 124 pub fn new(
125 twim: impl Peripheral<P = T> + 'd, 125 twim: impl Peripheral<P = T> + 'd,
126 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 126 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
127 sda: impl Peripheral<P = impl GpioPin> + 'd, 127 sda: impl Peripheral<P = impl GpioPin> + 'd,
128 scl: impl Peripheral<P = impl GpioPin> + 'd, 128 scl: impl Peripheral<P = impl GpioPin> + 'd,
129 config: Config, 129 config: Config,
@@ -750,7 +750,7 @@ pub(crate) mod sealed {
750/// TWIM peripheral instance. 750/// TWIM peripheral instance.
751pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 751pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
752 /// Interrupt for this peripheral. 752 /// Interrupt for this peripheral.
753 type Interrupt: Interrupt; 753 type Interrupt: interrupt::typelevel::Interrupt;
754} 754}
755 755
756macro_rules! impl_twim { 756macro_rules! impl_twim {
@@ -765,7 +765,7 @@ macro_rules! impl_twim {
765 } 765 }
766 } 766 }
767 impl crate::twim::Instance for peripherals::$type { 767 impl crate::twim::Instance for peripherals::$type {
768 type Interrupt = crate::interrupt::$irq; 768 type Interrupt = crate::interrupt::typelevel::$irq;
769 } 769 }
770 }; 770 };
771} 771}
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
index 752a8c046..a115d5616 100644
--- a/embassy-nrf/src/twis.rs
+++ b/embassy-nrf/src/twis.rs
@@ -15,9 +15,9 @@ use embassy_time::{Duration, Instant};
15 15
16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
17use crate::gpio::Pin as GpioPin; 17use crate::gpio::Pin as GpioPin;
18use crate::interrupt::{self, Interrupt}; 18use crate::interrupt::typelevel::Interrupt;
19use crate::util::slice_in_ram_or; 19use crate::util::slice_in_ram_or;
20use crate::{gpio, pac, Peripheral}; 20use crate::{gpio, interrupt, pac, Peripheral};
21 21
22/// TWIS config. 22/// TWIS config.
23#[non_exhaustive] 23#[non_exhaustive]
@@ -114,7 +114,7 @@ pub struct InterruptHandler<T: Instance> {
114 _phantom: PhantomData<T>, 114 _phantom: PhantomData<T>,
115} 115}
116 116
117impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 117impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
118 unsafe fn on_interrupt() { 118 unsafe fn on_interrupt() {
119 let r = T::regs(); 119 let r = T::regs();
120 let s = T::state(); 120 let s = T::state();
@@ -143,7 +143,7 @@ impl<'d, T: Instance> Twis<'d, T> {
143 /// Create a new TWIS driver. 143 /// Create a new TWIS driver.
144 pub fn new( 144 pub fn new(
145 twis: impl Peripheral<P = T> + 'd, 145 twis: impl Peripheral<P = T> + 'd,
146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 146 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
147 sda: impl Peripheral<P = impl GpioPin> + 'd, 147 sda: impl Peripheral<P = impl GpioPin> + 'd,
148 scl: impl Peripheral<P = impl GpioPin> + 'd, 148 scl: impl Peripheral<P = impl GpioPin> + 'd,
149 config: Config, 149 config: Config,
@@ -778,7 +778,7 @@ pub(crate) mod sealed {
778/// TWIS peripheral instance. 778/// TWIS peripheral instance.
779pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 779pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
780 /// Interrupt for this peripheral. 780 /// Interrupt for this peripheral.
781 type Interrupt: Interrupt; 781 type Interrupt: interrupt::typelevel::Interrupt;
782} 782}
783 783
784macro_rules! impl_twis { 784macro_rules! impl_twis {
@@ -793,7 +793,7 @@ macro_rules! impl_twis {
793 } 793 }
794 } 794 }
795 impl crate::twis::Instance for peripherals::$type { 795 impl crate::twis::Instance for peripherals::$type {
796 type Interrupt = crate::interrupt::$irq; 796 type Interrupt = crate::interrupt::typelevel::$irq;
797 } 797 }
798 }; 798 };
799} 799}
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 6c6941ee8..48d57fea4 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -27,11 +27,11 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
27use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 27use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
28use crate::gpio::sealed::Pin as _; 28use crate::gpio::sealed::Pin as _;
29use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 29use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
30use crate::interrupt::{self, Interrupt}; 30use crate::interrupt::typelevel::Interrupt;
31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
32use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 32use crate::timer::{Frequency, Instance as TimerInstance, Timer};
33use crate::util::slice_in_ram_or; 33use crate::util::slice_in_ram_or;
34use crate::{pac, Peripheral}; 34use crate::{interrupt, pac, Peripheral};
35 35
36/// UARTE config. 36/// UARTE config.
37#[derive(Clone)] 37#[derive(Clone)]
@@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> {
68 _phantom: PhantomData<T>, 68 _phantom: PhantomData<T>,
69} 69}
70 70
71impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 71impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
72 unsafe fn on_interrupt() { 72 unsafe fn on_interrupt() {
73 let r = T::regs(); 73 let r = T::regs();
74 let s = T::state(); 74 let s = T::state();
@@ -108,7 +108,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
108 /// Create a new UARTE without hardware flow control 108 /// Create a new UARTE without hardware flow control
109 pub fn new( 109 pub fn new(
110 uarte: impl Peripheral<P = T> + 'd, 110 uarte: impl Peripheral<P = T> + 'd,
111 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 111 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
112 rxd: impl Peripheral<P = impl GpioPin> + 'd, 112 rxd: impl Peripheral<P = impl GpioPin> + 'd,
113 txd: impl Peripheral<P = impl GpioPin> + 'd, 113 txd: impl Peripheral<P = impl GpioPin> + 'd,
114 config: Config, 114 config: Config,
@@ -120,7 +120,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
120 /// Create a new UARTE with hardware flow control (RTS/CTS) 120 /// Create a new UARTE with hardware flow control (RTS/CTS)
121 pub fn new_with_rtscts( 121 pub fn new_with_rtscts(
122 uarte: impl Peripheral<P = T> + 'd, 122 uarte: impl Peripheral<P = T> + 'd,
123 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 123 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
124 rxd: impl Peripheral<P = impl GpioPin> + 'd, 124 rxd: impl Peripheral<P = impl GpioPin> + 'd,
125 txd: impl Peripheral<P = impl GpioPin> + 'd, 125 txd: impl Peripheral<P = impl GpioPin> + 'd,
126 cts: impl Peripheral<P = impl GpioPin> + 'd, 126 cts: impl Peripheral<P = impl GpioPin> + 'd,
@@ -205,50 +205,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
205 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, 205 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
206 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, 206 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
207 ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { 207 ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) {
208 let timer = Timer::new(timer); 208 (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2))
209
210 into_ref!(ppi_ch1, ppi_ch2);
211
212 let r = T::regs();
213
214 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
215 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
216 //
217 // We want to stop RX if line is idle for 2 bytes worth of time
218 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
219 // This gives us the amount of 16M ticks for 20 bits.
220 let baudrate = r.baudrate.read().baudrate().variant().unwrap();
221 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
222
223 timer.set_frequency(Frequency::F16MHz);
224 timer.cc(0).write(timeout);
225 timer.cc(0).short_compare_clear();
226 timer.cc(0).short_compare_stop();
227
228 let mut ppi_ch1 = Ppi::new_one_to_two(
229 ppi_ch1.map_into(),
230 Event::from_reg(&r.events_rxdrdy),
231 timer.task_clear(),
232 timer.task_start(),
233 );
234 ppi_ch1.enable();
235
236 let mut ppi_ch2 = Ppi::new_one_to_one(
237 ppi_ch2.map_into(),
238 timer.cc(0).event_compare(),
239 Task::from_reg(&r.tasks_stoprx),
240 );
241 ppi_ch2.enable();
242
243 (
244 self.tx,
245 UarteRxWithIdle {
246 rx: self.rx,
247 timer,
248 ppi_ch1: ppi_ch1,
249 _ppi_ch2: ppi_ch2,
250 },
251 )
252 } 209 }
253 210
254 /// Return the endtx event for use with PPI 211 /// Return the endtx event for use with PPI
@@ -313,7 +270,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
313 /// Create a new tx-only UARTE without hardware flow control 270 /// Create a new tx-only UARTE without hardware flow control
314 pub fn new( 271 pub fn new(
315 uarte: impl Peripheral<P = T> + 'd, 272 uarte: impl Peripheral<P = T> + 'd,
316 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 273 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
317 txd: impl Peripheral<P = impl GpioPin> + 'd, 274 txd: impl Peripheral<P = impl GpioPin> + 'd,
318 config: Config, 275 config: Config,
319 ) -> Self { 276 ) -> Self {
@@ -324,7 +281,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
324 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) 281 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
325 pub fn new_with_rtscts( 282 pub fn new_with_rtscts(
326 uarte: impl Peripheral<P = T> + 'd, 283 uarte: impl Peripheral<P = T> + 'd,
327 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 284 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
328 txd: impl Peripheral<P = impl GpioPin> + 'd, 285 txd: impl Peripheral<P = impl GpioPin> + 'd,
329 cts: impl Peripheral<P = impl GpioPin> + 'd, 286 cts: impl Peripheral<P = impl GpioPin> + 'd,
330 config: Config, 287 config: Config,
@@ -509,7 +466,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
509 /// Create a new rx-only UARTE without hardware flow control 466 /// Create a new rx-only UARTE without hardware flow control
510 pub fn new( 467 pub fn new(
511 uarte: impl Peripheral<P = T> + 'd, 468 uarte: impl Peripheral<P = T> + 'd,
512 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 469 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
513 rxd: impl Peripheral<P = impl GpioPin> + 'd, 470 rxd: impl Peripheral<P = impl GpioPin> + 'd,
514 config: Config, 471 config: Config,
515 ) -> Self { 472 ) -> Self {
@@ -520,7 +477,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
520 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) 477 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
521 pub fn new_with_rtscts( 478 pub fn new_with_rtscts(
522 uarte: impl Peripheral<P = T> + 'd, 479 uarte: impl Peripheral<P = T> + 'd,
523 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 480 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
524 rxd: impl Peripheral<P = impl GpioPin> + 'd, 481 rxd: impl Peripheral<P = impl GpioPin> + 'd,
525 rts: impl Peripheral<P = impl GpioPin> + 'd, 482 rts: impl Peripheral<P = impl GpioPin> + 'd,
526 config: Config, 483 config: Config,
@@ -563,6 +520,56 @@ impl<'d, T: Instance> UarteRx<'d, T> {
563 Self { _p: uarte } 520 Self { _p: uarte }
564 } 521 }
565 522
523 /// Upgrade to an instance that supports idle line detection.
524 pub fn with_idle<U: TimerInstance>(
525 self,
526 timer: impl Peripheral<P = U> + 'd,
527 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
528 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
529 ) -> UarteRxWithIdle<'d, T, U> {
530 let timer = Timer::new(timer);
531
532 into_ref!(ppi_ch1, ppi_ch2);
533
534 let r = T::regs();
535
536 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
537 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
538 //
539 // We want to stop RX if line is idle for 2 bytes worth of time
540 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
541 // This gives us the amount of 16M ticks for 20 bits.
542 let baudrate = r.baudrate.read().baudrate().variant().unwrap();
543 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
544
545 timer.set_frequency(Frequency::F16MHz);
546 timer.cc(0).write(timeout);
547 timer.cc(0).short_compare_clear();
548 timer.cc(0).short_compare_stop();
549
550 let mut ppi_ch1 = Ppi::new_one_to_two(
551 ppi_ch1.map_into(),
552 Event::from_reg(&r.events_rxdrdy),
553 timer.task_clear(),
554 timer.task_start(),
555 );
556 ppi_ch1.enable();
557
558 let mut ppi_ch2 = Ppi::new_one_to_one(
559 ppi_ch2.map_into(),
560 timer.cc(0).event_compare(),
561 Task::from_reg(&r.tasks_stoprx),
562 );
563 ppi_ch2.enable();
564
565 UarteRxWithIdle {
566 rx: self,
567 timer,
568 ppi_ch1: ppi_ch1,
569 _ppi_ch2: ppi_ch2,
570 }
571 }
572
566 /// Read bytes until the buffer is filled. 573 /// Read bytes until the buffer is filled.
567 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 574 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
568 if buffer.len() == 0 { 575 if buffer.len() == 0 {
@@ -889,7 +896,7 @@ pub(crate) mod sealed {
889/// UARTE peripheral instance. 896/// UARTE peripheral instance.
890pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 897pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
891 /// Interrupt for this peripheral. 898 /// Interrupt for this peripheral.
892 type Interrupt: Interrupt; 899 type Interrupt: interrupt::typelevel::Interrupt;
893} 900}
894 901
895macro_rules! impl_uarte { 902macro_rules! impl_uarte {
@@ -908,7 +915,7 @@ macro_rules! impl_uarte {
908 } 915 }
909 } 916 }
910 impl crate::uarte::Instance for peripherals::$type { 917 impl crate::uarte::Instance for peripherals::$type {
911 type Interrupt = crate::interrupt::$irq; 918 type Interrupt = crate::interrupt::typelevel::$irq;
912 } 919 }
913 }; 920 };
914} 921}
diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs
index 3c62b4452..76cf40ac7 100644
--- a/embassy-nrf/src/usb/mod.rs
+++ b/embassy-nrf/src/usb/mod.rs
@@ -18,9 +18,9 @@ use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo
18use pac::usbd::RegisterBlock; 18use pac::usbd::RegisterBlock;
19 19
20use self::vbus_detect::VbusDetect; 20use self::vbus_detect::VbusDetect;
21use crate::interrupt::{self, Interrupt}; 21use crate::interrupt::typelevel::Interrupt;
22use crate::util::slice_in_ram; 22use crate::util::slice_in_ram;
23use crate::{pac, Peripheral}; 23use crate::{interrupt, pac, Peripheral};
24 24
25const NEW_AW: AtomicWaker = AtomicWaker::new(); 25const NEW_AW: AtomicWaker = AtomicWaker::new();
26static BUS_WAKER: AtomicWaker = NEW_AW; 26static BUS_WAKER: AtomicWaker = NEW_AW;
@@ -34,7 +34,7 @@ pub struct InterruptHandler<T: Instance> {
34 _phantom: PhantomData<T>, 34 _phantom: PhantomData<T>,
35} 35}
36 36
37impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 37impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
38 unsafe fn on_interrupt() { 38 unsafe fn on_interrupt() {
39 let regs = T::regs(); 39 let regs = T::regs();
40 40
@@ -98,7 +98,7 @@ impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
98 /// Create a new USB driver. 98 /// Create a new USB driver.
99 pub fn new( 99 pub fn new(
100 usb: impl Peripheral<P = T> + 'd, 100 usb: impl Peripheral<P = T> + 'd,
101 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 101 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
102 vbus_detect: V, 102 vbus_detect: V,
103 ) -> Self { 103 ) -> Self {
104 into_ref!(usb); 104 into_ref!(usb);
@@ -804,7 +804,7 @@ pub(crate) mod sealed {
804/// USB peripheral instance. 804/// USB peripheral instance.
805pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 805pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
806 /// Interrupt for this peripheral. 806 /// Interrupt for this peripheral.
807 type Interrupt: Interrupt; 807 type Interrupt: interrupt::typelevel::Interrupt;
808} 808}
809 809
810macro_rules! impl_usb { 810macro_rules! impl_usb {
@@ -815,7 +815,7 @@ macro_rules! impl_usb {
815 } 815 }
816 } 816 }
817 impl crate::usb::Instance for peripherals::$type { 817 impl crate::usb::Instance for peripherals::$type {
818 type Interrupt = crate::interrupt::$irq; 818 type Interrupt = crate::interrupt::typelevel::$irq;
819 } 819 }
820 }; 820 };
821} 821}
diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs
index a6a959905..a05e5aa52 100644
--- a/embassy-nrf/src/usb/vbus_detect.rs
+++ b/embassy-nrf/src/usb/vbus_detect.rs
@@ -7,8 +7,8 @@ use core::task::Poll;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::BUS_WAKER; 9use super::BUS_WAKER;
10use crate::interrupt::{self, Interrupt}; 10use crate::interrupt::typelevel::Interrupt;
11use crate::pac; 11use crate::{interrupt, pac};
12 12
13/// Trait for detecting USB VBUS power. 13/// Trait for detecting USB VBUS power.
14/// 14///
@@ -29,9 +29,9 @@ pub trait VbusDetect {
29} 29}
30 30
31#[cfg(not(feature = "_nrf5340"))] 31#[cfg(not(feature = "_nrf5340"))]
32type UsbRegIrq = interrupt::POWER_CLOCK; 32type UsbRegIrq = interrupt::typelevel::POWER_CLOCK;
33#[cfg(feature = "_nrf5340")] 33#[cfg(feature = "_nrf5340")]
34type UsbRegIrq = interrupt::USBREGULATOR; 34type UsbRegIrq = interrupt::typelevel::USBREGULATOR;
35 35
36#[cfg(not(feature = "_nrf5340"))] 36#[cfg(not(feature = "_nrf5340"))]
37type UsbRegPeri = pac::POWER; 37type UsbRegPeri = pac::POWER;
@@ -43,7 +43,7 @@ pub struct InterruptHandler {
43 _private: (), 43 _private: (),
44} 44}
45 45
46impl interrupt::Handler<UsbRegIrq> for InterruptHandler { 46impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler {
47 unsafe fn on_interrupt() { 47 unsafe fn on_interrupt() {
48 let regs = unsafe { &*UsbRegPeri::ptr() }; 48 let regs = unsafe { &*UsbRegPeri::ptr() };
49 49
@@ -77,7 +77,7 @@ static POWER_WAKER: AtomicWaker = AtomicWaker::new();
77 77
78impl HardwareVbusDetect { 78impl HardwareVbusDetect {
79 /// Create a new `VbusDetectNative`. 79 /// Create a new `VbusDetectNative`.
80 pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { 80 pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
81 let regs = unsafe { &*UsbRegPeri::ptr() }; 81 let regs = unsafe { &*UsbRegPeri::ptr() };
82 82
83 UsbRegIrq::unpend(); 83 UsbRegIrq::unpend();
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 5f08c7f33..66823771a 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -13,7 +13,8 @@ flavors = [
13] 13]
14 14
15[features] 15[features]
16default = [ "rp-pac/rt" ] 16default = [ "rt" ]
17rt = [ "rp-pac/rt" ]
17 18
18defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"] 19defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"]
19 20
@@ -41,8 +42,13 @@ boot2-ram-memcpy = []
41boot2-w25q080 = [] 42boot2-w25q080 = []
42boot2-w25x10cl = [] 43boot2-w25x10cl = []
43 44
45# Indicate code is running from RAM.
46# Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP.
47# This allows the flash driver to not force pausing execution on both cores when doing flash operations.
48run-from-ram = []
49
44# Enable nightly-only features 50# Enable nightly-only features
45nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] 51nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
46 52
47# Implement embedded-hal 1.0 alpha traits. 53# Implement embedded-hal 1.0 alpha traits.
48# Implement embedded-hal-async traits if `nightly` is set as well. 54# Implement embedded-hal-async traits if `nightly` is set as well.
@@ -50,11 +56,9 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
50 56
51[dependencies] 57[dependencies]
52embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 58embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
53embassy-executor = { version = "0.2.0", path = "../embassy-executor" }
54embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } 59embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
55embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 60embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
56embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} 61embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-2"] }
57embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
58embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 62embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
59embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } 63embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
60atomic-polyfill = "1.0.1" 64atomic-polyfill = "1.0.1"
@@ -72,7 +76,7 @@ embedded-storage = { version = "0.3" }
72rand_core = "0.6.4" 76rand_core = "0.6.4"
73fixed = "1.23.1" 77fixed = "1.23.1"
74 78
75rp-pac = { version = "4" } 79rp-pac = { version = "6" }
76 80
77embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 81embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
78embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 82embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
@@ -85,5 +89,5 @@ pio = {version= "0.2.1" }
85rp2040-boot2 = "0.3" 89rp2040-boot2 = "0.3"
86 90
87[dev-dependencies] 91[dev-dependencies]
88embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } 92embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] }
89static_cell = "1.1" 93static_cell = "1.1"
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 86a353670..699a0d61d 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -3,14 +3,14 @@ use core::marker::PhantomData;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_cortex_m::interrupt::{Binding, Interrupt};
7use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
8use embedded_hal_02::adc::{Channel, OneShot}; 7use embedded_hal_02::adc::{Channel, OneShot};
9 8
10use crate::gpio::Pin; 9use crate::gpio::Pin;
11use crate::interrupt::{self, ADC_IRQ_FIFO}; 10use crate::interrupt::typelevel::Binding;
11use crate::interrupt::InterruptExt;
12use crate::peripherals::ADC; 12use crate::peripherals::ADC;
13use crate::{pac, peripherals, Peripheral}; 13use crate::{interrupt, pac, peripherals, Peripheral};
14static WAKER: AtomicWaker = AtomicWaker::new(); 14static WAKER: AtomicWaker = AtomicWaker::new();
15 15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)] 16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -47,105 +47,97 @@ impl<'d> Adc<'d> {
47 47
48 pub fn new( 48 pub fn new(
49 _inner: impl Peripheral<P = ADC> + 'd, 49 _inner: impl Peripheral<P = ADC> + 'd,
50 _irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>, 50 _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
51 _config: Config, 51 _config: Config,
52 ) -> Self { 52 ) -> Self {
53 unsafe { 53 let reset = Self::reset();
54 let reset = Self::reset(); 54 crate::reset::reset(reset);
55 crate::reset::reset(reset); 55 crate::reset::unreset_wait(reset);
56 crate::reset::unreset_wait(reset); 56 let r = Self::regs();
57 let r = Self::regs(); 57 // Enable ADC
58 // Enable ADC 58 r.cs().write(|w| w.set_en(true));
59 r.cs().write(|w| w.set_en(true)); 59 // Wait for ADC ready
60 // Wait for ADC ready 60 while !r.cs().read().ready() {}
61 while !r.cs().read().ready() {}
62 }
63 61
64 // Setup IRQ 62 // Setup IRQ
65 unsafe { 63 interrupt::ADC_IRQ_FIFO.unpend();
66 ADC_IRQ_FIFO::unpend(); 64 unsafe { interrupt::ADC_IRQ_FIFO.enable() };
67 ADC_IRQ_FIFO::enable();
68 };
69 65
70 Self { phantom: PhantomData } 66 Self { phantom: PhantomData }
71 } 67 }
72 68
73 async fn wait_for_ready() { 69 async fn wait_for_ready() {
74 let r = Self::regs(); 70 let r = Self::regs();
75 unsafe { 71 r.inte().write(|w| w.set_fifo(true));
76 r.inte().write(|w| w.set_fifo(true)); 72 compiler_fence(Ordering::SeqCst);
77 compiler_fence(Ordering::SeqCst); 73 poll_fn(|cx| {
78 poll_fn(|cx| { 74 WAKER.register(cx.waker());
79 WAKER.register(cx.waker()); 75 if r.cs().read().ready() {
80 if r.cs().read().ready() { 76 return Poll::Ready(());
81 return Poll::Ready(()); 77 }
82 } 78 Poll::Pending
83 Poll::Pending 79 })
84 }) 80 .await;
85 .await;
86 }
87 } 81 }
88 82
89 pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { 83 pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
90 let r = Self::regs(); 84 let r = Self::regs();
91 unsafe { 85 // disable pull-down and pull-up resistors
92 // disable pull-down and pull-up resistors 86 // pull-down resistors are enabled by default
93 // pull-down resistors are enabled by default 87 pin.pad_ctrl().modify(|w| {
94 pin.pad_ctrl().modify(|w| { 88 w.set_ie(true);
95 w.set_ie(true); 89 let (pu, pd) = (false, false);
96 let (pu, pd) = (false, false); 90 w.set_pue(pu);
97 w.set_pue(pu); 91 w.set_pde(pd);
98 w.set_pde(pd); 92 });
99 }); 93 r.cs().modify(|w| {
100 r.cs().modify(|w| { 94 w.set_ainsel(PIN::channel());
101 w.set_ainsel(PIN::channel()); 95 w.set_start_once(true)
102 w.set_start_once(true) 96 });
103 }); 97 Self::wait_for_ready().await;
104 Self::wait_for_ready().await; 98 r.result().read().result().into()
105 r.result().read().result().into()
106 }
107 } 99 }
108 100
109 pub async fn read_temperature(&mut self) -> u16 { 101 pub async fn read_temperature(&mut self) -> u16 {
110 let r = Self::regs(); 102 let r = Self::regs();
111 unsafe { 103 r.cs().modify(|w| w.set_ts_en(true));
112 r.cs().modify(|w| w.set_ts_en(true)); 104 if !r.cs().read().ready() {
113 if !r.cs().read().ready() {
114 Self::wait_for_ready().await;
115 }
116 r.cs().modify(|w| {
117 w.set_ainsel(4);
118 w.set_start_once(true)
119 });
120 Self::wait_for_ready().await; 105 Self::wait_for_ready().await;
121 r.result().read().result().into()
122 } 106 }
107 r.cs().modify(|w| {
108 w.set_ainsel(4);
109 w.set_start_once(true)
110 });
111 Self::wait_for_ready().await;
112 r.result().read().result().into()
123 } 113 }
124 114
125 pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { 115 pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
126 let r = Self::regs(); 116 let r = Self::regs();
127 unsafe { 117 pin.pad_ctrl().modify(|w| {
128 r.cs().modify(|w| { 118 w.set_ie(true);
129 w.set_ainsel(PIN::channel()); 119 let (pu, pd) = (false, false);
130 w.set_start_once(true) 120 w.set_pue(pu);
131 }); 121 w.set_pde(pd);
132 while !r.cs().read().ready() {} 122 });
133 r.result().read().result().into() 123 r.cs().modify(|w| {
134 } 124 w.set_ainsel(PIN::channel());
125 w.set_start_once(true)
126 });
127 while !r.cs().read().ready() {}
128 r.result().read().result().into()
135 } 129 }
136 130
137 pub fn blocking_read_temperature(&mut self) -> u16 { 131 pub fn blocking_read_temperature(&mut self) -> u16 {
138 let r = Self::regs(); 132 let r = Self::regs();
139 unsafe { 133 r.cs().modify(|w| w.set_ts_en(true));
140 r.cs().modify(|w| w.set_ts_en(true)); 134 while !r.cs().read().ready() {}
141 while !r.cs().read().ready() {} 135 r.cs().modify(|w| {
142 r.cs().modify(|w| { 136 w.set_ainsel(4);
143 w.set_ainsel(4); 137 w.set_start_once(true)
144 w.set_start_once(true) 138 });
145 }); 139 while !r.cs().read().ready() {}
146 while !r.cs().read().ready() {} 140 r.result().read().result().into()
147 r.result().read().result().into()
148 }
149 } 141 }
150} 142}
151 143
@@ -164,7 +156,7 @@ pub struct InterruptHandler {
164 _empty: (), 156 _empty: (),
165} 157}
166 158
167impl interrupt::Handler<ADC_IRQ_FIFO> for InterruptHandler { 159impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler {
168 unsafe fn on_interrupt() { 160 unsafe fn on_interrupt() {
169 let r = Adc::regs(); 161 let r = Adc::regs();
170 r.inte().write(|w| w.set_fifo(false)); 162 r.inte().write(|w| w.set_fifo(false));
@@ -180,7 +172,7 @@ impl_pin!(PIN_29, 3);
180impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static> 172impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static>
181where 173where
182 WORD: From<u16>, 174 WORD: From<u16>,
183 PIN: Channel<Adc<'static>, ID = u8>, 175 PIN: Channel<Adc<'static>, ID = u8> + Pin,
184{ 176{
185 type Error = (); 177 type Error = ();
186 fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> { 178 fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 67439fda3..ddd61d224 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -46,13 +46,13 @@ static CLOCKS: Clocks = Clocks {
46#[non_exhaustive] 46#[non_exhaustive]
47#[derive(Clone, Copy, Debug, PartialEq, Eq)] 47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum PeriClkSrc { 48pub enum PeriClkSrc {
49 Sys = ClkPeriCtrlAuxsrc::CLK_SYS.0, 49 Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _,
50 PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS.0, 50 PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _,
51 PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0, 51 PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _,
52 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0, 52 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _,
53 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0, 53 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _,
54 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0, 54 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
55 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0, 55 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
56} 56}
57 57
58#[non_exhaustive] 58#[non_exhaustive]
@@ -251,12 +251,12 @@ pub struct SysClkConfig {
251#[non_exhaustive] 251#[non_exhaustive]
252#[derive(Clone, Copy, Debug, PartialEq, Eq)] 252#[derive(Clone, Copy, Debug, PartialEq, Eq)]
253pub enum UsbClkSrc { 253pub enum UsbClkSrc {
254 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB.0, 254 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
255 PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0, 255 PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _,
256 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0, 256 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _,
257 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0, 257 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _,
258 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0, 258 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
259 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0, 259 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
260} 260}
261 261
262pub struct UsbClkConfig { 262pub struct UsbClkConfig {
@@ -269,12 +269,12 @@ pub struct UsbClkConfig {
269#[non_exhaustive] 269#[non_exhaustive]
270#[derive(Clone, Copy, Debug, PartialEq, Eq)] 270#[derive(Clone, Copy, Debug, PartialEq, Eq)]
271pub enum AdcClkSrc { 271pub enum AdcClkSrc {
272 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB.0, 272 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
273 PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0, 273 PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
274 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0, 274 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
275 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0, 275 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _,
276 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0, 276 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
277 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0, 277 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
278} 278}
279 279
280pub struct AdcClkConfig { 280pub struct AdcClkConfig {
@@ -287,12 +287,12 @@ pub struct AdcClkConfig {
287#[non_exhaustive] 287#[non_exhaustive]
288#[derive(Clone, Copy, Debug, PartialEq, Eq)] 288#[derive(Clone, Copy, Debug, PartialEq, Eq)]
289pub enum RtcClkSrc { 289pub enum RtcClkSrc {
290 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB.0, 290 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _,
291 PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0, 291 PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
292 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0, 292 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
293 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0, 293 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _,
294 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0, 294 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
295 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0, 295 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
296} 296}
297 297
298pub struct RtcClkConfig { 298pub struct RtcClkConfig {
@@ -396,7 +396,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
396 w.set_src(ref_src); 396 w.set_src(ref_src);
397 w.set_auxsrc(ref_aux); 397 w.set_auxsrc(ref_aux);
398 }); 398 });
399 while c.clk_ref_selected().read() != 1 << ref_src.0 {} 399 while c.clk_ref_selected().read() != 1 << ref_src as u32 {}
400 c.clk_ref_div().write(|w| { 400 c.clk_ref_div().write(|w| {
401 w.set_int(config.ref_clk.div); 401 w.set_int(config.ref_clk.div);
402 }); 402 });
@@ -425,13 +425,13 @@ pub(crate) unsafe fn init(config: ClockConfig) {
425 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); 425 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
426 if sys_src != ClkSysCtrlSrc::CLK_REF { 426 if sys_src != ClkSysCtrlSrc::CLK_REF {
427 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); 427 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
428 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} 428 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {}
429 } 429 }
430 c.clk_sys_ctrl().write(|w| { 430 c.clk_sys_ctrl().write(|w| {
431 w.set_auxsrc(sys_aux); 431 w.set_auxsrc(sys_aux);
432 w.set_src(sys_src); 432 w.set_src(sys_src);
433 }); 433 });
434 while c.clk_sys_selected().read() != 1 << sys_src.0 {} 434 while c.clk_sys_selected().read() != 1 << sys_src as u32 {}
435 c.clk_sys_div().write(|w| { 435 c.clk_sys_div().write(|w| {
436 w.set_int(config.sys_clk.div_int); 436 w.set_int(config.sys_clk.div_int);
437 w.set_frac(config.sys_clk.div_frac); 437 w.set_frac(config.sys_clk.div_frac);
@@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
442 if let Some(src) = config.peri_clk_src { 442 if let Some(src) = config.peri_clk_src {
443 c.clk_peri_ctrl().write(|w| { 443 c.clk_peri_ctrl().write(|w| {
444 w.set_enable(true); 444 w.set_enable(true);
445 w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _)); 445 w.set_auxsrc(ClkPeriCtrlAuxsrc::from_bits(src as _));
446 }); 446 });
447 let peri_freq = match src { 447 let peri_freq = match src {
448 PeriClkSrc::Sys => clk_sys_freq, 448 PeriClkSrc::Sys => clk_sys_freq,
@@ -468,7 +468,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
468 c.clk_usb_ctrl().write(|w| { 468 c.clk_usb_ctrl().write(|w| {
469 w.set_phase(conf.phase); 469 w.set_phase(conf.phase);
470 w.set_enable(true); 470 w.set_enable(true);
471 w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _)); 471 w.set_auxsrc(ClkUsbCtrlAuxsrc::from_bits(conf.src as _));
472 }); 472 });
473 let usb_freq = match conf.src { 473 let usb_freq = match conf.src {
474 UsbClkSrc::PllUsb => pll_usb_freq, 474 UsbClkSrc::PllUsb => pll_usb_freq,
@@ -491,7 +491,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
491 c.clk_adc_ctrl().write(|w| { 491 c.clk_adc_ctrl().write(|w| {
492 w.set_phase(conf.phase); 492 w.set_phase(conf.phase);
493 w.set_enable(true); 493 w.set_enable(true);
494 w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _)); 494 w.set_auxsrc(ClkAdcCtrlAuxsrc::from_bits(conf.src as _));
495 }); 495 });
496 let adc_in_freq = match conf.src { 496 let adc_in_freq = match conf.src {
497 AdcClkSrc::PllUsb => pll_usb_freq, 497 AdcClkSrc::PllUsb => pll_usb_freq,
@@ -517,7 +517,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
517 c.clk_rtc_ctrl().write(|w| { 517 c.clk_rtc_ctrl().write(|w| {
518 w.set_phase(conf.phase); 518 w.set_phase(conf.phase);
519 w.set_enable(true); 519 w.set_enable(true);
520 w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _)); 520 w.set_auxsrc(ClkRtcCtrlAuxsrc::from_bits(conf.src as _));
521 }); 521 });
522 let rtc_in_freq = match conf.src { 522 let rtc_in_freq = match conf.src {
523 RtcClkSrc::PllUsb => pll_usb_freq, 523 RtcClkSrc::PllUsb => pll_usb_freq,
@@ -542,7 +542,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
542 reset::unreset_wait(peris); 542 reset::unreset_wait(peris);
543} 543}
544 544
545unsafe fn configure_rosc(config: RoscConfig) -> u32 { 545fn configure_rosc(config: RoscConfig) -> u32 {
546 let p = pac::ROSC; 546 let p = pac::ROSC;
547 547
548 p.freqa().write(|w| { 548 p.freqa().write(|w| {
@@ -620,7 +620,7 @@ pub fn clk_rtc_freq() -> u16 {
620 CLOCKS.rtc.load(Ordering::Relaxed) 620 CLOCKS.rtc.load(Ordering::Relaxed)
621} 621}
622 622
623unsafe fn start_xosc(crystal_hz: u32) { 623fn start_xosc(crystal_hz: u32) {
624 pac::XOSC 624 pac::XOSC
625 .ctrl() 625 .ctrl()
626 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); 626 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
@@ -635,7 +635,7 @@ unsafe fn start_xosc(crystal_hz: u32) {
635} 635}
636 636
637#[inline(always)] 637#[inline(always)]
638unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { 638fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
639 let ref_freq = input_freq / config.refdiv as u32; 639 let ref_freq = input_freq / config.refdiv as u32;
640 assert!(config.fbdiv >= 16 && config.fbdiv <= 320); 640 assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
641 assert!(config.post_div1 >= 1 && config.post_div1 <= 7); 641 assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
@@ -700,9 +700,7 @@ impl<'d, T: Pin> Gpin<'d, T> {
700 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { 700 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> {
701 into_ref!(gpin); 701 into_ref!(gpin);
702 702
703 unsafe { 703 gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
704 gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
705 }
706 704
707 Gpin { 705 Gpin {
708 gpin: gpin.map_into(), 706 gpin: gpin.map_into(),
@@ -717,12 +715,10 @@ impl<'d, T: Pin> Gpin<'d, T> {
717 715
718impl<'d, T: Pin> Drop for Gpin<'d, T> { 716impl<'d, T: Pin> Drop for Gpin<'d, T> {
719 fn drop(&mut self) { 717 fn drop(&mut self) {
720 unsafe { 718 self.gpin
721 self.gpin 719 .io()
722 .io() 720 .ctrl()
723 .ctrl() 721 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _));
724 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
725 }
726 } 722 }
727} 723}
728 724
@@ -747,17 +743,17 @@ impl_gpoutpin!(PIN_25, 3);
747 743
748#[repr(u8)] 744#[repr(u8)]
749pub enum GpoutSrc { 745pub enum GpoutSrc {
750 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0, 746 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _,
751 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0, 747 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
752 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0, 748 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
753 PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0, 749 PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _,
754 Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0, 750 Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _,
755 Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0, 751 Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _,
756 Sys = ClkGpoutCtrlAuxsrc::CLK_SYS.0, 752 Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _,
757 Usb = ClkGpoutCtrlAuxsrc::CLK_USB.0, 753 Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _,
758 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC.0, 754 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _,
759 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC.0, 755 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
760 Ref = ClkGpoutCtrlAuxsrc::CLK_REF.0, 756 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _,
761} 757}
762 758
763pub struct Gpout<'d, T: GpoutPin> { 759pub struct Gpout<'d, T: GpoutPin> {
@@ -768,53 +764,43 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
768 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { 764 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self {
769 into_ref!(gpout); 765 into_ref!(gpout);
770 766
771 unsafe { 767 gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
772 gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
773 }
774 768
775 Self { gpout } 769 Self { gpout }
776 } 770 }
777 771
778 pub fn set_div(&self, int: u32, frac: u8) { 772 pub fn set_div(&self, int: u32, frac: u8) {
779 unsafe { 773 let c = pac::CLOCKS;
780 let c = pac::CLOCKS; 774 c.clk_gpout_div(self.gpout.number()).write(|w| {
781 c.clk_gpout_div(self.gpout.number()).write(|w| { 775 w.set_int(int);
782 w.set_int(int); 776 w.set_frac(frac);
783 w.set_frac(frac); 777 });
784 });
785 }
786 } 778 }
787 779
788 pub fn set_src(&self, src: GpoutSrc) { 780 pub fn set_src(&self, src: GpoutSrc) {
789 unsafe { 781 let c = pac::CLOCKS;
790 let c = pac::CLOCKS; 782 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
791 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 783 w.set_auxsrc(ClkGpoutCtrlAuxsrc::from_bits(src as _));
792 w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); 784 });
793 });
794 }
795 } 785 }
796 786
797 pub fn enable(&self) { 787 pub fn enable(&self) {
798 unsafe { 788 let c = pac::CLOCKS;
799 let c = pac::CLOCKS; 789 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
800 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 790 w.set_enable(true);
801 w.set_enable(true); 791 });
802 });
803 }
804 } 792 }
805 793
806 pub fn disable(&self) { 794 pub fn disable(&self) {
807 unsafe { 795 let c = pac::CLOCKS;
808 let c = pac::CLOCKS; 796 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
809 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 797 w.set_enable(false);
810 w.set_enable(false); 798 });
811 });
812 }
813 } 799 }
814 800
815 pub fn get_freq(&self) -> u32 { 801 pub fn get_freq(&self) -> u32 {
816 let c = pac::CLOCKS; 802 let c = pac::CLOCKS;
817 let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() }; 803 let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc();
818 804
819 let base = match src { 805 let base = match src {
820 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), 806 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
@@ -831,7 +817,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
831 _ => unreachable!(), 817 _ => unreachable!(),
832 }; 818 };
833 819
834 let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() }; 820 let div = c.clk_gpout_div(self.gpout.number()).read();
835 let int = if div.int() == 0 { 65536 } else { div.int() } as u64; 821 let int = if div.int() == 0 { 65536 } else { div.int() } as u64;
836 let frac = div.frac() as u64; 822 let frac = div.frac() as u64;
837 823
@@ -842,12 +828,10 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
842impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { 828impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
843 fn drop(&mut self) { 829 fn drop(&mut self) {
844 self.disable(); 830 self.disable();
845 unsafe { 831 self.gpout
846 self.gpout 832 .io()
847 .io() 833 .ctrl()
848 .ctrl() 834 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _));
849 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
850 }
851 } 835 }
852} 836}
853 837
@@ -864,7 +848,7 @@ impl RoscRng {
864 let mut acc = 0; 848 let mut acc = 0;
865 for _ in 0..u8::BITS { 849 for _ in 0..u8::BITS {
866 acc <<= 1; 850 acc <<= 1;
867 acc |= unsafe { random_reg.read().randombit() as u8 }; 851 acc |= random_reg.read().randombit() as u8;
868 } 852 }
869 acc 853 acc
870 } 854 }
diff --git a/embassy-rp/src/critical_section_impl.rs b/embassy-rp/src/critical_section_impl.rs
index ce284c856..d233e6fab 100644
--- a/embassy-rp/src/critical_section_impl.rs
+++ b/embassy-rp/src/critical_section_impl.rs
@@ -103,14 +103,11 @@ where
103 /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is 103 /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is
104 /// already in use somewhere else. 104 /// already in use somewhere else.
105 pub fn try_claim() -> Option<Self> { 105 pub fn try_claim() -> Option<Self> {
106 // Safety: We're only reading from this register 106 let lock = pac::SIO.spinlock(N).read();
107 unsafe { 107 if lock > 0 {
108 let lock = pac::SIO.spinlock(N).read(); 108 Some(Self(core::marker::PhantomData))
109 if lock > 0 { 109 } else {
110 Some(Self(core::marker::PhantomData)) 110 None
111 } else {
112 None
113 }
114 } 111 }
115 } 112 }
116 113
@@ -120,10 +117,8 @@ where
120 /// 117 ///
121 /// Only call this function if you hold the spin-lock. 118 /// Only call this function if you hold the spin-lock.
122 pub unsafe fn release() { 119 pub unsafe fn release() {
123 unsafe { 120 // Write (any value): release the lock
124 // Write (any value): release the lock 121 pac::SIO.spinlock(N).write_value(1);
125 pac::SIO.spinlock(N).write_value(1);
126 }
127 } 122 }
128} 123}
129 124
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 74f4e6998..1a458778c 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -4,16 +4,17 @@ use core::pin::Pin;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
6 6
7use embassy_cortex_m::interrupt::Interrupt;
8use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; 7use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
10use pac::dma::vals::DataSize; 9use pac::dma::vals::DataSize;
11 10
11use crate::interrupt::InterruptExt;
12use crate::pac::dma::vals; 12use crate::pac::dma::vals;
13use crate::{interrupt, pac, peripherals}; 13use crate::{interrupt, pac, peripherals};
14 14
15#[cfg(feature = "rt")]
15#[interrupt] 16#[interrupt]
16unsafe fn DMA_IRQ_0() { 17fn DMA_IRQ_0() {
17 let ints0 = pac::DMA.ints0().read().ints0(); 18 let ints0 = pac::DMA.ints0().read().ints0();
18 for channel in 0..CHANNEL_COUNT { 19 for channel in 0..CHANNEL_COUNT {
19 let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); 20 let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read();
@@ -29,12 +30,12 @@ unsafe fn DMA_IRQ_0() {
29} 30}
30 31
31pub(crate) unsafe fn init() { 32pub(crate) unsafe fn init() {
32 interrupt::DMA_IRQ_0::disable(); 33 interrupt::DMA_IRQ_0.disable();
33 interrupt::DMA_IRQ_0::set_priority(interrupt::Priority::P3); 34 interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3);
34 35
35 pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF)); 36 pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF));
36 37
37 interrupt::DMA_IRQ_0::enable(); 38 interrupt::DMA_IRQ_0.enable();
38} 39}
39 40
40pub unsafe fn read<'a, C: Channel, W: Word>( 41pub unsafe fn read<'a, C: Channel, W: Word>(
@@ -75,16 +76,17 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
75 ) 76 )
76} 77}
77 78
79static DUMMY: u32 = 0;
80
78pub unsafe fn write_repeated<'a, C: Channel, W: Word>( 81pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
79 ch: impl Peripheral<P = C> + 'a, 82 ch: impl Peripheral<P = C> + 'a,
80 to: *mut W, 83 to: *mut W,
81 len: usize, 84 len: usize,
82 dreq: u8, 85 dreq: u8,
83) -> Transfer<'a, C> { 86) -> Transfer<'a, C> {
84 let dummy: u32 = 0;
85 copy_inner( 87 copy_inner(
86 ch, 88 ch,
87 &dummy as *const u32, 89 &DUMMY as *const u32,
88 to as *mut u32, 90 to as *mut u32,
89 len, 91 len,
90 W::size(), 92 W::size(),
@@ -126,28 +128,26 @@ fn copy_inner<'a, C: Channel>(
126) -> Transfer<'a, C> { 128) -> Transfer<'a, C> {
127 into_ref!(ch); 129 into_ref!(ch);
128 130
129 unsafe { 131 let p = ch.regs();
130 let p = ch.regs();
131 132
132 p.read_addr().write_value(from as u32); 133 p.read_addr().write_value(from as u32);
133 p.write_addr().write_value(to as u32); 134 p.write_addr().write_value(to as u32);
134 p.trans_count().write_value(len as u32); 135 p.trans_count().write_value(len as u32);
135 136
136 compiler_fence(Ordering::SeqCst); 137 compiler_fence(Ordering::SeqCst);
137 138
138 p.ctrl_trig().write(|w| { 139 p.ctrl_trig().write(|w| {
139 // TODO: Add all DREQ options to pac vals::TreqSel, and use 140 // TODO: Add all DREQ options to pac vals::TreqSel, and use
140 // `set_treq:sel` 141 // `set_treq:sel`
141 w.0 = ((dreq as u32) & 0x3f) << 15usize; 142 w.0 = ((dreq as u32) & 0x3f) << 15usize;
142 w.set_data_size(data_size); 143 w.set_data_size(data_size);
143 w.set_incr_read(incr_read); 144 w.set_incr_read(incr_read);
144 w.set_incr_write(incr_write); 145 w.set_incr_write(incr_write);
145 w.set_chain_to(ch.number()); 146 w.set_chain_to(ch.number());
146 w.set_en(true); 147 w.set_en(true);
147 }); 148 });
148 149
149 compiler_fence(Ordering::SeqCst); 150 compiler_fence(Ordering::SeqCst);
150 }
151 Transfer::new(ch) 151 Transfer::new(ch)
152} 152}
153 153
@@ -167,12 +167,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
167impl<'a, C: Channel> Drop for Transfer<'a, C> { 167impl<'a, C: Channel> Drop for Transfer<'a, C> {
168 fn drop(&mut self) { 168 fn drop(&mut self) {
169 let p = self.channel.regs(); 169 let p = self.channel.regs();
170 unsafe { 170 pac::DMA
171 pac::DMA 171 .chan_abort()
172 .chan_abort() 172 .modify(|m| m.set_chan_abort(1 << self.channel.number()));
173 .modify(|m| m.set_chan_abort(1 << self.channel.number())); 173 while p.ctrl_trig().read().busy() {}
174 while p.ctrl_trig().read().busy() {}
175 }
176 } 174 }
177} 175}
178 176
@@ -184,7 +182,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
184 // calls to wake will deregister the waker. 182 // calls to wake will deregister the waker.
185 CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); 183 CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
186 184
187 if unsafe { self.channel.regs().ctrl_trig().read().busy() } { 185 if self.channel.regs().ctrl_trig().read().busy() {
188 Poll::Pending 186 Poll::Pending
189 } else { 187 } else {
190 Poll::Ready(()) 188 Poll::Ready(())
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 0410429e0..96d2d4541 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -9,7 +9,11 @@ use embedded_storage::nor_flash::{
9use crate::pac; 9use crate::pac;
10use crate::peripherals::FLASH; 10use crate::peripherals::FLASH;
11 11
12pub const FLASH_BASE: usize = 0x10000000; 12pub const FLASH_BASE: *const u32 = 0x10000000 as _;
13
14// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
15// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
16pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram");
13 17
14// **NOTE**: 18// **NOTE**:
15// 19//
@@ -63,8 +67,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
63 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 67 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
64 trace!( 68 trace!(
65 "Reading from 0x{:x} to 0x{:x}", 69 "Reading from 0x{:x} to 0x{:x}",
66 FLASH_BASE + offset as usize, 70 FLASH_BASE as u32 + offset,
67 FLASH_BASE + offset as usize + bytes.len() 71 FLASH_BASE as u32 + offset + bytes.len() as u32
68 ); 72 );
69 check_read(self, offset, bytes.len())?; 73 check_read(self, offset, bytes.len())?;
70 74
@@ -89,7 +93,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
89 93
90 let len = to - from; 94 let len = to - from;
91 95
92 unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true))? }; 96 unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? };
93 97
94 Ok(()) 98 Ok(())
95 } 99 }
@@ -114,7 +118,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
114 118
115 let unaligned_offset = offset as usize - start; 119 let unaligned_offset = offset as usize - start;
116 120
117 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } 121 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
118 } 122 }
119 123
120 let remaining_len = bytes.len() - start_padding; 124 let remaining_len = bytes.len() - start_padding;
@@ -132,12 +136,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
132 if bytes.as_ptr() as usize >= 0x2000_0000 { 136 if bytes.as_ptr() as usize >= 0x2000_0000 {
133 let aligned_data = &bytes[start_padding..end_padding]; 137 let aligned_data = &bytes[start_padding..end_padding];
134 138
135 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true))? } 139 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
136 } else { 140 } else {
137 for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) { 141 for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
138 let mut ram_buf = [0xFF_u8; PAGE_SIZE]; 142 let mut ram_buf = [0xFF_u8; PAGE_SIZE];
139 ram_buf.copy_from_slice(chunk); 143 ram_buf.copy_from_slice(chunk);
140 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf, true))? } 144 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
141 aligned_offset += PAGE_SIZE; 145 aligned_offset += PAGE_SIZE;
142 } 146 }
143 } 147 }
@@ -152,7 +156,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
152 156
153 let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset); 157 let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
154 158
155 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } 159 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
156 } 160 }
157 161
158 Ok(()) 162 Ok(())
@@ -163,7 +167,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
163 /// - DMA must not access flash memory 167 /// - DMA must not access flash memory
164 unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { 168 unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> {
165 // Make sure we're running on CORE0 169 // Make sure we're running on CORE0
166 let core_id: u32 = unsafe { pac::SIO.cpuid().read() }; 170 let core_id: u32 = pac::SIO.cpuid().read();
167 if core_id != 0 { 171 if core_id != 0 {
168 return Err(Error::InvalidCore); 172 return Err(Error::InvalidCore);
169 } 173 }
@@ -190,7 +194,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
190 194
191 /// Read SPI flash unique ID 195 /// Read SPI flash unique ID
192 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { 196 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
193 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid, true))? }; 197 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
194 Ok(()) 198 Ok(())
195 } 199 }
196 200
@@ -199,7 +203,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
199 let mut jedec = None; 203 let mut jedec = None;
200 unsafe { 204 unsafe {
201 self.in_ram(|| { 205 self.in_ram(|| {
202 jedec.replace(ram_helpers::flash_jedec_id(true)); 206 jedec.replace(ram_helpers::flash_jedec_id());
203 })?; 207 })?;
204 }; 208 };
205 Ok(jedec.unwrap()) 209 Ok(jedec.unwrap())
@@ -242,6 +246,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S
242mod ram_helpers { 246mod ram_helpers {
243 use core::marker::PhantomData; 247 use core::marker::PhantomData;
244 248
249 use super::*;
245 use crate::rom_data; 250 use crate::rom_data;
246 251
247 #[repr(C)] 252 #[repr(C)]
@@ -306,7 +311,7 @@ mod ram_helpers {
306 /// 311 ///
307 /// `addr` and `len` must be multiples of 4096 312 /// `addr` and `len` must be multiples of 4096
308 /// 313 ///
309 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 314 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
310 /// is used to re-initialize the XIP engine after flashing. 315 /// is used to re-initialize the XIP engine after flashing.
311 /// 316 ///
312 /// # Safety 317 /// # Safety
@@ -318,10 +323,10 @@ mod ram_helpers {
318 /// - DMA must not access flash memory 323 /// - DMA must not access flash memory
319 /// 324 ///
320 /// `addr` and `len` parameters must be valid and are not checked. 325 /// `addr` and `len` parameters must be valid and are not checked.
321 pub unsafe fn flash_range_erase(addr: u32, len: u32, use_boot2: bool) { 326 pub unsafe fn flash_range_erase(addr: u32, len: u32) {
322 let mut boot2 = [0u32; 256 / 4]; 327 let mut boot2 = [0u32; 256 / 4];
323 let ptrs = if use_boot2 { 328 let ptrs = if USE_BOOT2 {
324 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 329 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
325 flash_function_pointers_with_boot2(true, false, &boot2) 330 flash_function_pointers_with_boot2(true, false, &boot2)
326 } else { 331 } else {
327 flash_function_pointers(true, false) 332 flash_function_pointers(true, false)
@@ -336,7 +341,7 @@ mod ram_helpers {
336 /// 341 ///
337 /// `addr` and `data.len()` must be multiples of 4096 342 /// `addr` and `data.len()` must be multiples of 4096
338 /// 343 ///
339 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 344 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
340 /// is used to re-initialize the XIP engine after flashing. 345 /// is used to re-initialize the XIP engine after flashing.
341 /// 346 ///
342 /// # Safety 347 /// # Safety
@@ -348,10 +353,10 @@ mod ram_helpers {
348 /// - DMA must not access flash memory 353 /// - DMA must not access flash memory
349 /// 354 ///
350 /// `addr` and `len` parameters must be valid and are not checked. 355 /// `addr` and `len` parameters must be valid and are not checked.
351 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8], use_boot2: bool) { 356 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
352 let mut boot2 = [0u32; 256 / 4]; 357 let mut boot2 = [0u32; 256 / 4];
353 let ptrs = if use_boot2 { 358 let ptrs = if USE_BOOT2 {
354 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 359 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
355 flash_function_pointers_with_boot2(true, true, &boot2) 360 flash_function_pointers_with_boot2(true, true, &boot2)
356 } else { 361 } else {
357 flash_function_pointers(true, true) 362 flash_function_pointers(true, true)
@@ -371,7 +376,7 @@ mod ram_helpers {
371 /// 376 ///
372 /// `addr` and `data.len()` must be multiples of 256 377 /// `addr` and `data.len()` must be multiples of 256
373 /// 378 ///
374 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 379 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
375 /// is used to re-initialize the XIP engine after flashing. 380 /// is used to re-initialize the XIP engine after flashing.
376 /// 381 ///
377 /// # Safety 382 /// # Safety
@@ -383,10 +388,10 @@ mod ram_helpers {
383 /// - DMA must not access flash memory 388 /// - DMA must not access flash memory
384 /// 389 ///
385 /// `addr` and `len` parameters must be valid and are not checked. 390 /// `addr` and `len` parameters must be valid and are not checked.
386 pub unsafe fn flash_range_program(addr: u32, data: &[u8], use_boot2: bool) { 391 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
387 let mut boot2 = [0u32; 256 / 4]; 392 let mut boot2 = [0u32; 256 / 4];
388 let ptrs = if use_boot2 { 393 let ptrs = if USE_BOOT2 {
389 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 394 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
390 flash_function_pointers_with_boot2(false, true, &boot2) 395 flash_function_pointers_with_boot2(false, true, &boot2)
391 } else { 396 } else {
392 flash_function_pointers(false, true) 397 flash_function_pointers(false, true)
@@ -508,10 +513,10 @@ mod ram_helpers {
508 /// - DMA must not access flash memory 513 /// - DMA must not access flash memory
509 /// 514 ///
510 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 515 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
511 pub unsafe fn flash_unique_id(out: &mut [u8], use_boot2: bool) { 516 pub unsafe fn flash_unique_id(out: &mut [u8]) {
512 let mut boot2 = [0u32; 256 / 4]; 517 let mut boot2 = [0u32; 256 / 4];
513 let ptrs = if use_boot2 { 518 let ptrs = if USE_BOOT2 {
514 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); 519 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
515 flash_function_pointers_with_boot2(false, false, &boot2) 520 flash_function_pointers_with_boot2(false, false, &boot2)
516 } else { 521 } else {
517 flash_function_pointers(false, false) 522 flash_function_pointers(false, false)
@@ -536,10 +541,10 @@ mod ram_helpers {
536 /// - DMA must not access flash memory 541 /// - DMA must not access flash memory
537 /// 542 ///
538 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 543 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
539 pub unsafe fn flash_jedec_id(use_boot2: bool) -> u32 { 544 pub unsafe fn flash_jedec_id() -> u32 {
540 let mut boot2 = [0u32; 256 / 4]; 545 let mut boot2 = [0u32; 256 / 4];
541 let ptrs = if use_boot2 { 546 let ptrs = if USE_BOOT2 {
542 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); 547 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
543 flash_function_pointers_with_boot2(false, false, &boot2) 548 flash_function_pointers_with_boot2(false, false, &boot2)
544 } else { 549 } else {
545 flash_function_pointers(false, false) 550 flash_function_pointers(false, false)
@@ -586,7 +591,6 @@ mod ram_helpers {
586 "ldr r4, [r5, #4]", 591 "ldr r4, [r5, #4]",
587 "blx r4", // flash_exit_xip() 592 "blx r4", // flash_exit_xip()
588 593
589 "mov r7, r10", // cmd
590 594
591 "movs r4, #0x18", 595 "movs r4, #0x18",
592 "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13 596 "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
@@ -603,8 +607,9 @@ mod ram_helpers {
603 "str r1, [r4, #0]", 607 "str r1, [r4, #0]",
604 608
605 // Write ctrlr1 with len-1 609 // Write ctrlr1 with len-1
606 "ldr r0, [r7, #8]", // dummy_len 610 "mov r3, r10", // cmd
607 "ldr r1, [r7, #16]", // data_len 611 "ldr r0, [r3, #8]", // dummy_len
612 "ldr r1, [r3, #16]", // data_len
608 "add r0, r1", 613 "add r0, r1",
609 "subs r0, #1", 614 "subs r0, #1",
610 "str r0, [r4, #0x04]", // CTRLR1 615 "str r0, [r4, #0x04]", // CTRLR1
@@ -616,8 +621,8 @@ mod ram_helpers {
616 // Write cmd/addr phase to DR 621 // Write cmd/addr phase to DR
617 "mov r2, r4", 622 "mov r2, r4",
618 "adds r2, 0x60", // &DR 623 "adds r2, 0x60", // &DR
619 "ldr r0, [r7, #0]", // cmd_addr 624 "ldr r0, [r3, #0]", // cmd_addr
620 "ldr r1, [r7, #4]", // cmd_addr_len 625 "ldr r1, [r3, #4]", // cmd_addr_len
621 "10:", 626 "10:",
622 "ldrb r3, [r0]", 627 "ldrb r3, [r0]",
623 "strb r3, [r2]", // DR 628 "strb r3, [r2]", // DR
@@ -626,7 +631,8 @@ mod ram_helpers {
626 "bne 10b", 631 "bne 10b",
627 632
628 // Skip any dummy cycles 633 // Skip any dummy cycles
629 "ldr r1, [r7, #8]", // dummy_len 634 "mov r3, r10", // cmd
635 "ldr r1, [r3, #8]", // dummy_len
630 "cmp r1, #0", 636 "cmp r1, #0",
631 "beq 9f", 637 "beq 9f",
632 "4:", 638 "4:",
@@ -643,8 +649,9 @@ mod ram_helpers {
643 649
644 // Read RX fifo 650 // Read RX fifo
645 "9:", 651 "9:",
646 "ldr r0, [r7, #12]", // data 652 "mov r2, r10", // cmd
647 "ldr r1, [r7, #16]", // data_len 653 "ldr r0, [r2, #12]", // data
654 "ldr r1, [r2, #16]", // data_len
648 655
649 "2:", 656 "2:",
650 "ldr r3, [r4, #0x28]", // SR 657 "ldr r3, [r4, #0x28]", // SR
@@ -678,13 +685,12 @@ mod ram_helpers {
678 out("r2") _, 685 out("r2") _,
679 out("r3") _, 686 out("r3") _,
680 out("r4") _, 687 out("r4") _,
688 out("r5") _,
681 // Registers r8-r10 are used to store values 689 // Registers r8-r10 are used to store values
682 // from r0-r2 in registers not clobbered by 690 // from r0-r2 in registers not clobbered by
683 // function calls. 691 // function calls.
684 // The values can't be passed in using r8-r10 directly 692 // The values can't be passed in using r8-r10 directly
685 // due to https://github.com/rust-lang/rust/issues/99071 693 // due to https://github.com/rust-lang/rust/issues/99071
686 out("r8") _,
687 out("r9") _,
688 out("r10") _, 694 out("r10") _,
689 clobber_abi("C"), 695 clobber_abi("C"),
690 ); 696 );
diff --git a/embassy-rp/src/float/div.rs b/embassy-rp/src/float/div.rs
index 094dec446..aff0dcb07 100644
--- a/embassy-rp/src/float/div.rs
+++ b/embassy-rp/src/float/div.rs
@@ -17,45 +17,43 @@ where
17{ 17{
18 let sio = rp_pac::SIO; 18 let sio = rp_pac::SIO;
19 19
20 unsafe { 20 // Since we can't save the signed-ness of the calculation, we have to make
21 // Since we can't save the signed-ness of the calculation, we have to make 21 // sure that there's at least an 8 cycle delay before we read the result.
22 // sure that there's at least an 8 cycle delay before we read the result. 22 // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
23 // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads. 23 // Since we can't be sure the Rust implementation will optimize to the same,
24 // Since we can't be sure the Rust implementation will optimize to the same, 24 // just use an explicit wait.
25 // just use an explicit wait. 25 while !sio.div().csr().read().ready() {}
26 while !sio.div().csr().read().ready() {} 26
27 27 // Read the quotient last, since that's what clears the dirty flag
28 // Read the quotient last, since that's what clears the dirty flag 28 let dividend = sio.div().udividend().read();
29 let dividend = sio.div().udividend().read(); 29 let divisor = sio.div().udivisor().read();
30 let divisor = sio.div().udivisor().read(); 30 let remainder = sio.div().remainder().read();
31 let remainder = sio.div().remainder().read(); 31 let quotient = sio.div().quotient().read();
32 let quotient = sio.div().quotient().read(); 32
33 33 // If we get interrupted here (before a write sets the DIRTY flag) its fine, since
34 // If we get interrupted here (before a write sets the DIRTY flag) its fine, since 34 // we have the full state, so the interruptor doesn't have to restore it. Once the
35 // we have the full state, so the interruptor doesn't have to restore it. Once the 35 // write happens and the DIRTY flag is set, the interruptor becomes responsible for
36 // write happens and the DIRTY flag is set, the interruptor becomes responsible for 36 // restoring our state.
37 // restoring our state. 37 let result = f();
38 let result = f(); 38
39 39 // If we are interrupted here, then the interruptor will start an incorrect calculation
40 // If we are interrupted here, then the interruptor will start an incorrect calculation 40 // using a wrong divisor, but we'll restore the divisor and result ourselves correctly.
41 // using a wrong divisor, but we'll restore the divisor and result ourselves correctly. 41 // This sets DIRTY, so any interruptor will save the state.
42 // This sets DIRTY, so any interruptor will save the state. 42 sio.div().udividend().write_value(dividend);
43 sio.div().udividend().write_value(dividend); 43 // If we are interrupted here, the the interruptor may start the calculation using
44 // If we are interrupted here, the the interruptor may start the calculation using 44 // incorrectly signed inputs, but we'll restore the result ourselves.
45 // incorrectly signed inputs, but we'll restore the result ourselves. 45 // This sets DIRTY, so any interruptor will save the state.
46 // This sets DIRTY, so any interruptor will save the state. 46 sio.div().udivisor().write_value(divisor);
47 sio.div().udivisor().write_value(divisor); 47 // If we are interrupted here, the interruptor will have restored everything but the
48 // If we are interrupted here, the interruptor will have restored everything but the 48 // quotient may be wrongly signed. If the calculation started by the above writes is
49 // quotient may be wrongly signed. If the calculation started by the above writes is 49 // still ongoing it is stopped, so it won't replace the result we're restoring.
50 // still ongoing it is stopped, so it won't replace the result we're restoring. 50 // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state.
51 // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state. 51 sio.div().remainder().write_value(remainder);
52 sio.div().remainder().write_value(remainder); 52 // State fully restored after the quotient write. This sets both DIRTY and READY, so
53 // State fully restored after the quotient write. This sets both DIRTY and READY, so 53 // whatever we may have interrupted can read the result.
54 // whatever we may have interrupted can read the result. 54 sio.div().quotient().write_value(quotient);
55 sio.div().quotient().write_value(quotient); 55
56 56 result
57 result
58 }
59} 57}
60 58
61fn save_divider<F, R>(f: F) -> R 59fn save_divider<F, R>(f: F) -> R
@@ -63,7 +61,7 @@ where
63 F: FnOnce() -> R, 61 F: FnOnce() -> R,
64{ 62{
65 let sio = rp_pac::SIO; 63 let sio = rp_pac::SIO;
66 if unsafe { !sio.div().csr().read().dirty() } { 64 if !sio.div().csr().read().dirty() {
67 // Not dirty, so nothing is waiting for the calculation. So we can just 65 // Not dirty, so nothing is waiting for the calculation. So we can just
68 // issue it directly without a save/restore. 66 // issue it directly without a save/restore.
69 f() 67 f()
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 91cef8609..f8048a4dd 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -3,10 +3,10 @@ use core::future::Future;
3use core::pin::Pin as FuturePin; 3use core::pin::Pin as FuturePin;
4use core::task::{Context, Poll}; 4use core::task::{Context, Poll};
5 5
6use embassy_cortex_m::interrupt::Interrupt;
7use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; 6use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9 8
9use crate::interrupt::InterruptExt;
10use crate::pac::common::{Reg, RW}; 10use crate::pac::common::{Reg, RW};
11use crate::pac::SIO; 11use crate::pac::SIO;
12use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; 12use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
@@ -137,13 +137,14 @@ pub enum InterruptTrigger {
137} 137}
138 138
139pub(crate) unsafe fn init() { 139pub(crate) unsafe fn init() {
140 interrupt::IO_IRQ_BANK0::disable(); 140 interrupt::IO_IRQ_BANK0.disable();
141 interrupt::IO_IRQ_BANK0::set_priority(interrupt::Priority::P3); 141 interrupt::IO_IRQ_BANK0.set_priority(interrupt::Priority::P3);
142 interrupt::IO_IRQ_BANK0::enable(); 142 interrupt::IO_IRQ_BANK0.enable();
143} 143}
144 144
145#[cfg(feature = "rt")]
145#[interrupt] 146#[interrupt]
146unsafe fn IO_IRQ_BANK0() { 147fn IO_IRQ_BANK0() {
147 let cpu = SIO.cpuid().read() as usize; 148 let cpu = SIO.cpuid().read() as usize;
148 // There are two sets of interrupt registers, one for cpu0 and one for cpu1 149 // There are two sets of interrupt registers, one for cpu0 and one for cpu1
149 // and here we are selecting the set that belongs to the currently executing 150 // and here we are selecting the set that belongs to the currently executing
@@ -184,47 +185,45 @@ struct InputFuture<'a, T: Pin> {
184impl<'d, T: Pin> InputFuture<'d, T> { 185impl<'d, T: Pin> InputFuture<'d, T> {
185 pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { 186 pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
186 into_ref!(pin); 187 into_ref!(pin);
187 unsafe { 188 let pin_group = (pin.pin() % 8) as usize;
188 let pin_group = (pin.pin() % 8) as usize; 189 // first, clear the INTR register bits. without this INTR will still
189 // first, clear the INTR register bits. without this INTR will still 190 // contain reports of previous edges, causing the IRQ to fire early
190 // contain reports of previous edges, causing the IRQ to fire early 191 // on stale state. clearing these means that we can only detect edges
191 // on stale state. clearing these means that we can only detect edges 192 // that occur *after* the clear happened, but since both this and the
192 // that occur *after* the clear happened, but since both this and the 193 // alternative are fundamentally racy it's probably fine.
193 // alternative are fundamentally racy it's probably fine. 194 // (the alternative being checking the current level and waiting for
194 // (the alternative being checking the current level and waiting for 195 // its inverse, but that requires reading the current level and thus
195 // its inverse, but that requires reading the current level and thus 196 // missing anything that happened before the level was read.)
196 // missing anything that happened before the level was read.) 197 pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| {
197 pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { 198 w.set_edge_high(pin_group, true);
198 w.set_edge_high(pin_group, true); 199 w.set_edge_low(pin_group, true);
199 w.set_edge_low(pin_group, true); 200 });
201
202 // Each INTR register is divided into 8 groups, one group for each
203 // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
204 // and EGDE_HIGH.
205 pin.int_proc()
206 .inte((pin.pin() / 8) as usize)
207 .write_set(|w| match level {
208 InterruptTrigger::LevelHigh => {
209 trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
210 w.set_level_high(pin_group, true);
211 }
212 InterruptTrigger::LevelLow => {
213 w.set_level_low(pin_group, true);
214 }
215 InterruptTrigger::EdgeHigh => {
216 w.set_edge_high(pin_group, true);
217 }
218 InterruptTrigger::EdgeLow => {
219 w.set_edge_low(pin_group, true);
220 }
221 InterruptTrigger::AnyEdge => {
222 w.set_edge_high(pin_group, true);
223 w.set_edge_low(pin_group, true);
224 }
200 }); 225 });
201 226
202 // Each INTR register is divided into 8 groups, one group for each
203 // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
204 // and EGDE_HIGH.
205 pin.int_proc()
206 .inte((pin.pin() / 8) as usize)
207 .write_set(|w| match level {
208 InterruptTrigger::LevelHigh => {
209 trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
210 w.set_level_high(pin_group, true);
211 }
212 InterruptTrigger::LevelLow => {
213 w.set_level_low(pin_group, true);
214 }
215 InterruptTrigger::EdgeHigh => {
216 w.set_edge_high(pin_group, true);
217 }
218 InterruptTrigger::EdgeLow => {
219 w.set_edge_low(pin_group, true);
220 }
221 InterruptTrigger::AnyEdge => {
222 w.set_edge_high(pin_group, true);
223 w.set_edge_low(pin_group, true);
224 }
225 });
226 }
227
228 Self { pin, level } 227 Self { pin, level }
229 } 228 }
230} 229}
@@ -241,7 +240,7 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
241 // then we want to access the interrupt enable register for our 240 // then we want to access the interrupt enable register for our
242 // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and 241 // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
243 // PROC0_INTE3 per cpu). 242 // PROC0_INTE3 per cpu).
244 let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() }; 243 let inte: pac::io::regs::Int = self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read();
245 // The register is divided into groups of four, one group for 244 // The register is divided into groups of four, one group for
246 // each pin. Each group consists of four trigger levels LEVEL_LOW, 245 // each pin. Each group consists of four trigger levels LEVEL_LOW,
247 // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. 246 // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
@@ -448,15 +447,13 @@ impl<'d, T: Pin> Flex<'d, T> {
448 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { 447 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self {
449 into_ref!(pin); 448 into_ref!(pin);
450 449
451 unsafe { 450 pin.pad_ctrl().write(|w| {
452 pin.pad_ctrl().write(|w| { 451 w.set_ie(true);
453 w.set_ie(true); 452 });
454 });
455 453
456 pin.io().ctrl().write(|w| { 454 pin.io().ctrl().write(|w| {
457 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); 455 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _);
458 }); 456 });
459 }
460 457
461 Self { pin } 458 Self { pin }
462 } 459 }
@@ -469,43 +466,37 @@ impl<'d, T: Pin> Flex<'d, T> {
469 /// Set the pin's pull. 466 /// Set the pin's pull.
470 #[inline] 467 #[inline]
471 pub fn set_pull(&mut self, pull: Pull) { 468 pub fn set_pull(&mut self, pull: Pull) {
472 unsafe { 469 self.pin.pad_ctrl().modify(|w| {
473 self.pin.pad_ctrl().modify(|w| { 470 w.set_ie(true);
474 w.set_ie(true); 471 let (pu, pd) = match pull {
475 let (pu, pd) = match pull { 472 Pull::Up => (true, false),
476 Pull::Up => (true, false), 473 Pull::Down => (false, true),
477 Pull::Down => (false, true), 474 Pull::None => (false, false),
478 Pull::None => (false, false), 475 };
479 }; 476 w.set_pue(pu);
480 w.set_pue(pu); 477 w.set_pde(pd);
481 w.set_pde(pd); 478 });
482 });
483 }
484 } 479 }
485 480
486 /// Set the pin's drive strength. 481 /// Set the pin's drive strength.
487 #[inline] 482 #[inline]
488 pub fn set_drive_strength(&mut self, strength: Drive) { 483 pub fn set_drive_strength(&mut self, strength: Drive) {
489 unsafe { 484 self.pin.pad_ctrl().modify(|w| {
490 self.pin.pad_ctrl().modify(|w| { 485 w.set_drive(match strength {
491 w.set_drive(match strength { 486 Drive::_2mA => pac::pads::vals::Drive::_2MA,
492 Drive::_2mA => pac::pads::vals::Drive::_2MA, 487 Drive::_4mA => pac::pads::vals::Drive::_4MA,
493 Drive::_4mA => pac::pads::vals::Drive::_4MA, 488 Drive::_8mA => pac::pads::vals::Drive::_8MA,
494 Drive::_8mA => pac::pads::vals::Drive::_8MA, 489 Drive::_12mA => pac::pads::vals::Drive::_12MA,
495 Drive::_12mA => pac::pads::vals::Drive::_12MA,
496 });
497 }); 490 });
498 } 491 });
499 } 492 }
500 493
501 // Set the pin's slew rate. 494 // Set the pin's slew rate.
502 #[inline] 495 #[inline]
503 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 496 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
504 unsafe { 497 self.pin.pad_ctrl().modify(|w| {
505 self.pin.pad_ctrl().modify(|w| { 498 w.set_slewfast(slew_rate == SlewRate::Fast);
506 w.set_slewfast(slew_rate == SlewRate::Fast); 499 });
507 });
508 }
509 } 500 }
510 501
511 /// Put the pin into input mode. 502 /// Put the pin into input mode.
@@ -513,7 +504,7 @@ impl<'d, T: Pin> Flex<'d, T> {
513 /// The pull setting is left unchanged. 504 /// The pull setting is left unchanged.
514 #[inline] 505 #[inline]
515 pub fn set_as_input(&mut self) { 506 pub fn set_as_input(&mut self) {
516 unsafe { self.pin.sio_oe().value_clr().write_value(self.bit()) } 507 self.pin.sio_oe().value_clr().write_value(self.bit())
517 } 508 }
518 509
519 /// Put the pin into output mode. 510 /// Put the pin into output mode.
@@ -522,17 +513,17 @@ impl<'d, T: Pin> Flex<'d, T> {
522 /// at a specific level, call `set_high`/`set_low` on the pin first. 513 /// at a specific level, call `set_high`/`set_low` on the pin first.
523 #[inline] 514 #[inline]
524 pub fn set_as_output(&mut self) { 515 pub fn set_as_output(&mut self) {
525 unsafe { self.pin.sio_oe().value_set().write_value(self.bit()) } 516 self.pin.sio_oe().value_set().write_value(self.bit())
526 } 517 }
527 518
528 #[inline] 519 #[inline]
529 fn is_set_as_output(&self) -> bool { 520 fn is_set_as_output(&self) -> bool {
530 unsafe { (self.pin.sio_oe().value().read() & self.bit()) != 0 } 521 (self.pin.sio_oe().value().read() & self.bit()) != 0
531 } 522 }
532 523
533 #[inline] 524 #[inline]
534 pub fn toggle_set_as_output(&mut self) { 525 pub fn toggle_set_as_output(&mut self) {
535 unsafe { self.pin.sio_oe().value_xor().write_value(self.bit()) } 526 self.pin.sio_oe().value_xor().write_value(self.bit())
536 } 527 }
537 528
538 #[inline] 529 #[inline]
@@ -542,7 +533,7 @@ impl<'d, T: Pin> Flex<'d, T> {
542 533
543 #[inline] 534 #[inline]
544 pub fn is_low(&self) -> bool { 535 pub fn is_low(&self) -> bool {
545 unsafe { self.pin.sio_in().read() & self.bit() == 0 } 536 self.pin.sio_in().read() & self.bit() == 0
546 } 537 }
547 538
548 /// Returns current pin level 539 /// Returns current pin level
@@ -554,13 +545,13 @@ impl<'d, T: Pin> Flex<'d, T> {
554 /// Set the output as high. 545 /// Set the output as high.
555 #[inline] 546 #[inline]
556 pub fn set_high(&mut self) { 547 pub fn set_high(&mut self) {
557 unsafe { self.pin.sio_out().value_set().write_value(self.bit()) } 548 self.pin.sio_out().value_set().write_value(self.bit())
558 } 549 }
559 550
560 /// Set the output as low. 551 /// Set the output as low.
561 #[inline] 552 #[inline]
562 pub fn set_low(&mut self) { 553 pub fn set_low(&mut self) {
563 unsafe { self.pin.sio_out().value_clr().write_value(self.bit()) } 554 self.pin.sio_out().value_clr().write_value(self.bit())
564 } 555 }
565 556
566 /// Set the output level. 557 /// Set the output level.
@@ -575,7 +566,7 @@ impl<'d, T: Pin> Flex<'d, T> {
575 /// Is the output level high? 566 /// Is the output level high?
576 #[inline] 567 #[inline]
577 pub fn is_set_high(&self) -> bool { 568 pub fn is_set_high(&self) -> bool {
578 unsafe { (self.pin.sio_out().value().read() & self.bit()) == 0 } 569 (self.pin.sio_out().value().read() & self.bit()) == 0
579 } 570 }
580 571
581 /// Is the output level low? 572 /// Is the output level low?
@@ -593,7 +584,7 @@ impl<'d, T: Pin> Flex<'d, T> {
593 /// Toggle pin output 584 /// Toggle pin output
594 #[inline] 585 #[inline]
595 pub fn toggle(&mut self) { 586 pub fn toggle(&mut self) {
596 unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) } 587 self.pin.sio_out().value_xor().write_value(self.bit())
597 } 588 }
598 589
599 #[inline] 590 #[inline]
@@ -625,12 +616,10 @@ impl<'d, T: Pin> Flex<'d, T> {
625impl<'d, T: Pin> Drop for Flex<'d, T> { 616impl<'d, T: Pin> Drop for Flex<'d, T> {
626 #[inline] 617 #[inline]
627 fn drop(&mut self) { 618 fn drop(&mut self) {
628 unsafe { 619 self.pin.pad_ctrl().write(|_| {});
629 self.pin.pad_ctrl().write(|_| {}); 620 self.pin.io().ctrl().write(|w| {
630 self.pin.io().ctrl().write(|w| { 621 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _);
631 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); 622 });
632 });
633 }
634 } 623 }
635} 624}
636 625
@@ -687,7 +676,7 @@ pub(crate) mod sealed {
687 Bank::Bank0 => crate::pac::IO_BANK0, 676 Bank::Bank0 => crate::pac::IO_BANK0,
688 Bank::Qspi => crate::pac::IO_QSPI, 677 Bank::Qspi => crate::pac::IO_QSPI,
689 }; 678 };
690 let proc = unsafe { SIO.cpuid().read() }; 679 let proc = SIO.cpuid().read();
691 io_block.int_proc(proc as _) 680 io_block.int_proc(proc as _)
692 } 681 }
693 } 682 }
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 124f1c00a..791c64554 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -2,14 +2,14 @@ use core::future;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_cortex_m::interrupt::{self, Binding, Interrupt};
6use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
8use pac::i2c; 7use pac::i2c;
9 8
10use crate::gpio::sealed::Pin; 9use crate::gpio::sealed::Pin;
11use crate::gpio::AnyPin; 10use crate::gpio::AnyPin;
12use crate::{pac, peripherals, Peripheral}; 11use crate::interrupt::typelevel::{Binding, Interrupt};
12use crate::{interrupt, pac, peripherals, Peripheral};
13 13
14/// I2C error abort reason 14/// I2C error abort reason
15#[derive(Debug)] 15#[derive(Debug)]
@@ -85,7 +85,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
85 let r = T::regs(); 85 let r = T::regs();
86 86
87 // mask everything initially 87 // mask everything initially
88 unsafe { r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)) } 88 r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
89 T::Interrupt::unpend(); 89 T::Interrupt::unpend();
90 unsafe { T::Interrupt::enable() }; 90 unsafe { T::Interrupt::enable() };
91 91
@@ -135,13 +135,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
135 let last = remaining_queue == 0; 135 let last = remaining_queue == 0;
136 batch += 1; 136 batch += 1;
137 137
138 unsafe { 138 p.ic_data_cmd().write(|w| {
139 p.ic_data_cmd().write(|w| { 139 w.set_restart(restart && remaining_queue == buffer.len() - 1);
140 w.set_restart(restart && remaining_queue == buffer.len() - 1); 140 w.set_stop(last && send_stop);
141 w.set_stop(last && send_stop); 141 w.set_cmd(true);
142 w.set_cmd(true); 142 });
143 });
144 }
145 } 143 }
146 144
147 // We've either run out of txfifo or just plain finished setting up 145 // We've either run out of txfifo or just plain finished setting up
@@ -161,7 +159,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
161 Poll::Pending 159 Poll::Pending
162 } 160 }
163 }, 161 },
164 |_me| unsafe { 162 |_me| {
165 // Set the read threshold to the number of bytes we're 163 // Set the read threshold to the number of bytes we're
166 // expecting so we don't get spurious interrupts. 164 // expecting so we don't get spurious interrupts.
167 p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); 165 p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1));
@@ -185,7 +183,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
185 let rxbytes = (rxfifo as usize).min(remaining); 183 let rxbytes = (rxfifo as usize).min(remaining);
186 let received = buffer.len() - remaining; 184 let received = buffer.len() - remaining;
187 for b in &mut buffer[received..received + rxbytes] { 185 for b in &mut buffer[received..received + rxbytes] {
188 *b = unsafe { p.ic_data_cmd().read().dat() }; 186 *b = p.ic_data_cmd().read().dat();
189 } 187 }
190 remaining -= rxbytes; 188 remaining -= rxbytes;
191 } 189 }
@@ -211,13 +209,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
211 if let Some(byte) = bytes.next() { 209 if let Some(byte) = bytes.next() {
212 let last = bytes.peek().is_none(); 210 let last = bytes.peek().is_none();
213 211
214 unsafe { 212 p.ic_data_cmd().write(|w| {
215 p.ic_data_cmd().write(|w| { 213 w.set_stop(last && send_stop);
216 w.set_stop(last && send_stop); 214 w.set_cmd(false);
217 w.set_cmd(false); 215 w.set_dat(byte);
218 w.set_dat(byte); 216 });
219 });
220 }
221 } else { 217 } else {
222 break 'xmit Ok(()); 218 break 'xmit Ok(());
223 } 219 }
@@ -235,7 +231,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
235 Poll::Pending 231 Poll::Pending
236 } 232 }
237 }, 233 },
238 |_me| unsafe { 234 |_me| {
239 // Set tx "free" threshold a little high so that we get 235 // Set tx "free" threshold a little high so that we get
240 // woken before the fifo completely drains to minimize 236 // woken before the fifo completely drains to minimize
241 // transfer stalls. 237 // transfer stalls.
@@ -267,7 +263,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
267 263
268 let had_abort2 = self 264 let had_abort2 = self
269 .wait_on( 265 .wait_on(
270 |me| unsafe { 266 |me| {
271 // We could see an abort while processing fifo backlog, 267 // We could see an abort while processing fifo backlog,
272 // so handle it here. 268 // so handle it here.
273 let abort = me.read_and_clear_abort_reason(); 269 let abort = me.read_and_clear_abort_reason();
@@ -279,7 +275,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
279 Poll::Pending 275 Poll::Pending
280 } 276 }
281 }, 277 },
282 |_me| unsafe { 278 |_me| {
283 p.ic_intr_mask().modify(|w| { 279 p.ic_intr_mask().modify(|w| {
284 w.set_m_stop_det(true); 280 w.set_m_stop_det(true);
285 w.set_m_tx_abrt(true); 281 w.set_m_tx_abrt(true);
@@ -287,9 +283,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
287 }, 283 },
288 ) 284 )
289 .await; 285 .await;
290 unsafe { 286 p.ic_clr_stop_det().read();
291 p.ic_clr_stop_det().read();
292 }
293 287
294 had_abort.and(had_abort2) 288 had_abort.and(had_abort2)
295 } else { 289 } else {
@@ -312,7 +306,7 @@ pub struct InterruptHandler<T: Instance> {
312 _uart: PhantomData<T>, 306 _uart: PhantomData<T>,
313} 307}
314 308
315impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 309impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
316 // Mask interrupts and wake any task waiting for this interrupt 310 // Mask interrupts and wake any task waiting for this interrupt
317 unsafe fn on_interrupt() { 311 unsafe fn on_interrupt() {
318 let i2c = T::regs(); 312 let i2c = T::regs();
@@ -336,95 +330,93 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
336 330
337 let p = T::regs(); 331 let p = T::regs();
338 332
339 unsafe { 333 let reset = T::reset();
340 let reset = T::reset(); 334 crate::reset::reset(reset);
341 crate::reset::reset(reset); 335 crate::reset::unreset_wait(reset);
342 crate::reset::unreset_wait(reset); 336
343 337 p.ic_enable().write(|w| w.set_enable(false));
344 p.ic_enable().write(|w| w.set_enable(false)); 338
345 339 // Select controller mode & speed
346 // Select controller mode & speed 340 p.ic_con().modify(|w| {
347 p.ic_con().modify(|w| { 341 // Always use "fast" mode (<= 400 kHz, works fine for standard
348 // Always use "fast" mode (<= 400 kHz, works fine for standard 342 // mode too)
349 // mode too) 343 w.set_speed(i2c::vals::Speed::FAST);
350 w.set_speed(i2c::vals::Speed::FAST); 344 w.set_master_mode(true);
351 w.set_master_mode(true); 345 w.set_ic_slave_disable(true);
352 w.set_ic_slave_disable(true); 346 w.set_ic_restart_en(true);
353 w.set_ic_restart_en(true); 347 w.set_tx_empty_ctrl(true);
354 w.set_tx_empty_ctrl(true); 348 });
355 }); 349
356 350 // Set FIFO watermarks to 1 to make things simpler. This is encoded
357 // Set FIFO watermarks to 1 to make things simpler. This is encoded 351 // by a register value of 0.
358 // by a register value of 0. 352 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
359 p.ic_tx_tl().write(|w| w.set_tx_tl(0)); 353 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
360 p.ic_rx_tl().write(|w| w.set_rx_tl(0)); 354
361 355 // Configure SCL & SDA pins
362 // Configure SCL & SDA pins 356 scl.io().ctrl().write(|w| w.set_funcsel(3));
363 scl.io().ctrl().write(|w| w.set_funcsel(3)); 357 sda.io().ctrl().write(|w| w.set_funcsel(3));
364 sda.io().ctrl().write(|w| w.set_funcsel(3)); 358
365 359 scl.pad_ctrl().write(|w| {
366 scl.pad_ctrl().write(|w| { 360 w.set_schmitt(true);
367 w.set_schmitt(true); 361 w.set_ie(true);
368 w.set_ie(true); 362 w.set_od(false);
369 w.set_od(false); 363 w.set_pue(true);
370 w.set_pue(true); 364 w.set_pde(false);
371 w.set_pde(false); 365 });
372 }); 366 sda.pad_ctrl().write(|w| {
373 sda.pad_ctrl().write(|w| { 367 w.set_schmitt(true);
374 w.set_schmitt(true); 368 w.set_ie(true);
375 w.set_ie(true); 369 w.set_od(false);
376 w.set_od(false); 370 w.set_pue(true);
377 w.set_pue(true); 371 w.set_pde(false);
378 w.set_pde(false); 372 });
379 }); 373
380 374 // Configure baudrate
381 // Configure baudrate 375
382 376 // There are some subtleties to I2C timing which we are completely
383 // There are some subtleties to I2C timing which we are completely 377 // ignoring here See:
384 // ignoring here See: 378 // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69
385 // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 379 let clk_base = crate::clocks::clk_peri_freq();
386 let clk_base = crate::clocks::clk_peri_freq(); 380
387 381 let period = (clk_base + config.frequency / 2) / config.frequency;
388 let period = (clk_base + config.frequency / 2) / config.frequency; 382 let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low
389 let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low 383 let hcnt = period - lcnt; // and 2/5 (40%) of the period high
390 let hcnt = period - lcnt; // and 2/5 (40%) of the period high 384
391 385 // Check for out-of-range divisors:
392 // Check for out-of-range divisors: 386 assert!(hcnt <= 0xffff);
393 assert!(hcnt <= 0xffff); 387 assert!(lcnt <= 0xffff);
394 assert!(lcnt <= 0xffff); 388 assert!(hcnt >= 8);
395 assert!(hcnt >= 8); 389 assert!(lcnt >= 8);
396 assert!(lcnt >= 8); 390
397 391 // Per I2C-bus specification a device in standard or fast mode must
398 // Per I2C-bus specification a device in standard or fast mode must 392 // internally provide a hold time of at least 300ns for the SDA
399 // internally provide a hold time of at least 300ns for the SDA 393 // signal to bridge the undefined region of the falling edge of SCL.
400 // signal to bridge the undefined region of the falling edge of SCL. 394 // A smaller hold time of 120ns is used for fast mode plus.
401 // A smaller hold time of 120ns is used for fast mode plus. 395 let sda_tx_hold_count = if config.frequency < 1_000_000 {
402 let sda_tx_hold_count = if config.frequency < 1_000_000 { 396 // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
403 // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / 397 // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
404 // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't 398 // fit in uint. Add 1 to avoid division truncation.
405 // fit in uint. Add 1 to avoid division truncation. 399 ((clk_base * 3) / 10_000_000) + 1
406 ((clk_base * 3) / 10_000_000) + 1 400 } else {
407 } else { 401 // fast mode plus requires a clk_base > 32MHz
408 // fast mode plus requires a clk_base > 32MHz 402 assert!(clk_base >= 32_000_000);
409 assert!(clk_base >= 32_000_000);
410 403
411 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / 404 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
412 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't 405 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
413 // fit in uint. Add 1 to avoid division truncation. 406 // fit in uint. Add 1 to avoid division truncation.
414 ((clk_base * 3) / 25_000_000) + 1 407 ((clk_base * 3) / 25_000_000) + 1
415 }; 408 };
416 assert!(sda_tx_hold_count <= lcnt - 2); 409 assert!(sda_tx_hold_count <= lcnt - 2);
417 410
418 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); 411 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16));
419 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); 412 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16));
420 p.ic_fs_spklen() 413 p.ic_fs_spklen()
421 .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); 414 .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 }));
422 p.ic_sda_hold() 415 p.ic_sda_hold()
423 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); 416 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
424 417
425 // Enable I2C block 418 // Enable I2C block
426 p.ic_enable().write(|w| w.set_enable(true)); 419 p.ic_enable().write(|w| w.set_enable(true));
427 }
428 420
429 Self { phantom: PhantomData } 421 Self { phantom: PhantomData }
430 } 422 }
@@ -439,11 +431,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
439 } 431 }
440 432
441 let p = T::regs(); 433 let p = T::regs();
442 unsafe { 434 p.ic_enable().write(|w| w.set_enable(false));
443 p.ic_enable().write(|w| w.set_enable(false)); 435 p.ic_tar().write(|w| w.set_ic_tar(addr));
444 p.ic_tar().write(|w| w.set_ic_tar(addr)); 436 p.ic_enable().write(|w| w.set_enable(true));
445 p.ic_enable().write(|w| w.set_enable(true));
446 }
447 Ok(()) 437 Ok(())
448 } 438 }
449 439
@@ -455,40 +445,38 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
455 #[inline] 445 #[inline]
456 fn tx_fifo_capacity() -> u8 { 446 fn tx_fifo_capacity() -> u8 {
457 let p = T::regs(); 447 let p = T::regs();
458 unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } 448 FIFO_SIZE - p.ic_txflr().read().txflr()
459 } 449 }
460 450
461 #[inline] 451 #[inline]
462 fn rx_fifo_len() -> u8 { 452 fn rx_fifo_len() -> u8 {
463 let p = T::regs(); 453 let p = T::regs();
464 unsafe { p.ic_rxflr().read().rxflr() } 454 p.ic_rxflr().read().rxflr()
465 } 455 }
466 456
467 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { 457 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
468 let p = T::regs(); 458 let p = T::regs();
469 unsafe { 459 let abort_reason = p.ic_tx_abrt_source().read();
470 let abort_reason = p.ic_tx_abrt_source().read(); 460 if abort_reason.0 != 0 {
471 if abort_reason.0 != 0 { 461 // Note clearing the abort flag also clears the reason, and this
472 // Note clearing the abort flag also clears the reason, and this 462 // instance of flag is clear-on-read! Note also the
473 // instance of flag is clear-on-read! Note also the 463 // IC_CLR_TX_ABRT register always reads as 0.
474 // IC_CLR_TX_ABRT register always reads as 0. 464 p.ic_clr_tx_abrt().read();
475 p.ic_clr_tx_abrt().read(); 465
476 466 let reason = if abort_reason.abrt_7b_addr_noack()
477 let reason = if abort_reason.abrt_7b_addr_noack() 467 | abort_reason.abrt_10addr1_noack()
478 | abort_reason.abrt_10addr1_noack() 468 | abort_reason.abrt_10addr2_noack()
479 | abort_reason.abrt_10addr2_noack() 469 {
480 { 470 AbortReason::NoAcknowledge
481 AbortReason::NoAcknowledge 471 } else if abort_reason.arb_lost() {
482 } else if abort_reason.arb_lost() { 472 AbortReason::ArbitrationLoss
483 AbortReason::ArbitrationLoss
484 } else {
485 AbortReason::Other(abort_reason.0)
486 };
487
488 Err(Error::Abort(reason))
489 } else { 473 } else {
490 Ok(()) 474 AbortReason::Other(abort_reason.0)
491 } 475 };
476
477 Err(Error::Abort(reason))
478 } else {
479 Ok(())
492 } 480 }
493 } 481 }
494 482
@@ -503,24 +491,21 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
503 let first = i == 0; 491 let first = i == 0;
504 let last = i == lastindex; 492 let last = i == lastindex;
505 493
506 // NOTE(unsafe) We have &mut self 494 // wait until there is space in the FIFO to write the next byte
507 unsafe { 495 while Self::tx_fifo_full() {}
508 // wait until there is space in the FIFO to write the next byte
509 while Self::tx_fifo_full() {}
510 496
511 p.ic_data_cmd().write(|w| { 497 p.ic_data_cmd().write(|w| {
512 w.set_restart(restart && first); 498 w.set_restart(restart && first);
513 w.set_stop(send_stop && last); 499 w.set_stop(send_stop && last);
514 500
515 w.set_cmd(true); 501 w.set_cmd(true);
516 }); 502 });
517
518 while Self::rx_fifo_len() == 0 {
519 self.read_and_clear_abort_reason()?;
520 }
521 503
522 *byte = p.ic_data_cmd().read().dat(); 504 while Self::rx_fifo_len() == 0 {
505 self.read_and_clear_abort_reason()?;
523 } 506 }
507
508 *byte = p.ic_data_cmd().read().dat();
524 } 509 }
525 510
526 Ok(()) 511 Ok(())
@@ -536,36 +521,33 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
536 for (i, byte) in write.iter().enumerate() { 521 for (i, byte) in write.iter().enumerate() {
537 let last = i == write.len() - 1; 522 let last = i == write.len() - 1;
538 523
539 // NOTE(unsafe) We have &mut self 524 p.ic_data_cmd().write(|w| {
540 unsafe { 525 w.set_stop(send_stop && last);
541 p.ic_data_cmd().write(|w| { 526 w.set_dat(*byte);
542 w.set_stop(send_stop && last); 527 });
543 w.set_dat(*byte);
544 });
545
546 // Wait until the transmission of the address/data from the
547 // internal shift register has completed. For this to function
548 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
549 // TX_EMPTY_CTRL flag was set in i2c_init.
550 while !p.ic_raw_intr_stat().read().tx_empty() {}
551 528
552 let abort_reason = self.read_and_clear_abort_reason(); 529 // Wait until the transmission of the address/data from the
530 // internal shift register has completed. For this to function
531 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
532 // TX_EMPTY_CTRL flag was set in i2c_init.
533 while !p.ic_raw_intr_stat().read().tx_empty() {}
553 534
554 if abort_reason.is_err() || (send_stop && last) { 535 let abort_reason = self.read_and_clear_abort_reason();
555 // If the transaction was aborted or if it completed
556 // successfully wait until the STOP condition has occurred.
557 536
558 while !p.ic_raw_intr_stat().read().stop_det() {} 537 if abort_reason.is_err() || (send_stop && last) {
538 // If the transaction was aborted or if it completed
539 // successfully wait until the STOP condition has occurred.
559 540
560 p.ic_clr_stop_det().read().clr_stop_det(); 541 while !p.ic_raw_intr_stat().read().stop_det() {}
561 }
562 542
563 // Note the hardware issues a STOP automatically on an abort 543 p.ic_clr_stop_det().read().clr_stop_det();
564 // condition. Note also the hardware clears RX FIFO as well as
565 // TX on abort, ecause we set hwparam
566 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
567 abort_reason?;
568 } 544 }
545
546 // Note the hardware issues a STOP automatically on an abort
547 // condition. Note also the hardware clears RX FIFO as well as
548 // TX on abort, ecause we set hwparam
549 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
550 abort_reason?;
569 } 551 }
570 Ok(()) 552 Ok(())
571 } 553 }
@@ -760,14 +742,15 @@ fn i2c_reserved_addr(addr: u16) -> bool {
760} 742}
761 743
762mod sealed { 744mod sealed {
763 use embassy_cortex_m::interrupt::Interrupt;
764 use embassy_sync::waitqueue::AtomicWaker; 745 use embassy_sync::waitqueue::AtomicWaker;
765 746
747 use crate::interrupt;
748
766 pub trait Instance { 749 pub trait Instance {
767 const TX_DREQ: u8; 750 const TX_DREQ: u8;
768 const RX_DREQ: u8; 751 const RX_DREQ: u8;
769 752
770 type Interrupt: Interrupt; 753 type Interrupt: interrupt::typelevel::Interrupt;
771 754
772 fn regs() -> crate::pac::i2c::I2c; 755 fn regs() -> crate::pac::i2c::I2c;
773 fn reset() -> crate::pac::resets::regs::Peripherals; 756 fn reset() -> crate::pac::resets::regs::Peripherals;
@@ -803,7 +786,7 @@ macro_rules! impl_instance {
803 const TX_DREQ: u8 = $tx_dreq; 786 const TX_DREQ: u8 = $tx_dreq;
804 const RX_DREQ: u8 = $rx_dreq; 787 const RX_DREQ: u8 = $rx_dreq;
805 788
806 type Interrupt = crate::interrupt::$irq; 789 type Interrupt = crate::interrupt::typelevel::$irq;
807 790
808 #[inline] 791 #[inline]
809 fn regs() -> pac::i2c::I2c { 792 fn regs() -> pac::i2c::I2c {
diff --git a/embassy-rp/src/interrupt.rs b/embassy-rp/src/interrupt.rs
deleted file mode 100644
index c9298644d..000000000
--- a/embassy-rp/src/interrupt.rs
+++ /dev/null
@@ -1,65 +0,0 @@
1//! Interrupt definitions and macros to bind them.
2pub use cortex_m::interrupt::{CriticalSection, Mutex};
3use embassy_cortex_m::interrupt::_export::declare;
4pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, Priority};
5
6use crate::pac::Interrupt as InterruptEnum;
7declare!(TIMER_IRQ_0);
8declare!(TIMER_IRQ_1);
9declare!(TIMER_IRQ_2);
10declare!(TIMER_IRQ_3);
11declare!(PWM_IRQ_WRAP);
12declare!(USBCTRL_IRQ);
13declare!(XIP_IRQ);
14declare!(PIO0_IRQ_0);
15declare!(PIO0_IRQ_1);
16declare!(PIO1_IRQ_0);
17declare!(PIO1_IRQ_1);
18declare!(DMA_IRQ_0);
19declare!(DMA_IRQ_1);
20declare!(IO_IRQ_BANK0);
21declare!(IO_IRQ_QSPI);
22declare!(SIO_IRQ_PROC0);
23declare!(SIO_IRQ_PROC1);
24declare!(CLOCKS_IRQ);
25declare!(SPI0_IRQ);
26declare!(SPI1_IRQ);
27declare!(UART0_IRQ);
28declare!(UART1_IRQ);
29declare!(ADC_IRQ_FIFO);
30declare!(I2C0_IRQ);
31declare!(I2C1_IRQ);
32declare!(RTC_IRQ);
33declare!(SWI_IRQ_0);
34declare!(SWI_IRQ_1);
35declare!(SWI_IRQ_2);
36declare!(SWI_IRQ_3);
37declare!(SWI_IRQ_4);
38declare!(SWI_IRQ_5);
39
40/// Macro to bind interrupts to handlers.
41///
42/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
43/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
44/// prove at compile-time that the right interrupts have been bound.
45// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
46#[macro_export]
47macro_rules! bind_interrupts {
48 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
49 $vis struct $name;
50
51 $(
52 #[allow(non_snake_case)]
53 #[no_mangle]
54 unsafe extern "C" fn $irq() {
55 $(
56 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
57 )*
58 }
59
60 $(
61 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
62 )*
63 )*
64 };
65}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 4e4542d70..4fd3cb46a 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -16,7 +16,6 @@ pub mod flash;
16mod float; 16mod float;
17pub mod gpio; 17pub mod gpio;
18pub mod i2c; 18pub mod i2c;
19pub mod interrupt;
20pub mod multicore; 19pub mod multicore;
21pub mod pwm; 20pub mod pwm;
22mod reset; 21mod reset;
@@ -37,14 +36,77 @@ pub mod pio_instr_util;
37pub mod relocate; 36pub mod relocate;
38 37
39// Reexports 38// Reexports
40pub use embassy_cortex_m::executor;
41pub use embassy_cortex_m::interrupt::_export::interrupt;
42pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 39pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
43#[cfg(feature = "unstable-pac")] 40#[cfg(feature = "unstable-pac")]
44pub use rp_pac as pac; 41pub use rp_pac as pac;
45#[cfg(not(feature = "unstable-pac"))] 42#[cfg(not(feature = "unstable-pac"))]
46pub(crate) use rp_pac as pac; 43pub(crate) use rp_pac as pac;
47 44
45#[cfg(feature = "rt")]
46pub use crate::pac::NVIC_PRIO_BITS;
47
48embassy_hal_common::interrupt_mod!(
49 TIMER_IRQ_0,
50 TIMER_IRQ_1,
51 TIMER_IRQ_2,
52 TIMER_IRQ_3,
53 PWM_IRQ_WRAP,
54 USBCTRL_IRQ,
55 XIP_IRQ,
56 PIO0_IRQ_0,
57 PIO0_IRQ_1,
58 PIO1_IRQ_0,
59 PIO1_IRQ_1,
60 DMA_IRQ_0,
61 DMA_IRQ_1,
62 IO_IRQ_BANK0,
63 IO_IRQ_QSPI,
64 SIO_IRQ_PROC0,
65 SIO_IRQ_PROC1,
66 CLOCKS_IRQ,
67 SPI0_IRQ,
68 SPI1_IRQ,
69 UART0_IRQ,
70 UART1_IRQ,
71 ADC_IRQ_FIFO,
72 I2C0_IRQ,
73 I2C1_IRQ,
74 RTC_IRQ,
75 SWI_IRQ_0,
76 SWI_IRQ_1,
77 SWI_IRQ_2,
78 SWI_IRQ_3,
79 SWI_IRQ_4,
80 SWI_IRQ_5,
81);
82
83/// Macro to bind interrupts to handlers.
84///
85/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
86/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
87/// prove at compile-time that the right interrupts have been bound.
88// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
89#[macro_export]
90macro_rules! bind_interrupts {
91 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
92 $vis struct $name;
93
94 $(
95 #[allow(non_snake_case)]
96 #[no_mangle]
97 unsafe extern "C" fn $irq() {
98 $(
99 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
100 )*
101 }
102
103 $(
104 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
105 )*
106 )*
107 };
108}
109
48embassy_hal_common::peripherals! { 110embassy_hal_common::peripherals! {
49 PIN_0, 111 PIN_0,
50 PIN_1, 112 PIN_1,
@@ -199,33 +261,39 @@ pub fn init(config: config::Config) -> Peripherals {
199 261
200/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. 262/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
201trait RegExt<T: Copy> { 263trait RegExt<T: Copy> {
202 unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 264 fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
203 unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 265 fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
204 unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 266 fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
205} 267}
206 268
207impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { 269impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
208 unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { 270 fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
209 let mut val = Default::default(); 271 let mut val = Default::default();
210 let res = f(&mut val); 272 let res = f(&mut val);
211 let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T; 273 unsafe {
212 ptr.write_volatile(val); 274 let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T;
275 ptr.write_volatile(val);
276 }
213 res 277 res
214 } 278 }
215 279
216 unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { 280 fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
217 let mut val = Default::default(); 281 let mut val = Default::default();
218 let res = f(&mut val); 282 let res = f(&mut val);
219 let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T; 283 unsafe {
220 ptr.write_volatile(val); 284 let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T;
285 ptr.write_volatile(val);
286 }
221 res 287 res
222 } 288 }
223 289
224 unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { 290 fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
225 let mut val = Default::default(); 291 let mut val = Default::default();
226 let res = f(&mut val); 292 let res = f(&mut val);
227 let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T; 293 unsafe {
228 ptr.write_volatile(val); 294 let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T;
295 ptr.write_volatile(val);
296 }
229 res 297 res
230 } 298 }
231} 299}
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index 807fda57b..468e8470a 100644
--- a/embassy-rp/src/multicore.rs
+++ b/embassy-rp/src/multicore.rs
@@ -50,7 +50,7 @@
50use core::mem::ManuallyDrop; 50use core::mem::ManuallyDrop;
51use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; 51use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
52 52
53use crate::interrupt::Interrupt; 53use crate::interrupt::InterruptExt;
54use crate::peripherals::CORE1; 54use crate::peripherals::CORE1;
55use crate::{gpio, interrupt, pac}; 55use crate::{gpio, interrupt, pac};
56 56
@@ -106,6 +106,7 @@ impl<const SIZE: usize> Stack<SIZE> {
106 } 106 }
107} 107}
108 108
109#[cfg(feature = "rt")]
109#[interrupt] 110#[interrupt]
110#[link_section = ".data.ram_func"] 111#[link_section = ".data.ram_func"]
111unsafe fn SIO_IRQ_PROC1() { 112unsafe fn SIO_IRQ_PROC1() {
@@ -156,20 +157,18 @@ where
156 157
157 IS_CORE1_INIT.store(true, Ordering::Release); 158 IS_CORE1_INIT.store(true, Ordering::Release);
158 // Enable fifo interrupt on CORE1 for `pause` functionality. 159 // Enable fifo interrupt on CORE1 for `pause` functionality.
159 unsafe { interrupt::SIO_IRQ_PROC1::enable() }; 160 unsafe { interrupt::SIO_IRQ_PROC1.enable() };
160 161
161 entry() 162 entry()
162 } 163 }
163 164
164 // Reset the core 165 // Reset the core
165 unsafe { 166 let psm = pac::PSM;
166 let psm = pac::PSM; 167 psm.frce_off().modify(|w| w.set_proc1(true));
167 psm.frce_off().modify(|w| w.set_proc1(true)); 168 while !psm.frce_off().read().proc1() {
168 while !psm.frce_off().read().proc1() { 169 cortex_m::asm::nop();
169 cortex_m::asm::nop();
170 }
171 psm.frce_off().modify(|w| w.set_proc1(false));
172 } 170 }
171 psm.frce_off().modify(|w| w.set_proc1(false));
173 172
174 // The ARM AAPCS ABI requires 8-byte stack alignment. 173 // The ARM AAPCS ABI requires 8-byte stack alignment.
175 // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be 174 // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be
@@ -269,14 +268,12 @@ pub fn resume_core1() {
269// Push a value to the inter-core FIFO, block until space is available 268// Push a value to the inter-core FIFO, block until space is available
270#[inline(always)] 269#[inline(always)]
271fn fifo_write(value: u32) { 270fn fifo_write(value: u32) {
272 unsafe { 271 let sio = pac::SIO;
273 let sio = pac::SIO; 272 // Wait for the FIFO to have enough space
274 // Wait for the FIFO to have enough space 273 while !sio.fifo().st().read().rdy() {
275 while !sio.fifo().st().read().rdy() { 274 cortex_m::asm::nop();
276 cortex_m::asm::nop();
277 }
278 sio.fifo().wr().write_value(value);
279 } 275 }
276 sio.fifo().wr().write_value(value);
280 // Fire off an event to the other core. 277 // Fire off an event to the other core.
281 // This is required as the other core may be `wfe` (waiting for event) 278 // This is required as the other core may be `wfe` (waiting for event)
282 cortex_m::asm::sev(); 279 cortex_m::asm::sev();
@@ -285,37 +282,32 @@ fn fifo_write(value: u32) {
285// Pop a value from inter-core FIFO, block until available 282// Pop a value from inter-core FIFO, block until available
286#[inline(always)] 283#[inline(always)]
287fn fifo_read() -> u32 { 284fn fifo_read() -> u32 {
288 unsafe { 285 let sio = pac::SIO;
289 let sio = pac::SIO; 286 // Wait until FIFO has data
290 // Wait until FIFO has data 287 while !sio.fifo().st().read().vld() {
291 while !sio.fifo().st().read().vld() { 288 cortex_m::asm::nop();
292 cortex_m::asm::nop();
293 }
294 sio.fifo().rd().read()
295 } 289 }
290 sio.fifo().rd().read()
296} 291}
297 292
298// Pop a value from inter-core FIFO, `wfe` until available 293// Pop a value from inter-core FIFO, `wfe` until available
299#[inline(always)] 294#[inline(always)]
295#[allow(unused)]
300fn fifo_read_wfe() -> u32 { 296fn fifo_read_wfe() -> u32 {
301 unsafe { 297 let sio = pac::SIO;
302 let sio = pac::SIO; 298 // Wait until FIFO has data
303 // Wait until FIFO has data 299 while !sio.fifo().st().read().vld() {
304 while !sio.fifo().st().read().vld() { 300 cortex_m::asm::wfe();
305 cortex_m::asm::wfe();
306 }
307 sio.fifo().rd().read()
308 } 301 }
302 sio.fifo().rd().read()
309} 303}
310 304
311// Drain inter-core FIFO 305// Drain inter-core FIFO
312#[inline(always)] 306#[inline(always)]
313fn fifo_drain() { 307fn fifo_drain() {
314 unsafe { 308 let sio = pac::SIO;
315 let sio = pac::SIO; 309 while sio.fifo().st().read().vld() {
316 while sio.fifo().st().read().vld() { 310 let _ = sio.fifo().rd().read();
317 let _ = sio.fifo().rd().read();
318 }
319 } 311 }
320} 312}
321 313
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 93e5bd34b..30648e8ea 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -5,7 +5,6 @@ use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
6 6
7use atomic_polyfill::{AtomicU32, AtomicU8}; 7use atomic_polyfill::{AtomicU32, AtomicU8};
8use embassy_cortex_m::interrupt::Interrupt;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
11use fixed::types::extra::U8; 10use fixed::types::extra::U8;
@@ -17,6 +16,7 @@ use pio::{SideSet, Wrap};
17use crate::dma::{Channel, Transfer, Word}; 16use crate::dma::{Channel, Transfer, Word};
18use crate::gpio::sealed::Pin as SealedPin; 17use crate::gpio::sealed::Pin as SealedPin;
19use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; 18use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
19use crate::interrupt::InterruptExt;
20use crate::pac::dma::vals::TreqSel; 20use crate::pac::dma::vals::TreqSel;
21use crate::relocate::RelocatedProgram; 21use crate::relocate::RelocatedProgram;
22use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt}; 22use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt};
@@ -85,8 +85,9 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
85const TXNFULL_MASK: u32 = 1 << 4; 85const TXNFULL_MASK: u32 = 1 << 4;
86const SMIRQ_MASK: u32 = 1 << 8; 86const SMIRQ_MASK: u32 = 1 << 8;
87 87
88#[cfg(feature = "rt")]
88#[interrupt] 89#[interrupt]
89unsafe fn PIO0_IRQ_0() { 90fn PIO0_IRQ_0() {
90 use crate::pac; 91 use crate::pac;
91 let ints = pac::PIO0.irqs(0).ints().read().0; 92 let ints = pac::PIO0.irqs(0).ints().read().0;
92 for bit in 0..12 { 93 for bit in 0..12 {
@@ -97,8 +98,9 @@ unsafe fn PIO0_IRQ_0() {
97 pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints); 98 pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
98} 99}
99 100
101#[cfg(feature = "rt")]
100#[interrupt] 102#[interrupt]
101unsafe fn PIO1_IRQ_0() { 103fn PIO1_IRQ_0() {
102 use crate::pac; 104 use crate::pac;
103 let ints = pac::PIO1.irqs(0).ints().read().0; 105 let ints = pac::PIO1.irqs(0).ints().read().0;
104 for bit in 0..12 { 106 for bit in 0..12 {
@@ -110,15 +112,15 @@ unsafe fn PIO1_IRQ_0() {
110} 112}
111 113
112pub(crate) unsafe fn init() { 114pub(crate) unsafe fn init() {
113 interrupt::PIO0_IRQ_0::disable(); 115 interrupt::PIO0_IRQ_0.disable();
114 interrupt::PIO0_IRQ_0::set_priority(interrupt::Priority::P3); 116 interrupt::PIO0_IRQ_0.set_priority(interrupt::Priority::P3);
115 pac::PIO0.irqs(0).inte().write(|m| m.0 = 0); 117 pac::PIO0.irqs(0).inte().write(|m| m.0 = 0);
116 interrupt::PIO0_IRQ_0::enable(); 118 interrupt::PIO0_IRQ_0.enable();
117 119
118 interrupt::PIO1_IRQ_0::disable(); 120 interrupt::PIO1_IRQ_0.disable();
119 interrupt::PIO1_IRQ_0::set_priority(interrupt::Priority::P3); 121 interrupt::PIO1_IRQ_0.set_priority(interrupt::Priority::P3);
120 pac::PIO1.irqs(0).inte().write(|m| m.0 = 0); 122 pac::PIO1.irqs(0).inte().write(|m| m.0 = 0);
121 interrupt::PIO1_IRQ_0::enable(); 123 interrupt::PIO1_IRQ_0.enable();
122} 124}
123 125
124/// Future that waits for TX-FIFO to become writable 126/// Future that waits for TX-FIFO to become writable
@@ -143,11 +145,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
143 Poll::Ready(()) 145 Poll::Ready(())
144 } else { 146 } else {
145 WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); 147 WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker());
146 unsafe { 148 PIO::PIO.irqs(0).inte().write_set(|m| {
147 PIO::PIO.irqs(0).inte().write_set(|m| { 149 m.0 = TXNFULL_MASK << SM;
148 m.0 = TXNFULL_MASK << SM; 150 });
149 });
150 }
151 // debug!("Pending"); 151 // debug!("Pending");
152 Poll::Pending 152 Poll::Pending
153 } 153 }
@@ -156,11 +156,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
156 156
157impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { 157impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> {
158 fn drop(&mut self) { 158 fn drop(&mut self) {
159 unsafe { 159 PIO::PIO.irqs(0).inte().write_clear(|m| {
160 PIO::PIO.irqs(0).inte().write_clear(|m| { 160 m.0 = TXNFULL_MASK << SM;
161 m.0 = TXNFULL_MASK << SM; 161 });
162 });
163 }
164 } 162 }
165} 163}
166 164
@@ -184,11 +182,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
184 Poll::Ready(v) 182 Poll::Ready(v)
185 } else { 183 } else {
186 WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); 184 WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker());
187 unsafe { 185 PIO::PIO.irqs(0).inte().write_set(|m| {
188 PIO::PIO.irqs(0).inte().write_set(|m| { 186 m.0 = RXNEMPTY_MASK << SM;
189 m.0 = RXNEMPTY_MASK << SM; 187 });
190 });
191 }
192 //debug!("Pending"); 188 //debug!("Pending");
193 Poll::Pending 189 Poll::Pending
194 } 190 }
@@ -197,11 +193,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
197 193
198impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { 194impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> {
199 fn drop(&mut self) { 195 fn drop(&mut self) {
200 unsafe { 196 PIO::PIO.irqs(0).inte().write_clear(|m| {
201 PIO::PIO.irqs(0).inte().write_clear(|m| { 197 m.0 = RXNEMPTY_MASK << SM;
202 m.0 = RXNEMPTY_MASK << SM; 198 });
203 });
204 }
205 } 199 }
206} 200}
207 201
@@ -218,30 +212,24 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> {
218 //debug!("Poll {},{}", PIO::PIO_NO, SM); 212 //debug!("Poll {},{}", PIO::PIO_NO, SM);
219 213
220 // Check if IRQ flag is already set 214 // Check if IRQ flag is already set
221 if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } { 215 if PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 {
222 unsafe { 216 PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
223 PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
224 }
225 return Poll::Ready(()); 217 return Poll::Ready(());
226 } 218 }
227 219
228 WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); 220 WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
229 unsafe { 221 PIO::PIO.irqs(0).inte().write_set(|m| {
230 PIO::PIO.irqs(0).inte().write_set(|m| { 222 m.0 = SMIRQ_MASK << self.irq_no;
231 m.0 = SMIRQ_MASK << self.irq_no; 223 });
232 });
233 }
234 Poll::Pending 224 Poll::Pending
235 } 225 }
236} 226}
237 227
238impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { 228impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
239 fn drop(&mut self) { 229 fn drop(&mut self) {
240 unsafe { 230 PIO::PIO.irqs(0).inte().write_clear(|m| {
241 PIO::PIO.irqs(0).inte().write_clear(|m| { 231 m.0 = SMIRQ_MASK << self.irq_no;
242 m.0 = SMIRQ_MASK << self.irq_no; 232 });
243 });
244 }
245 } 233 }
246} 234}
247 235
@@ -254,57 +242,47 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
254 /// Set the pin's drive strength. 242 /// Set the pin's drive strength.
255 #[inline] 243 #[inline]
256 pub fn set_drive_strength(&mut self, strength: Drive) { 244 pub fn set_drive_strength(&mut self, strength: Drive) {
257 unsafe { 245 self.pin.pad_ctrl().modify(|w| {
258 self.pin.pad_ctrl().modify(|w| { 246 w.set_drive(match strength {
259 w.set_drive(match strength { 247 Drive::_2mA => pac::pads::vals::Drive::_2MA,
260 Drive::_2mA => pac::pads::vals::Drive::_2MA, 248 Drive::_4mA => pac::pads::vals::Drive::_4MA,
261 Drive::_4mA => pac::pads::vals::Drive::_4MA, 249 Drive::_8mA => pac::pads::vals::Drive::_8MA,
262 Drive::_8mA => pac::pads::vals::Drive::_8MA, 250 Drive::_12mA => pac::pads::vals::Drive::_12MA,
263 Drive::_12mA => pac::pads::vals::Drive::_12MA,
264 });
265 }); 251 });
266 } 252 });
267 } 253 }
268 254
269 // Set the pin's slew rate. 255 // Set the pin's slew rate.
270 #[inline] 256 #[inline]
271 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 257 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
272 unsafe { 258 self.pin.pad_ctrl().modify(|w| {
273 self.pin.pad_ctrl().modify(|w| { 259 w.set_slewfast(slew_rate == SlewRate::Fast);
274 w.set_slewfast(slew_rate == SlewRate::Fast); 260 });
275 });
276 }
277 } 261 }
278 262
279 /// Set the pin's pull. 263 /// Set the pin's pull.
280 #[inline] 264 #[inline]
281 pub fn set_pull(&mut self, pull: Pull) { 265 pub fn set_pull(&mut self, pull: Pull) {
282 unsafe { 266 self.pin.pad_ctrl().modify(|w| {
283 self.pin.pad_ctrl().modify(|w| { 267 w.set_pue(pull == Pull::Up);
284 w.set_pue(pull == Pull::Up); 268 w.set_pde(pull == Pull::Down);
285 w.set_pde(pull == Pull::Down); 269 });
286 });
287 }
288 } 270 }
289 271
290 /// Set the pin's schmitt trigger. 272 /// Set the pin's schmitt trigger.
291 #[inline] 273 #[inline]
292 pub fn set_schmitt(&mut self, enable: bool) { 274 pub fn set_schmitt(&mut self, enable: bool) {
293 unsafe { 275 self.pin.pad_ctrl().modify(|w| {
294 self.pin.pad_ctrl().modify(|w| { 276 w.set_schmitt(enable);
295 w.set_schmitt(enable); 277 });
296 });
297 }
298 } 278 }
299 279
300 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { 280 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
301 let mask = 1 << self.pin(); 281 let mask = 1 << self.pin();
302 unsafe { 282 if bypass {
303 if bypass { 283 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
304 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); 284 } else {
305 } else { 285 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
306 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
307 }
308 } 286 }
309 } 287 }
310 288
@@ -319,41 +297,37 @@ pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> {
319 297
320impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { 298impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
321 pub fn empty(&self) -> bool { 299 pub fn empty(&self) -> bool {
322 unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } 300 PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0
323 } 301 }
324 302
325 pub fn full(&self) -> bool { 303 pub fn full(&self) -> bool {
326 unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } 304 PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0
327 } 305 }
328 306
329 pub fn level(&self) -> u8 { 307 pub fn level(&self) -> u8 {
330 unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } 308 (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f
331 } 309 }
332 310
333 pub fn stalled(&self) -> bool { 311 pub fn stalled(&self) -> bool {
334 unsafe { 312 let fdebug = PIO::PIO.fdebug();
335 let fdebug = PIO::PIO.fdebug(); 313 let ret = fdebug.read().rxstall() & (1 << SM) != 0;
336 let ret = fdebug.read().rxstall() & (1 << SM) != 0; 314 if ret {
337 if ret { 315 fdebug.write(|w| w.set_rxstall(1 << SM));
338 fdebug.write(|w| w.set_rxstall(1 << SM));
339 }
340 ret
341 } 316 }
317 ret
342 } 318 }
343 319
344 pub fn underflowed(&self) -> bool { 320 pub fn underflowed(&self) -> bool {
345 unsafe { 321 let fdebug = PIO::PIO.fdebug();
346 let fdebug = PIO::PIO.fdebug(); 322 let ret = fdebug.read().rxunder() & (1 << SM) != 0;
347 let ret = fdebug.read().rxunder() & (1 << SM) != 0; 323 if ret {
348 if ret { 324 fdebug.write(|w| w.set_rxunder(1 << SM));
349 fdebug.write(|w| w.set_rxunder(1 << SM));
350 }
351 ret
352 } 325 }
326 ret
353 } 327 }
354 328
355 pub fn pull(&mut self) -> u32 { 329 pub fn pull(&mut self) -> u32 {
356 unsafe { PIO::PIO.rxf(SM).read() } 330 PIO::PIO.rxf(SM).read()
357 } 331 }
358 332
359 pub fn try_pull(&mut self) -> Option<u32> { 333 pub fn try_pull(&mut self) -> Option<u32> {
@@ -372,24 +346,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
372 ch: PeripheralRef<'a, C>, 346 ch: PeripheralRef<'a, C>,
373 data: &'a mut [W], 347 data: &'a mut [W],
374 ) -> Transfer<'a, C> { 348 ) -> Transfer<'a, C> {
375 unsafe { 349 let pio_no = PIO::PIO_NO;
376 let pio_no = PIO::PIO_NO; 350 let p = ch.regs();
377 let p = ch.regs(); 351 p.write_addr().write_value(data.as_ptr() as u32);
378 p.write_addr().write_value(data.as_ptr() as u32); 352 p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
379 p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); 353 p.trans_count().write_value(data.len() as u32);
380 p.trans_count().write_value(data.len() as u32); 354 compiler_fence(Ordering::SeqCst);
381 compiler_fence(Ordering::SeqCst); 355 p.ctrl_trig().write(|w| {
382 p.ctrl_trig().write(|w| { 356 // Set RX DREQ for this statemachine
383 // Set RX DREQ for this statemachine 357 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4));
384 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); 358 w.set_data_size(W::size());
385 w.set_data_size(W::size()); 359 w.set_chain_to(ch.number());
386 w.set_chain_to(ch.number()); 360 w.set_incr_read(false);
387 w.set_incr_read(false); 361 w.set_incr_write(true);
388 w.set_incr_write(true); 362 w.set_en(true);
389 w.set_en(true); 363 });
390 }); 364 compiler_fence(Ordering::SeqCst);
391 compiler_fence(Ordering::SeqCst);
392 }
393 Transfer::new(ch) 365 Transfer::new(ch)
394 } 366 }
395} 367}
@@ -400,42 +372,36 @@ pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> {
400 372
401impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { 373impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
402 pub fn empty(&self) -> bool { 374 pub fn empty(&self) -> bool {
403 unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } 375 PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0
404 } 376 }
405 pub fn full(&self) -> bool { 377 pub fn full(&self) -> bool {
406 unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } 378 PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0
407 } 379 }
408 380
409 pub fn level(&self) -> u8 { 381 pub fn level(&self) -> u8 {
410 unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } 382 (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f
411 } 383 }
412 384
413 pub fn stalled(&self) -> bool { 385 pub fn stalled(&self) -> bool {
414 unsafe { 386 let fdebug = PIO::PIO.fdebug();
415 let fdebug = PIO::PIO.fdebug(); 387 let ret = fdebug.read().txstall() & (1 << SM) != 0;
416 let ret = fdebug.read().txstall() & (1 << SM) != 0; 388 if ret {
417 if ret { 389 fdebug.write(|w| w.set_txstall(1 << SM));
418 fdebug.write(|w| w.set_txstall(1 << SM));
419 }
420 ret
421 } 390 }
391 ret
422 } 392 }
423 393
424 pub fn overflowed(&self) -> bool { 394 pub fn overflowed(&self) -> bool {
425 unsafe { 395 let fdebug = PIO::PIO.fdebug();
426 let fdebug = PIO::PIO.fdebug(); 396 let ret = fdebug.read().txover() & (1 << SM) != 0;
427 let ret = fdebug.read().txover() & (1 << SM) != 0; 397 if ret {
428 if ret { 398 fdebug.write(|w| w.set_txover(1 << SM));
429 fdebug.write(|w| w.set_txover(1 << SM));
430 }
431 ret
432 } 399 }
400 ret
433 } 401 }
434 402
435 pub fn push(&mut self, v: u32) { 403 pub fn push(&mut self, v: u32) {
436 unsafe { 404 PIO::PIO.txf(SM).write_value(v);
437 PIO::PIO.txf(SM).write_value(v);
438 }
439 } 405 }
440 406
441 pub fn try_push(&mut self, v: u32) -> bool { 407 pub fn try_push(&mut self, v: u32) -> bool {
@@ -451,24 +417,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
451 } 417 }
452 418
453 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { 419 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
454 unsafe { 420 let pio_no = PIO::PIO_NO;
455 let pio_no = PIO::PIO_NO; 421 let p = ch.regs();
456 let p = ch.regs(); 422 p.read_addr().write_value(data.as_ptr() as u32);
457 p.read_addr().write_value(data.as_ptr() as u32); 423 p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
458 p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); 424 p.trans_count().write_value(data.len() as u32);
459 p.trans_count().write_value(data.len() as u32); 425 compiler_fence(Ordering::SeqCst);
460 compiler_fence(Ordering::SeqCst); 426 p.ctrl_trig().write(|w| {
461 p.ctrl_trig().write(|w| { 427 // Set TX DREQ for this statemachine
462 // Set TX DREQ for this statemachine 428 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8));
463 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); 429 w.set_data_size(W::size());
464 w.set_data_size(W::size()); 430 w.set_chain_to(ch.number());
465 w.set_chain_to(ch.number()); 431 w.set_incr_read(true);
466 w.set_incr_read(true); 432 w.set_incr_write(false);
467 w.set_incr_write(false); 433 w.set_en(true);
468 w.set_en(true); 434 });
469 }); 435 compiler_fence(Ordering::SeqCst);
470 compiler_fence(Ordering::SeqCst);
471 }
472 Transfer::new(ch) 436 Transfer::new(ch)
473 } 437 }
474} 438}
@@ -480,9 +444,7 @@ pub struct StateMachine<'d, PIO: Instance, const SM: usize> {
480 444
481impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { 445impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> {
482 fn drop(&mut self) { 446 fn drop(&mut self) {
483 unsafe { 447 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
484 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
485 }
486 on_pio_drop::<PIO>(); 448 on_pio_drop::<PIO>();
487 } 449 }
488} 450}
@@ -645,45 +607,43 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
645 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); 607 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
646 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); 608 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
647 let sm = Self::this_sm(); 609 let sm = Self::this_sm();
648 unsafe { 610 sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
649 sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); 611 sm.execctrl().write(|w| {
650 sm.execctrl().write(|w| { 612 w.set_side_en(config.exec.side_en);
651 w.set_side_en(config.exec.side_en); 613 w.set_side_pindir(config.exec.side_pindir);
652 w.set_side_pindir(config.exec.side_pindir); 614 w.set_jmp_pin(config.exec.jmp_pin);
653 w.set_jmp_pin(config.exec.jmp_pin); 615 w.set_out_en_sel(config.out_en_sel);
654 w.set_out_en_sel(config.out_en_sel); 616 w.set_inline_out_en(config.inline_out_en);
655 w.set_inline_out_en(config.inline_out_en); 617 w.set_out_sticky(config.out_sticky);
656 w.set_out_sticky(config.out_sticky); 618 w.set_wrap_top(config.exec.wrap_top);
657 w.set_wrap_top(config.exec.wrap_top); 619 w.set_wrap_bottom(config.exec.wrap_bottom);
658 w.set_wrap_bottom(config.exec.wrap_bottom); 620 w.set_status_sel(match config.status_sel {
659 w.set_status_sel(match config.status_sel { 621 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
660 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, 622 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
661 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
662 });
663 w.set_status_n(config.status_n);
664 });
665 sm.shiftctrl().write(|w| {
666 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
667 w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
668 w.set_pull_thresh(config.shift_out.threshold);
669 w.set_push_thresh(config.shift_in.threshold);
670 w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
671 w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
672 w.set_autopull(config.shift_out.auto_fill);
673 w.set_autopush(config.shift_in.auto_fill);
674 });
675 sm.pinctrl().write(|w| {
676 w.set_sideset_count(config.pins.sideset_count);
677 w.set_set_count(config.pins.set_count);
678 w.set_out_count(config.pins.out_count);
679 w.set_in_base(config.pins.in_base);
680 w.set_sideset_base(config.pins.sideset_base);
681 w.set_set_base(config.pins.set_base);
682 w.set_out_base(config.pins.out_base);
683 }); 623 });
684 if let Some(origin) = config.origin { 624 w.set_status_n(config.status_n);
685 pio_instr_util::exec_jmp(self, origin); 625 });
686 } 626 sm.shiftctrl().write(|w| {
627 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
628 w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
629 w.set_pull_thresh(config.shift_out.threshold);
630 w.set_push_thresh(config.shift_in.threshold);
631 w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
632 w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
633 w.set_autopull(config.shift_out.auto_fill);
634 w.set_autopush(config.shift_in.auto_fill);
635 });
636 sm.pinctrl().write(|w| {
637 w.set_sideset_count(config.pins.sideset_count);
638 w.set_set_count(config.pins.set_count);
639 w.set_out_count(config.pins.out_count);
640 w.set_in_base(config.pins.in_base);
641 w.set_sideset_base(config.pins.sideset_base);
642 w.set_set_base(config.pins.set_base);
643 w.set_out_base(config.pins.out_base);
644 });
645 if let Some(origin) = config.origin {
646 unsafe { pio_instr_util::exec_jmp(self, origin) }
687 } 647 }
688 } 648 }
689 649
@@ -694,45 +654,35 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
694 654
695 pub fn restart(&mut self) { 655 pub fn restart(&mut self) {
696 let mask = 1u8 << SM; 656 let mask = 1u8 << SM;
697 unsafe { 657 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
698 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
699 }
700 } 658 }
701 pub fn set_enable(&mut self, enable: bool) { 659 pub fn set_enable(&mut self, enable: bool) {
702 let mask = 1u8 << SM; 660 let mask = 1u8 << SM;
703 unsafe { 661 if enable {
704 if enable { 662 PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
705 PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); 663 } else {
706 } else { 664 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
707 PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
708 }
709 } 665 }
710 } 666 }
711 667
712 pub fn is_enabled(&self) -> bool { 668 pub fn is_enabled(&self) -> bool {
713 unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } 669 PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0
714 } 670 }
715 671
716 pub fn clkdiv_restart(&mut self) { 672 pub fn clkdiv_restart(&mut self) {
717 let mask = 1u8 << SM; 673 let mask = 1u8 << SM;
718 unsafe { 674 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
719 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
720 }
721 } 675 }
722 676
723 fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { 677 fn with_paused(&mut self, f: impl FnOnce(&mut Self)) {
724 let enabled = self.is_enabled(); 678 let enabled = self.is_enabled();
725 self.set_enable(false); 679 self.set_enable(false);
726 let pincfg = unsafe { Self::this_sm().pinctrl().read() }; 680 let pincfg = Self::this_sm().pinctrl().read();
727 let execcfg = unsafe { Self::this_sm().execctrl().read() }; 681 let execcfg = Self::this_sm().execctrl().read();
728 unsafe { 682 Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
729 Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
730 }
731 f(self); 683 f(self);
732 unsafe { 684 Self::this_sm().pinctrl().write_value(pincfg);
733 Self::this_sm().pinctrl().write_value(pincfg); 685 Self::this_sm().execctrl().write_value(execcfg);
734 Self::this_sm().execctrl().write_value(execcfg);
735 }
736 self.set_enable(enabled); 686 self.set_enable(enabled);
737 } 687 }
738 688
@@ -741,14 +691,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
741 pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { 691 pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) {
742 self.with_paused(|sm| { 692 self.with_paused(|sm| {
743 for pin in pins { 693 for pin in pins {
744 unsafe { 694 Self::this_sm().pinctrl().write(|w| {
745 Self::this_sm().pinctrl().write(|w| { 695 w.set_set_base(pin.pin());
746 w.set_set_base(pin.pin()); 696 w.set_set_count(1);
747 w.set_set_count(1); 697 });
748 }); 698 // SET PINDIRS, (dir)
749 // SET PINDIRS, (dir) 699 unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) };
750 sm.exec_instr(0b111_00000_100_00000 | dir as u16);
751 }
752 } 700 }
753 }); 701 });
754 } 702 }
@@ -758,29 +706,25 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
758 pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { 706 pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) {
759 self.with_paused(|sm| { 707 self.with_paused(|sm| {
760 for pin in pins { 708 for pin in pins {
761 unsafe { 709 Self::this_sm().pinctrl().write(|w| {
762 Self::this_sm().pinctrl().write(|w| { 710 w.set_set_base(pin.pin());
763 w.set_set_base(pin.pin()); 711 w.set_set_count(1);
764 w.set_set_count(1); 712 });
765 }); 713 // SET PINS, (dir)
766 // SET PINS, (dir) 714 unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) };
767 sm.exec_instr(0b111_00000_000_00000 | level as u16);
768 }
769 } 715 }
770 }); 716 });
771 } 717 }
772 718
773 pub fn clear_fifos(&mut self) { 719 pub fn clear_fifos(&mut self) {
774 // Toggle FJOIN_RX to flush FIFOs 720 // Toggle FJOIN_RX to flush FIFOs
775 unsafe { 721 let shiftctrl = Self::this_sm().shiftctrl();
776 let shiftctrl = Self::this_sm().shiftctrl(); 722 shiftctrl.modify(|w| {
777 shiftctrl.modify(|w| { 723 w.set_fjoin_rx(!w.fjoin_rx());
778 w.set_fjoin_rx(!w.fjoin_rx()); 724 });
779 }); 725 shiftctrl.modify(|w| {
780 shiftctrl.modify(|w| { 726 w.set_fjoin_rx(!w.fjoin_rx());
781 w.set_fjoin_rx(!w.fjoin_rx()); 727 });
782 });
783 }
784 } 728 }
785 729
786 pub unsafe fn exec_instr(&mut self, instr: u16) { 730 pub unsafe fn exec_instr(&mut self, instr: u16) {
@@ -854,11 +798,9 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
854 if (self.instructions_used | used_mask) & mask != 0 { 798 if (self.instructions_used | used_mask) & mask != 0 {
855 return Err(addr); 799 return Err(addr);
856 } 800 }
857 unsafe { 801 PIO::PIO.instr_mem(addr).write(|w| {
858 PIO::PIO.instr_mem(addr).write(|w| { 802 w.set_instr_mem(instr);
859 w.set_instr_mem(instr); 803 });
860 });
861 }
862 used_mask |= mask; 804 used_mask |= mask;
863 } 805 }
864 self.instructions_used |= used_mask; 806 self.instructions_used |= used_mask;
@@ -875,17 +817,15 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
875 } 817 }
876 818
877 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { 819 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
878 unsafe { 820 // this can interfere with per-pin bypass functions. splitting the
879 // this can interfere with per-pin bypass functions. splitting the 821 // modification is going to be fine since nothing that relies on
880 // modification is going to be fine since nothing that relies on 822 // it can reasonably run before we finish.
881 // it can reasonably run before we finish. 823 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
882 PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); 824 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
883 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
884 }
885 } 825 }
886 826
887 pub fn get_input_sync_bypass(&self) -> u32 { 827 pub fn get_input_sync_bypass(&self) -> u32 {
888 unsafe { PIO::PIO.input_sync_bypass().read() } 828 PIO::PIO.input_sync_bypass().read()
889 } 829 }
890 830
891 /// Register a pin for PIO usage. Pins will be released from the PIO block 831 /// Register a pin for PIO usage. Pins will be released from the PIO block
@@ -894,9 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
894 /// of [`Pio`] do not keep pin registrations alive.** 834 /// of [`Pio`] do not keep pin registrations alive.**
895 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { 835 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
896 into_ref!(pin); 836 into_ref!(pin);
897 unsafe { 837 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _));
898 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
899 }
900 // we can be relaxed about this because we're &mut here and nothing is cached 838 // we can be relaxed about this because we're &mut here and nothing is cached
901 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); 839 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
902 Pin { 840 Pin {
@@ -914,13 +852,11 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
914 _pio: PhantomData, 852 _pio: PhantomData,
915 }; 853 };
916 f(&mut batch); 854 f(&mut batch);
917 unsafe { 855 PIO::PIO.ctrl().modify(|w| {
918 PIO::PIO.ctrl().modify(|w| { 856 w.set_clkdiv_restart(batch.clkdiv_restart);
919 w.set_clkdiv_restart(batch.clkdiv_restart); 857 w.set_sm_restart(batch.sm_restart);
920 w.set_sm_restart(batch.sm_restart); 858 w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable);
921 w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable); 859 });
922 });
923 }
924 } 860 }
925} 861}
926 862
@@ -972,11 +908,11 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
972 } 908 }
973 909
974 pub fn check_any(&self, irqs: u8) -> bool { 910 pub fn check_any(&self, irqs: u8) -> bool {
975 unsafe { PIO::PIO.irq().read().irq() & irqs != 0 } 911 PIO::PIO.irq().read().irq() & irqs != 0
976 } 912 }
977 913
978 pub fn check_all(&self, irqs: u8) -> bool { 914 pub fn check_all(&self, irqs: u8) -> bool {
979 unsafe { PIO::PIO.irq().read().irq() & irqs == irqs } 915 PIO::PIO.irq().read().irq() & irqs == irqs
980 } 916 }
981 917
982 pub fn clear(&self, irq_no: usize) { 918 pub fn clear(&self, irq_no: usize) {
@@ -985,7 +921,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
985 } 921 }
986 922
987 pub fn clear_all(&self, irqs: u8) { 923 pub fn clear_all(&self, irqs: u8) {
988 unsafe { PIO::PIO.irq().write(|w| w.set_irq(irqs)) } 924 PIO::PIO.irq().write(|w| w.set_irq(irqs))
989 } 925 }
990 926
991 pub fn set(&self, irq_no: usize) { 927 pub fn set(&self, irq_no: usize) {
@@ -994,7 +930,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
994 } 930 }
995 931
996 pub fn set_all(&self, irqs: u8) { 932 pub fn set_all(&self, irqs: u8) {
997 unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) } 933 PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs))
998 } 934 }
999} 935}
1000 936
@@ -1062,13 +998,11 @@ fn on_pio_drop<PIO: Instance>() {
1062 let state = PIO::state(); 998 let state = PIO::state();
1063 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { 999 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
1064 let used_pins = state.used_pins.load(Ordering::Relaxed); 1000 let used_pins = state.used_pins.load(Ordering::Relaxed);
1065 let null = Gpio0ctrlFuncsel::NULL.0; 1001 let null = Gpio0ctrlFuncsel::NULL as _;
1066 // we only have 30 pins. don't test the other two since gpio() asserts. 1002 // we only have 30 pins. don't test the other two since gpio() asserts.
1067 for i in 0..30 { 1003 for i in 0..30 {
1068 if used_pins & (1 << i) != 0 { 1004 if used_pins & (1 << i) != 0 {
1069 unsafe { 1005 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
1070 pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
1071 }
1072 } 1006 }
1073 } 1007 }
1074 } 1008 }
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index 0f9dcf479..20bb88446 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -71,20 +71,18 @@ impl<'d, T: Channel> Pwm<'d, T> {
71 into_ref!(inner); 71 into_ref!(inner);
72 72
73 let p = inner.regs(); 73 let p = inner.regs();
74 unsafe { 74 p.csr().modify(|w| {
75 p.csr().modify(|w| { 75 w.set_divmode(divmode);
76 w.set_divmode(divmode); 76 w.set_en(false);
77 w.set_en(false); 77 });
78 }); 78 p.ctr().write(|w| w.0 = 0);
79 p.ctr().write(|w| w.0 = 0); 79 Self::configure(p, &config);
80 Self::configure(p, &config); 80
81 81 if let Some(pin) = &a {
82 if let Some(pin) = &a { 82 pin.io().ctrl().write(|w| w.set_funcsel(4));
83 pin.io().ctrl().write(|w| w.set_funcsel(4)); 83 }
84 } 84 if let Some(pin) = &b {
85 if let Some(pin) = &b { 85 pin.io().ctrl().write(|w| w.set_funcsel(4));
86 pin.io().ctrl().write(|w| w.set_funcsel(4));
87 }
88 } 86 }
89 Self { 87 Self {
90 inner, 88 inner,
@@ -161,31 +159,29 @@ impl<'d, T: Channel> Pwm<'d, T> {
161 panic!("Requested divider is too large"); 159 panic!("Requested divider is too large");
162 } 160 }
163 161
164 unsafe { 162 p.div().write_value(ChDiv(config.divider.to_bits() as u32));
165 p.div().write_value(ChDiv(config.divider.to_bits() as u32)); 163 p.cc().write(|w| {
166 p.cc().write(|w| { 164 w.set_a(config.compare_a);
167 w.set_a(config.compare_a); 165 w.set_b(config.compare_b);
168 w.set_b(config.compare_b); 166 });
169 }); 167 p.top().write(|w| w.set_top(config.top));
170 p.top().write(|w| w.set_top(config.top)); 168 p.csr().modify(|w| {
171 p.csr().modify(|w| { 169 w.set_a_inv(config.invert_a);
172 w.set_a_inv(config.invert_a); 170 w.set_b_inv(config.invert_b);
173 w.set_b_inv(config.invert_b); 171 w.set_ph_correct(config.phase_correct);
174 w.set_ph_correct(config.phase_correct); 172 w.set_en(config.enable);
175 w.set_en(config.enable); 173 });
176 });
177 }
178 } 174 }
179 175
180 #[inline] 176 #[inline]
181 pub unsafe fn phase_advance(&mut self) { 177 pub fn phase_advance(&mut self) {
182 let p = self.inner.regs(); 178 let p = self.inner.regs();
183 p.csr().write_set(|w| w.set_ph_adv(true)); 179 p.csr().write_set(|w| w.set_ph_adv(true));
184 while p.csr().read().ph_adv() {} 180 while p.csr().read().ph_adv() {}
185 } 181 }
186 182
187 #[inline] 183 #[inline]
188 pub unsafe fn phase_retard(&mut self) { 184 pub fn phase_retard(&mut self) {
189 let p = self.inner.regs(); 185 let p = self.inner.regs();
190 p.csr().write_set(|w| w.set_ph_ret(true)); 186 p.csr().write_set(|w| w.set_ph_ret(true));
191 while p.csr().read().ph_ret() {} 187 while p.csr().read().ph_ret() {}
@@ -193,12 +189,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
193 189
194 #[inline] 190 #[inline]
195 pub fn counter(&self) -> u16 { 191 pub fn counter(&self) -> u16 {
196 unsafe { self.inner.regs().ctr().read().ctr() } 192 self.inner.regs().ctr().read().ctr()
197 } 193 }
198 194
199 #[inline] 195 #[inline]
200 pub fn set_counter(&self, ctr: u16) { 196 pub fn set_counter(&self, ctr: u16) {
201 unsafe { self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) } 197 self.inner.regs().ctr().write(|w| w.set_ctr(ctr))
202 } 198 }
203 199
204 #[inline] 200 #[inline]
@@ -209,14 +205,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
209 205
210 #[inline] 206 #[inline]
211 pub fn wrapped(&mut self) -> bool { 207 pub fn wrapped(&mut self) -> bool {
212 unsafe { pac::PWM.intr().read().0 & self.bit() != 0 } 208 pac::PWM.intr().read().0 & self.bit() != 0
213 } 209 }
214 210
215 #[inline] 211 #[inline]
216 pub fn clear_wrapped(&mut self) { 212 pub fn clear_wrapped(&mut self) {
217 unsafe { 213 pac::PWM.intr().write_value(Intr(self.bit() as _));
218 pac::PWM.intr().write_value(Intr(self.bit() as _));
219 }
220 } 214 }
221 215
222 #[inline] 216 #[inline]
@@ -237,26 +231,22 @@ impl PwmBatch {
237 pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { 231 pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) {
238 let mut en = PwmBatch(0); 232 let mut en = PwmBatch(0);
239 batch(&mut en); 233 batch(&mut en);
240 unsafe { 234 if enabled {
241 if enabled { 235 pac::PWM.en().write_set(|w| w.0 = en.0);
242 pac::PWM.en().write_set(|w| w.0 = en.0); 236 } else {
243 } else { 237 pac::PWM.en().write_clear(|w| w.0 = en.0);
244 pac::PWM.en().write_clear(|w| w.0 = en.0);
245 }
246 } 238 }
247 } 239 }
248} 240}
249 241
250impl<'d, T: Channel> Drop for Pwm<'d, T> { 242impl<'d, T: Channel> Drop for Pwm<'d, T> {
251 fn drop(&mut self) { 243 fn drop(&mut self) {
252 unsafe { 244 self.inner.regs().csr().write_clear(|w| w.set_en(false));
253 self.inner.regs().csr().write_clear(|w| w.set_en(false)); 245 if let Some(pin) = &self.pin_a {
254 if let Some(pin) = &self.pin_a { 246 pin.io().ctrl().write(|w| w.set_funcsel(31));
255 pin.io().ctrl().write(|w| w.set_funcsel(31)); 247 }
256 } 248 if let Some(pin) = &self.pin_b {
257 if let Some(pin) = &self.pin_b { 249 pin.io().ctrl().write(|w| w.set_funcsel(31));
258 pin.io().ctrl().write(|w| w.set_funcsel(31));
259 }
260 } 250 }
261 } 251 }
262} 252}
diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs
index edd47c223..70512fa14 100644
--- a/embassy-rp/src/reset.rs
+++ b/embassy-rp/src/reset.rs
@@ -4,11 +4,11 @@ use crate::pac;
4 4
5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); 5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff);
6 6
7pub unsafe fn reset(peris: Peripherals) { 7pub(crate) fn reset(peris: Peripherals) {
8 pac::RESETS.reset().write_value(peris); 8 pac::RESETS.reset().write_value(peris);
9} 9}
10 10
11pub unsafe fn unreset_wait(peris: Peripherals) { 11pub(crate) fn unreset_wait(peris: Peripherals) {
12 // TODO use the "atomic clear" register version 12 // TODO use the "atomic clear" register version
13 pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0)); 13 pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0));
14 while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} 14 while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {}
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index e1d886d4a..b18f12fc4 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -26,7 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
26 into_ref!(inner); 26 into_ref!(inner);
27 27
28 // Set the RTC divider 28 // Set the RTC divider
29 unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) }; 29 inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
30 30
31 let mut result = Self { inner }; 31 let mut result = Self { inner };
32 result.set_leap_year_check(true); // should be on by default, make sure this is the case. 32 result.set_leap_year_check(true); // should be on by default, make sure this is the case.
@@ -38,17 +38,14 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
38 /// 38 ///
39 /// Leap year checking is enabled by default. 39 /// Leap year checking is enabled by default.
40 pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { 40 pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
41 unsafe { 41 self.inner.regs().ctrl().modify(|w| {
42 self.inner 42 w.set_force_notleapyear(!leap_year_check_enabled);
43 .regs() 43 });
44 .ctrl()
45 .modify(|w| w.set_force_notleapyear(!leap_year_check_enabled))
46 };
47 } 44 }
48 45
49 /// Checks to see if this RealTimeClock is running 46 /// Checks to see if this RealTimeClock is running
50 pub fn is_running(&self) -> bool { 47 pub fn is_running(&self) -> bool {
51 unsafe { self.inner.regs().ctrl().read().rtc_active() } 48 self.inner.regs().ctrl().read().rtc_active()
52 } 49 }
53 50
54 /// Set the datetime to a new value. 51 /// Set the datetime to a new value.
@@ -60,25 +57,23 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
60 self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; 57 self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
61 58
62 // disable RTC while we configure it 59 // disable RTC while we configure it
63 unsafe { 60 self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
64 self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); 61 while self.inner.regs().ctrl().read().rtc_active() {
65 while self.inner.regs().ctrl().read().rtc_active() { 62 core::hint::spin_loop();
66 core::hint::spin_loop(); 63 }
67 } 64
68 65 self.inner.regs().setup_0().write(|w| {
69 self.inner.regs().setup_0().write(|w| { 66 self::datetime::write_setup_0(&t, w);
70 self::datetime::write_setup_0(&t, w); 67 });
71 }); 68 self.inner.regs().setup_1().write(|w| {
72 self.inner.regs().setup_1().write(|w| { 69 self::datetime::write_setup_1(&t, w);
73 self::datetime::write_setup_1(&t, w); 70 });
74 }); 71
75 72 // Load the new datetime and re-enable RTC
76 // Load the new datetime and re-enable RTC 73 self.inner.regs().ctrl().write(|w| w.set_load(true));
77 self.inner.regs().ctrl().write(|w| w.set_load(true)); 74 self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true));
78 self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); 75 while !self.inner.regs().ctrl().read().rtc_active() {
79 while !self.inner.regs().ctrl().read().rtc_active() { 76 core::hint::spin_loop();
80 core::hint::spin_loop();
81 }
82 } 77 }
83 Ok(()) 78 Ok(())
84 } 79 }
@@ -93,8 +88,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
93 return Err(RtcError::NotRunning); 88 return Err(RtcError::NotRunning);
94 } 89 }
95 90
96 let rtc_0 = unsafe { self.inner.regs().rtc_0().read() }; 91 let rtc_0 = self.inner.regs().rtc_0().read();
97 let rtc_1 = unsafe { self.inner.regs().rtc_1().read() }; 92 let rtc_1 = self.inner.regs().rtc_1().read();
98 93
99 self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime) 94 self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime)
100 } 95 }
@@ -103,12 +98,10 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
103 /// 98 ///
104 /// [`schedule_alarm`]: #method.schedule_alarm 99 /// [`schedule_alarm`]: #method.schedule_alarm
105 pub fn disable_alarm(&mut self) { 100 pub fn disable_alarm(&mut self) {
106 unsafe { 101 self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
107 self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
108 102
109 while self.inner.regs().irq_setup_0().read().match_active() { 103 while self.inner.regs().irq_setup_0().read().match_active() {
110 core::hint::spin_loop(); 104 core::hint::spin_loop();
111 }
112 } 105 }
113 } 106 }
114 107
@@ -132,21 +125,19 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
132 pub fn schedule_alarm(&mut self, filter: DateTimeFilter) { 125 pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
133 self.disable_alarm(); 126 self.disable_alarm();
134 127
135 unsafe { 128 self.inner.regs().irq_setup_0().write(|w| {
136 self.inner.regs().irq_setup_0().write(|w| { 129 filter.write_setup_0(w);
137 filter.write_setup_0(w); 130 });
138 }); 131 self.inner.regs().irq_setup_1().write(|w| {
139 self.inner.regs().irq_setup_1().write(|w| { 132 filter.write_setup_1(w);
140 filter.write_setup_1(w); 133 });
141 }); 134
142 135 self.inner.regs().inte().modify(|w| w.set_rtc(true));
143 self.inner.regs().inte().modify(|w| w.set_rtc(true)); 136
144 137 // Set the enable bit and check if it is set
145 // Set the enable bit and check if it is set 138 self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true));
146 self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true)); 139 while !self.inner.regs().irq_setup_0().read().match_active() {
147 while !self.inner.regs().irq_setup_0().read().match_active() { 140 core::hint::spin_loop();
148 core::hint::spin_loop();
149 }
150 } 141 }
151 } 142 }
152 143
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 7da214743..e817d074e 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -79,39 +79,37 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
79 ) -> Self { 79 ) -> Self {
80 into_ref!(inner); 80 into_ref!(inner);
81 81
82 unsafe { 82 let p = inner.regs();
83 let p = inner.regs(); 83 let (presc, postdiv) = calc_prescs(config.frequency);
84 let (presc, postdiv) = calc_prescs(config.frequency); 84
85 85 p.cpsr().write(|w| w.set_cpsdvsr(presc));
86 p.cpsr().write(|w| w.set_cpsdvsr(presc)); 86 p.cr0().write(|w| {
87 p.cr0().write(|w| { 87 w.set_dss(0b0111); // 8bit
88 w.set_dss(0b0111); // 8bit 88 w.set_spo(config.polarity == Polarity::IdleHigh);
89 w.set_spo(config.polarity == Polarity::IdleHigh); 89 w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
90 w.set_sph(config.phase == Phase::CaptureOnSecondTransition); 90 w.set_scr(postdiv);
91 w.set_scr(postdiv); 91 });
92 }); 92
93 93 // Always enable DREQ signals -- harmless if DMA is not listening
94 // Always enable DREQ signals -- harmless if DMA is not listening 94 p.dmacr().write(|reg| {
95 p.dmacr().write(|reg| { 95 reg.set_rxdmae(true);
96 reg.set_rxdmae(true); 96 reg.set_txdmae(true);
97 reg.set_txdmae(true); 97 });
98 }); 98
99 99 // finally, enable.
100 // finally, enable. 100 p.cr1().write(|w| w.set_sse(true));
101 p.cr1().write(|w| w.set_sse(true)); 101
102 102 if let Some(pin) = &clk {
103 if let Some(pin) = &clk { 103 pin.io().ctrl().write(|w| w.set_funcsel(1));
104 pin.io().ctrl().write(|w| w.set_funcsel(1)); 104 }
105 } 105 if let Some(pin) = &mosi {
106 if let Some(pin) = &mosi { 106 pin.io().ctrl().write(|w| w.set_funcsel(1));
107 pin.io().ctrl().write(|w| w.set_funcsel(1)); 107 }
108 } 108 if let Some(pin) = &miso {
109 if let Some(pin) = &miso { 109 pin.io().ctrl().write(|w| w.set_funcsel(1));
110 pin.io().ctrl().write(|w| w.set_funcsel(1)); 110 }
111 } 111 if let Some(pin) = &cs {
112 if let Some(pin) = &cs { 112 pin.io().ctrl().write(|w| w.set_funcsel(1));
113 pin.io().ctrl().write(|w| w.set_funcsel(1));
114 }
115 } 113 }
116 Self { 114 Self {
117 inner, 115 inner,
@@ -122,60 +120,52 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
122 } 120 }
123 121
124 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { 122 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
125 unsafe { 123 let p = self.inner.regs();
126 let p = self.inner.regs(); 124 for &b in data {
127 for &b in data { 125 while !p.sr().read().tnf() {}
128 while !p.sr().read().tnf() {} 126 p.dr().write(|w| w.set_data(b as _));
129 p.dr().write(|w| w.set_data(b as _)); 127 while !p.sr().read().rne() {}
130 while !p.sr().read().rne() {} 128 let _ = p.dr().read();
131 let _ = p.dr().read();
132 }
133 } 129 }
134 self.flush()?; 130 self.flush()?;
135 Ok(()) 131 Ok(())
136 } 132 }
137 133
138 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { 134 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
139 unsafe { 135 let p = self.inner.regs();
140 let p = self.inner.regs(); 136 for b in data {
141 for b in data { 137 while !p.sr().read().tnf() {}
142 while !p.sr().read().tnf() {} 138 p.dr().write(|w| w.set_data(*b as _));
143 p.dr().write(|w| w.set_data(*b as _)); 139 while !p.sr().read().rne() {}
144 while !p.sr().read().rne() {} 140 *b = p.dr().read().data() as u8;
145 *b = p.dr().read().data() as u8;
146 }
147 } 141 }
148 self.flush()?; 142 self.flush()?;
149 Ok(()) 143 Ok(())
150 } 144 }
151 145
152 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { 146 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
153 unsafe { 147 let p = self.inner.regs();
154 let p = self.inner.regs(); 148 for b in data {
155 for b in data { 149 while !p.sr().read().tnf() {}
156 while !p.sr().read().tnf() {} 150 p.dr().write(|w| w.set_data(0));
157 p.dr().write(|w| w.set_data(0)); 151 while !p.sr().read().rne() {}
158 while !p.sr().read().rne() {} 152 *b = p.dr().read().data() as u8;
159 *b = p.dr().read().data() as u8;
160 }
161 } 153 }
162 self.flush()?; 154 self.flush()?;
163 Ok(()) 155 Ok(())
164 } 156 }
165 157
166 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { 158 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
167 unsafe { 159 let p = self.inner.regs();
168 let p = self.inner.regs(); 160 let len = read.len().max(write.len());
169 let len = read.len().max(write.len()); 161 for i in 0..len {
170 for i in 0..len { 162 let wb = write.get(i).copied().unwrap_or(0);
171 let wb = write.get(i).copied().unwrap_or(0); 163 while !p.sr().read().tnf() {}
172 while !p.sr().read().tnf() {} 164 p.dr().write(|w| w.set_data(wb as _));
173 p.dr().write(|w| w.set_data(wb as _)); 165 while !p.sr().read().rne() {}
174 while !p.sr().read().rne() {} 166 let rb = p.dr().read().data() as u8;
175 let rb = p.dr().read().data() as u8; 167 if let Some(r) = read.get_mut(i) {
176 if let Some(r) = read.get_mut(i) { 168 *r = rb;
177 *r = rb;
178 }
179 } 169 }
180 } 170 }
181 self.flush()?; 171 self.flush()?;
@@ -183,29 +173,25 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
183 } 173 }
184 174
185 pub fn flush(&mut self) -> Result<(), Error> { 175 pub fn flush(&mut self) -> Result<(), Error> {
186 unsafe { 176 let p = self.inner.regs();
187 let p = self.inner.regs(); 177 while p.sr().read().bsy() {}
188 while p.sr().read().bsy() {}
189 }
190 Ok(()) 178 Ok(())
191 } 179 }
192 180
193 pub fn set_frequency(&mut self, freq: u32) { 181 pub fn set_frequency(&mut self, freq: u32) {
194 let (presc, postdiv) = calc_prescs(freq); 182 let (presc, postdiv) = calc_prescs(freq);
195 let p = self.inner.regs(); 183 let p = self.inner.regs();
196 unsafe { 184 // disable
197 // disable 185 p.cr1().write(|w| w.set_sse(false));
198 p.cr1().write(|w| w.set_sse(false)); 186
199 187 // change stuff
200 // change stuff 188 p.cpsr().write(|w| w.set_cpsdvsr(presc));
201 p.cpsr().write(|w| w.set_cpsdvsr(presc)); 189 p.cr0().modify(|w| {
202 p.cr0().modify(|w| { 190 w.set_scr(postdiv);
203 w.set_scr(postdiv); 191 });
204 }); 192
205 193 // enable
206 // enable 194 p.cr1().write(|w| w.set_sse(true));
207 p.cr1().write(|w| w.set_sse(true));
208 }
209 } 195 }
210} 196}
211 197
@@ -337,21 +323,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
337 let tx_transfer = unsafe { 323 let tx_transfer = unsafe {
338 // If we don't assign future to a variable, the data register pointer 324 // If we don't assign future to a variable, the data register pointer
339 // is held across an await and makes the future non-Send. 325 // is held across an await and makes the future non-Send.
340 crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) 326 crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ)
341 }; 327 };
342 tx_transfer.await; 328 tx_transfer.await;
343 329
344 let p = self.inner.regs(); 330 let p = self.inner.regs();
345 unsafe { 331 while p.sr().read().bsy() {}
346 while p.sr().read().bsy() {}
347 332
348 // clear RX FIFO contents to prevent stale reads 333 // clear RX FIFO contents to prevent stale reads
349 while p.sr().read().rne() { 334 while p.sr().read().rne() {
350 let _: u16 = p.dr().read().data(); 335 let _: u16 = p.dr().read().data();
351 }
352 // clear RX overrun interrupt
353 p.icr().write(|w| w.set_roric(true));
354 } 336 }
337 // clear RX overrun interrupt
338 p.icr().write(|w| w.set_roric(true));
355 339
356 Ok(()) 340 Ok(())
357 } 341 }
@@ -363,14 +347,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
363 let rx_transfer = unsafe { 347 let rx_transfer = unsafe {
364 // If we don't assign future to a variable, the data register pointer 348 // If we don't assign future to a variable, the data register pointer
365 // is held across an await and makes the future non-Send. 349 // is held across an await and makes the future non-Send.
366 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) 350 crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ)
367 }; 351 };
368 352
369 let tx_ch = self.tx_dma.as_mut().unwrap(); 353 let tx_ch = self.tx_dma.as_mut().unwrap();
370 let tx_transfer = unsafe { 354 let tx_transfer = unsafe {
371 // If we don't assign future to a variable, the data register pointer 355 // If we don't assign future to a variable, the data register pointer
372 // is held across an await and makes the future non-Send. 356 // is held across an await and makes the future non-Send.
373 crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ) 357 crate::dma::write_repeated(
358 tx_ch,
359 self.inner.regs().dr().as_ptr() as *mut u8,
360 buffer.len(),
361 T::TX_DREQ,
362 )
374 }; 363 };
375 join(tx_transfer, rx_transfer).await; 364 join(tx_transfer, rx_transfer).await;
376 Ok(()) 365 Ok(())
@@ -394,7 +383,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
394 let rx_transfer = unsafe { 383 let rx_transfer = unsafe {
395 // If we don't assign future to a variable, the data register pointer 384 // If we don't assign future to a variable, the data register pointer
396 // is held across an await and makes the future non-Send. 385 // is held across an await and makes the future non-Send.
397 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) 386 crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx_ptr, T::RX_DREQ)
398 }; 387 };
399 388
400 let mut tx_ch = self.tx_dma.as_mut().unwrap(); 389 let mut tx_ch = self.tx_dma.as_mut().unwrap();
@@ -403,13 +392,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
403 let tx_transfer = async { 392 let tx_transfer = async {
404 let p = self.inner.regs(); 393 let p = self.inner.regs();
405 unsafe { 394 unsafe {
406 crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await; 395 crate::dma::write(&mut tx_ch, tx_ptr, p.dr().as_ptr() as *mut _, T::TX_DREQ).await;
407 396
408 if rx_len > tx_len { 397 if rx_len > tx_len {
409 let write_bytes_len = rx_len - tx_len; 398 let write_bytes_len = rx_len - tx_len;
410 // write dummy data 399 // write dummy data
411 // this will disable incrementation of the buffers 400 // this will disable incrementation of the buffers
412 crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await 401 crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
413 } 402 }
414 } 403 }
415 }; 404 };
@@ -418,16 +407,14 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
418 // if tx > rx we should clear any overflow of the FIFO SPI buffer 407 // if tx > rx we should clear any overflow of the FIFO SPI buffer
419 if tx_len > rx_len { 408 if tx_len > rx_len {
420 let p = self.inner.regs(); 409 let p = self.inner.regs();
421 unsafe { 410 while p.sr().read().bsy() {}
422 while p.sr().read().bsy() {}
423 411
424 // clear RX FIFO contents to prevent stale reads 412 // clear RX FIFO contents to prevent stale reads
425 while p.sr().read().rne() { 413 while p.sr().read().rne() {
426 let _: u16 = p.dr().read().data(); 414 let _: u16 = p.dr().read().data();
427 }
428 // clear RX overrun interrupt
429 p.icr().write(|w| w.set_roric(true));
430 } 415 }
416 // clear RX overrun interrupt
417 p.icr().write(|w| w.set_roric(true));
431 } 418 }
432 419
433 Ok(()) 420 Ok(())
@@ -625,14 +612,12 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
625 fn set_config(&mut self, config: &Self::Config) { 612 fn set_config(&mut self, config: &Self::Config) {
626 let p = self.inner.regs(); 613 let p = self.inner.regs();
627 let (presc, postdiv) = calc_prescs(config.frequency); 614 let (presc, postdiv) = calc_prescs(config.frequency);
628 unsafe { 615 p.cpsr().write(|w| w.set_cpsdvsr(presc));
629 p.cpsr().write(|w| w.set_cpsdvsr(presc)); 616 p.cr0().write(|w| {
630 p.cr0().write(|w| { 617 w.set_dss(0b0111); // 8bit
631 w.set_dss(0b0111); // 8bit 618 w.set_spo(config.polarity == Polarity::IdleHigh);
632 w.set_spo(config.polarity == Polarity::IdleHigh); 619 w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
633 w.set_sph(config.phase == Phase::CaptureOnSecondTransition); 620 w.set_scr(postdiv);
634 w.set_scr(postdiv); 621 });
635 });
636 }
637 } 622 }
638} 623}
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index 68793950f..faa8df037 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::blocking_mutex::Mutex; 6use embassy_sync::blocking_mutex::Mutex;
7use embassy_time::driver::{AlarmHandle, Driver}; 7use embassy_time::driver::{AlarmHandle, Driver};
8 8
9use crate::interrupt::Interrupt; 9use crate::interrupt::InterruptExt;
10use crate::{interrupt, pac}; 10use crate::{interrupt, pac};
11 11
12struct AlarmState { 12struct AlarmState {
@@ -34,13 +34,11 @@ embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
34impl Driver for TimerDriver { 34impl Driver for TimerDriver {
35 fn now(&self) -> u64 { 35 fn now(&self) -> u64 {
36 loop { 36 loop {
37 unsafe { 37 let hi = pac::TIMER.timerawh().read();
38 let hi = pac::TIMER.timerawh().read(); 38 let lo = pac::TIMER.timerawl().read();
39 let lo = pac::TIMER.timerawl().read(); 39 let hi2 = pac::TIMER.timerawh().read();
40 let hi2 = pac::TIMER.timerawh().read(); 40 if hi == hi2 {
41 if hi == hi2 { 41 return (hi as u64) << 32 | (lo as u64);
42 return (hi as u64) << 32 | (lo as u64);
43 }
44 } 42 }
45 } 43 }
46 } 44 }
@@ -78,13 +76,13 @@ impl Driver for TimerDriver {
78 // Note that we're not checking the high bits at all. This means the irq may fire early 76 // Note that we're not checking the high bits at all. This means the irq may fire early
79 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire 77 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
80 // it is checked if the alarm time has passed. 78 // it is checked if the alarm time has passed.
81 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; 79 pac::TIMER.alarm(n).write_value(timestamp as u32);
82 80
83 let now = self.now(); 81 let now = self.now();
84 if timestamp <= now { 82 if timestamp <= now {
85 // If alarm timestamp has passed the alarm will not fire. 83 // If alarm timestamp has passed the alarm will not fire.
86 // Disarm the alarm and return `false` to indicate that. 84 // Disarm the alarm and return `false` to indicate that.
87 unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } 85 pac::TIMER.armed().write(|w| w.set_armed(1 << n));
88 86
89 alarm.timestamp.set(u64::MAX); 87 alarm.timestamp.set(u64::MAX);
90 88
@@ -106,17 +104,17 @@ impl TimerDriver {
106 } else { 104 } else {
107 // Not elapsed, arm it again. 105 // Not elapsed, arm it again.
108 // This can happen if it was set more than 2^32 us in the future. 106 // This can happen if it was set more than 2^32 us in the future.
109 unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; 107 pac::TIMER.alarm(n).write_value(timestamp as u32);
110 } 108 }
111 }); 109 });
112 110
113 // clear the irq 111 // clear the irq
114 unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) } 112 pac::TIMER.intr().write(|w| w.set_alarm(n, true));
115 } 113 }
116 114
117 fn trigger_alarm(&self, n: usize, cs: CriticalSection) { 115 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
118 // disarm 116 // disarm
119 unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } 117 pac::TIMER.armed().write(|w| w.set_armed(1 << n));
120 118
121 let alarm = &self.alarms.borrow(cs)[n]; 119 let alarm = &self.alarms.borrow(cs)[n];
122 alarm.timestamp.set(u64::MAX); 120 alarm.timestamp.set(u64::MAX);
@@ -145,28 +143,32 @@ pub unsafe fn init() {
145 w.set_alarm(2, true); 143 w.set_alarm(2, true);
146 w.set_alarm(3, true); 144 w.set_alarm(3, true);
147 }); 145 });
148 interrupt::TIMER_IRQ_0::enable(); 146 interrupt::TIMER_IRQ_0.enable();
149 interrupt::TIMER_IRQ_1::enable(); 147 interrupt::TIMER_IRQ_1.enable();
150 interrupt::TIMER_IRQ_2::enable(); 148 interrupt::TIMER_IRQ_2.enable();
151 interrupt::TIMER_IRQ_3::enable(); 149 interrupt::TIMER_IRQ_3.enable();
152} 150}
153 151
152#[cfg(feature = "rt")]
154#[interrupt] 153#[interrupt]
155unsafe fn TIMER_IRQ_0() { 154fn TIMER_IRQ_0() {
156 DRIVER.check_alarm(0) 155 DRIVER.check_alarm(0)
157} 156}
158 157
158#[cfg(feature = "rt")]
159#[interrupt] 159#[interrupt]
160unsafe fn TIMER_IRQ_1() { 160fn TIMER_IRQ_1() {
161 DRIVER.check_alarm(1) 161 DRIVER.check_alarm(1)
162} 162}
163 163
164#[cfg(feature = "rt")]
164#[interrupt] 165#[interrupt]
165unsafe fn TIMER_IRQ_2() { 166fn TIMER_IRQ_2() {
166 DRIVER.check_alarm(2) 167 DRIVER.check_alarm(2)
167} 168}
168 169
170#[cfg(feature = "rt")]
169#[interrupt] 171#[interrupt]
170unsafe fn TIMER_IRQ_3() { 172fn TIMER_IRQ_3() {
171 DRIVER.check_alarm(3) 173 DRIVER.check_alarm(3)
172} 174}
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index bb808c467..30eeb5476 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -3,14 +3,14 @@ use core::slice;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicU8, Ordering}; 5use atomic_polyfill::{AtomicU8, Ordering};
6use embassy_cortex_m::interrupt::{self, Binding, Interrupt};
7use embassy_hal_common::atomic_ring_buffer::RingBuffer; 6use embassy_hal_common::atomic_ring_buffer::RingBuffer;
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9use embassy_time::{Duration, Timer}; 8use embassy_time::{Duration, Timer};
10 9
11use super::*; 10use super::*;
12use crate::clocks::clk_peri_freq; 11use crate::clocks::clk_peri_freq;
13use crate::RegExt; 12use crate::interrupt::typelevel::{Binding, Interrupt};
13use crate::{interrupt, RegExt};
14 14
15pub struct State { 15pub struct State {
16 tx_waker: AtomicWaker, 16 tx_waker: AtomicWaker,
@@ -73,16 +73,14 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
73 // we clear it after it happens. The downside is that the we manually have 73 // we clear it after it happens. The downside is that the we manually have
74 // to pend the ISR when we want data transmission to start. 74 // to pend the ISR when we want data transmission to start.
75 let regs = T::regs(); 75 let regs = T::regs();
76 unsafe { 76 regs.uartimsc().write(|w| {
77 regs.uartimsc().write(|w| { 77 w.set_rxim(true);
78 w.set_rxim(true); 78 w.set_rtim(true);
79 w.set_rtim(true); 79 w.set_txim(true);
80 w.set_txim(true); 80 });
81 }); 81
82 82 T::Interrupt::unpend();
83 T::Interrupt::unpend(); 83 unsafe { T::Interrupt::enable() };
84 T::Interrupt::enable();
85 };
86} 84}
87 85
88impl<'d, T: Instance> BufferedUart<'d, T> { 86impl<'d, T: Instance> BufferedUart<'d, T> {
@@ -247,12 +245,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
247 // (Re-)Enable the interrupt to receive more data in case it was 245 // (Re-)Enable the interrupt to receive more data in case it was
248 // disabled because the buffer was full or errors were detected. 246 // disabled because the buffer was full or errors were detected.
249 let regs = T::regs(); 247 let regs = T::regs();
250 unsafe { 248 regs.uartimsc().write_set(|w| {
251 regs.uartimsc().write_set(|w| { 249 w.set_rxim(true);
252 w.set_rxim(true); 250 w.set_rtim(true);
253 w.set_rtim(true); 251 });
254 });
255 }
256 252
257 Poll::Ready(result) 253 Poll::Ready(result)
258 } 254 }
@@ -299,12 +295,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
299 // (Re-)Enable the interrupt to receive more data in case it was 295 // (Re-)Enable the interrupt to receive more data in case it was
300 // disabled because the buffer was full or errors were detected. 296 // disabled because the buffer was full or errors were detected.
301 let regs = T::regs(); 297 let regs = T::regs();
302 unsafe { 298 regs.uartimsc().write_set(|w| {
303 regs.uartimsc().write_set(|w| { 299 w.set_rxim(true);
304 w.set_rxim(true); 300 w.set_rtim(true);
305 w.set_rtim(true); 301 });
306 });
307 }
308 } 302 }
309} 303}
310 304
@@ -414,7 +408,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
414 } 408 }
415 409
416 pub fn busy(&self) -> bool { 410 pub fn busy(&self) -> bool {
417 unsafe { T::regs().uartfr().read().busy() } 411 T::regs().uartfr().read().busy()
418 } 412 }
419 413
420 /// Assert a break condition after waiting for the transmit buffers to empty, 414 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -426,42 +420,35 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
426 /// for the transmit fifo to empty, which may take a while on slow links. 420 /// for the transmit fifo to empty, which may take a while on slow links.
427 pub async fn send_break(&mut self, bits: u32) { 421 pub async fn send_break(&mut self, bits: u32) {
428 let regs = T::regs(); 422 let regs = T::regs();
429 let bits = bits.max(unsafe { 423 let bits = bits.max({
430 let lcr = regs.uartlcr_h().read(); 424 let lcr = regs.uartlcr_h().read();
431 let width = lcr.wlen() as u32 + 5; 425 let width = lcr.wlen() as u32 + 5;
432 let parity = lcr.pen() as u32; 426 let parity = lcr.pen() as u32;
433 let stops = 1 + lcr.stp2() as u32; 427 let stops = 1 + lcr.stp2() as u32;
434 2 * (1 + width + parity + stops) 428 2 * (1 + width + parity + stops)
435 }); 429 });
436 let divx64 = unsafe { 430 let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
437 ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 431 + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
438 } as u64;
439 let div_clk = clk_peri_freq() as u64 * 64; 432 let div_clk = clk_peri_freq() as u64 * 64;
440 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; 433 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
441 434
442 Self::flush().await.unwrap(); 435 Self::flush().await.unwrap();
443 while self.busy() {} 436 while self.busy() {}
444 unsafe { 437 regs.uartlcr_h().write_set(|w| w.set_brk(true));
445 regs.uartlcr_h().write_set(|w| w.set_brk(true));
446 }
447 Timer::after(Duration::from_micros(wait_usecs)).await; 438 Timer::after(Duration::from_micros(wait_usecs)).await;
448 unsafe { 439 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
449 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
450 }
451 } 440 }
452} 441}
453 442
454impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { 443impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
455 fn drop(&mut self) { 444 fn drop(&mut self) {
456 let state = T::buffered_state(); 445 let state = T::buffered_state();
457 unsafe { 446 unsafe { state.rx_buf.deinit() }
458 state.rx_buf.deinit();
459 447
460 // TX is inactive if the the buffer is not available. 448 // TX is inactive if the the buffer is not available.
461 // We can now unregister the interrupt handler 449 // We can now unregister the interrupt handler
462 if state.tx_buf.len() == 0 { 450 if state.tx_buf.len() == 0 {
463 T::Interrupt::disable(); 451 T::Interrupt::disable();
464 }
465 } 452 }
466 } 453 }
467} 454}
@@ -469,14 +456,12 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
469impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { 456impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
470 fn drop(&mut self) { 457 fn drop(&mut self) {
471 let state = T::buffered_state(); 458 let state = T::buffered_state();
472 unsafe { 459 unsafe { state.tx_buf.deinit() }
473 state.tx_buf.deinit();
474 460
475 // RX is inactive if the the buffer is not available. 461 // RX is inactive if the the buffer is not available.
476 // We can now unregister the interrupt handler 462 // We can now unregister the interrupt handler
477 if state.rx_buf.len() == 0 { 463 if state.rx_buf.len() == 0 {
478 T::Interrupt::disable(); 464 T::Interrupt::disable();
479 }
480 } 465 }
481 } 466 }
482} 467}
@@ -485,7 +470,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
485 _uart: PhantomData<T>, 470 _uart: PhantomData<T>,
486} 471}
487 472
488impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> { 473impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
489 unsafe fn on_interrupt() { 474 unsafe fn on_interrupt() {
490 let r = T::regs(); 475 let r = T::regs();
491 if r.uartdmacr().read().rxdmae() { 476 if r.uartdmacr().read().rxdmae() {
@@ -494,94 +479,92 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<
494 479
495 let s = T::buffered_state(); 480 let s = T::buffered_state();
496 481
497 unsafe { 482 // Clear TX and error interrupt flags
498 // Clear TX and error interrupt flags 483 // RX interrupt flags are cleared by reading from the FIFO.
499 // RX interrupt flags are cleared by reading from the FIFO. 484 let ris = r.uartris().read();
500 let ris = r.uartris().read(); 485 r.uarticr().write(|w| {
501 r.uarticr().write(|w| { 486 w.set_txic(ris.txris());
502 w.set_txic(ris.txris()); 487 w.set_feic(ris.feris());
503 w.set_feic(ris.feris()); 488 w.set_peic(ris.peris());
504 w.set_peic(ris.peris()); 489 w.set_beic(ris.beris());
505 w.set_beic(ris.beris()); 490 w.set_oeic(ris.oeris());
506 w.set_oeic(ris.oeris()); 491 });
507 });
508 492
509 trace!("on_interrupt ris={:#X}", ris.0); 493 trace!("on_interrupt ris={:#X}", ris.0);
510 494
511 // Errors 495 // Errors
512 if ris.feris() { 496 if ris.feris() {
513 warn!("Framing error"); 497 warn!("Framing error");
514 } 498 }
515 if ris.peris() { 499 if ris.peris() {
516 warn!("Parity error"); 500 warn!("Parity error");
517 } 501 }
518 if ris.beris() { 502 if ris.beris() {
519 warn!("Break error"); 503 warn!("Break error");
520 } 504 }
521 if ris.oeris() { 505 if ris.oeris() {
522 warn!("Overrun error"); 506 warn!("Overrun error");
523 } 507 }
524 508
525 // RX 509 // RX
526 let mut rx_writer = s.rx_buf.writer(); 510 let mut rx_writer = unsafe { s.rx_buf.writer() };
527 let rx_buf = rx_writer.push_slice(); 511 let rx_buf = rx_writer.push_slice();
528 let mut n_read = 0; 512 let mut n_read = 0;
529 let mut error = false; 513 let mut error = false;
530 for rx_byte in rx_buf { 514 for rx_byte in rx_buf {
531 if r.uartfr().read().rxfe() { 515 if r.uartfr().read().rxfe() {
532 break; 516 break;
533 }
534 let dr = r.uartdr().read();
535 if (dr.0 >> 8) != 0 {
536 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
537 error = true;
538 // only fill the buffer with valid characters. the current character is fine
539 // if the error is an overrun, but if we add it to the buffer we'll report
540 // the overrun one character too late. drop it instead and pretend we were
541 // a bit slower at draining the rx fifo than we actually were.
542 // this is consistent with blocking uart error reporting.
543 break;
544 }
545 *rx_byte = dr.data();
546 n_read += 1;
547 }
548 if n_read > 0 {
549 rx_writer.push_done(n_read);
550 s.rx_waker.wake();
551 } else if error {
552 s.rx_waker.wake();
553 } 517 }
554 // Disable any further RX interrupts when the buffer becomes full or 518 let dr = r.uartdr().read();
555 // errors have occurred. This lets us buffer additional errors in the 519 if (dr.0 >> 8) != 0 {
556 // fifo without needing more error storage locations, and most applications 520 s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed);
557 // will want to do a full reset of their uart state anyway once an error 521 error = true;
558 // has happened. 522 // only fill the buffer with valid characters. the current character is fine
559 if s.rx_buf.is_full() || error { 523 // if the error is an overrun, but if we add it to the buffer we'll report
560 r.uartimsc().write_clear(|w| { 524 // the overrun one character too late. drop it instead and pretend we were
561 w.set_rxim(true); 525 // a bit slower at draining the rx fifo than we actually were.
562 w.set_rtim(true); 526 // this is consistent with blocking uart error reporting.
563 }); 527 break;
564 } 528 }
529 *rx_byte = dr.data();
530 n_read += 1;
531 }
532 if n_read > 0 {
533 rx_writer.push_done(n_read);
534 s.rx_waker.wake();
535 } else if error {
536 s.rx_waker.wake();
537 }
538 // Disable any further RX interrupts when the buffer becomes full or
539 // errors have occurred. This lets us buffer additional errors in the
540 // fifo without needing more error storage locations, and most applications
541 // will want to do a full reset of their uart state anyway once an error
542 // has happened.
543 if s.rx_buf.is_full() || error {
544 r.uartimsc().write_clear(|w| {
545 w.set_rxim(true);
546 w.set_rtim(true);
547 });
548 }
565 549
566 // TX 550 // TX
567 let mut tx_reader = s.tx_buf.reader(); 551 let mut tx_reader = unsafe { s.tx_buf.reader() };
568 let tx_buf = tx_reader.pop_slice(); 552 let tx_buf = tx_reader.pop_slice();
569 let mut n_written = 0; 553 let mut n_written = 0;
570 for tx_byte in tx_buf.iter_mut() { 554 for tx_byte in tx_buf.iter_mut() {
571 if r.uartfr().read().txff() { 555 if r.uartfr().read().txff() {
572 break; 556 break;
573 }
574 r.uartdr().write(|w| w.set_data(*tx_byte));
575 n_written += 1;
576 }
577 if n_written > 0 {
578 tx_reader.pop_done(n_written);
579 s.tx_waker.wake();
580 } 557 }
581 // The TX interrupt only triggers once when the FIFO threshold is 558 r.uartdr().write(|w| w.set_data(*tx_byte));
582 // crossed. No need to disable it when the buffer becomes empty 559 n_written += 1;
583 // as it does re-trigger anymore once we have cleared it. 560 }
561 if n_written > 0 {
562 tx_reader.pop_done(n_written);
563 s.tx_waker.wake();
584 } 564 }
565 // The TX interrupt only triggers once when the FIFO threshold is
566 // crossed. No need to disable it when the buffer becomes empty
567 // as it does re-trigger anymore once we have cleared it.
585 } 568 }
586} 569}
587 570
@@ -695,24 +678,22 @@ mod eh02 {
695 678
696 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 679 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
697 let r = T::regs(); 680 let r = T::regs();
698 unsafe { 681 if r.uartfr().read().rxfe() {
699 if r.uartfr().read().rxfe() { 682 return Err(nb::Error::WouldBlock);
700 return Err(nb::Error::WouldBlock); 683 }
701 }
702 684
703 let dr = r.uartdr().read(); 685 let dr = r.uartdr().read();
704 686
705 if dr.oe() { 687 if dr.oe() {
706 Err(nb::Error::Other(Error::Overrun)) 688 Err(nb::Error::Other(Error::Overrun))
707 } else if dr.be() { 689 } else if dr.be() {
708 Err(nb::Error::Other(Error::Break)) 690 Err(nb::Error::Other(Error::Break))
709 } else if dr.pe() { 691 } else if dr.pe() {
710 Err(nb::Error::Other(Error::Parity)) 692 Err(nb::Error::Other(Error::Parity))
711 } else if dr.fe() { 693 } else if dr.fe() {
712 Err(nb::Error::Other(Error::Framing)) 694 Err(nb::Error::Other(Error::Framing))
713 } else { 695 } else {
714 Ok(dr.data()) 696 Ok(dr.data())
715 }
716 } 697 }
717 } 698 }
718 } 699 }
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index a83d94e49..7b94bce5e 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -3,7 +3,6 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicU16, Ordering}; 5use atomic_polyfill::{AtomicU16, Ordering};
6use embassy_cortex_m::interrupt::{self, Binding, Interrupt};
7use embassy_futures::select::{select, Either}; 6use embassy_futures::select::{select, Either};
8use embassy_hal_common::{into_ref, PeripheralRef}; 7use embassy_hal_common::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
@@ -14,8 +13,9 @@ use crate::clocks::clk_peri_freq;
14use crate::dma::{AnyChannel, Channel}; 13use crate::dma::{AnyChannel, Channel};
15use crate::gpio::sealed::Pin; 14use crate::gpio::sealed::Pin;
16use crate::gpio::AnyPin; 15use crate::gpio::AnyPin;
16use crate::interrupt::typelevel::{Binding, Interrupt};
17use crate::pac::io::vals::{Inover, Outover}; 17use crate::pac::io::vals::{Inover, Outover};
18use crate::{pac, peripherals, Peripheral, RegExt}; 18use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
19 19
20#[cfg(feature = "nightly")] 20#[cfg(feature = "nightly")]
21mod buffered; 21mod buffered;
@@ -146,23 +146,21 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
146 146
147 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 147 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
148 let r = T::regs(); 148 let r = T::regs();
149 unsafe { 149 for &b in buffer {
150 for &b in buffer { 150 while r.uartfr().read().txff() {}
151 while r.uartfr().read().txff() {} 151 r.uartdr().write(|w| w.set_data(b));
152 r.uartdr().write(|w| w.set_data(b));
153 }
154 } 152 }
155 Ok(()) 153 Ok(())
156 } 154 }
157 155
158 pub fn blocking_flush(&mut self) -> Result<(), Error> { 156 pub fn blocking_flush(&mut self) -> Result<(), Error> {
159 let r = T::regs(); 157 let r = T::regs();
160 unsafe { while !r.uartfr().read().txfe() {} } 158 while !r.uartfr().read().txfe() {}
161 Ok(()) 159 Ok(())
162 } 160 }
163 161
164 pub fn busy(&self) -> bool { 162 pub fn busy(&self) -> bool {
165 unsafe { T::regs().uartfr().read().busy() } 163 T::regs().uartfr().read().busy()
166 } 164 }
167 165
168 /// Assert a break condition after waiting for the transmit buffers to empty, 166 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -174,28 +172,23 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
174 /// for the transmit fifo to empty, which may take a while on slow links. 172 /// for the transmit fifo to empty, which may take a while on slow links.
175 pub async fn send_break(&mut self, bits: u32) { 173 pub async fn send_break(&mut self, bits: u32) {
176 let regs = T::regs(); 174 let regs = T::regs();
177 let bits = bits.max(unsafe { 175 let bits = bits.max({
178 let lcr = regs.uartlcr_h().read(); 176 let lcr = regs.uartlcr_h().read();
179 let width = lcr.wlen() as u32 + 5; 177 let width = lcr.wlen() as u32 + 5;
180 let parity = lcr.pen() as u32; 178 let parity = lcr.pen() as u32;
181 let stops = 1 + lcr.stp2() as u32; 179 let stops = 1 + lcr.stp2() as u32;
182 2 * (1 + width + parity + stops) 180 2 * (1 + width + parity + stops)
183 }); 181 });
184 let divx64 = unsafe { 182 let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
185 ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 183 + regs.uartfbrd().read().baud_divfrac() as u32) as u64;
186 } as u64;
187 let div_clk = clk_peri_freq() as u64 * 64; 184 let div_clk = clk_peri_freq() as u64 * 64;
188 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; 185 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
189 186
190 self.blocking_flush().unwrap(); 187 self.blocking_flush().unwrap();
191 while self.busy() {} 188 while self.busy() {}
192 unsafe { 189 regs.uartlcr_h().write_set(|w| w.set_brk(true));
193 regs.uartlcr_h().write_set(|w| w.set_brk(true));
194 }
195 Timer::after(Duration::from_micros(wait_usecs)).await; 190 Timer::after(Duration::from_micros(wait_usecs)).await;
196 unsafe { 191 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
197 regs.uartlcr_h().write_clear(|w| w.set_brk(true));
198 }
199 } 192 }
200} 193}
201 194
@@ -221,7 +214,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> {
221 }); 214 });
222 // If we don't assign future to a variable, the data register pointer 215 // If we don't assign future to a variable, the data register pointer
223 // is held across an await and makes the future non-Send. 216 // is held across an await and makes the future non-Send.
224 crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) 217 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ)
225 }; 218 };
226 transfer.await; 219 transfer.await;
227 Ok(()) 220 Ok(())
@@ -246,7 +239,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
246 debug_assert_eq!(has_irq, rx_dma.is_some()); 239 debug_assert_eq!(has_irq, rx_dma.is_some());
247 if has_irq { 240 if has_irq {
248 // disable all error interrupts initially 241 // disable all error interrupts initially
249 unsafe { T::regs().uartimsc().write(|w| w.0 = 0) } 242 T::regs().uartimsc().write(|w| w.0 = 0);
250 T::Interrupt::unpend(); 243 T::Interrupt::unpend();
251 unsafe { T::Interrupt::enable() }; 244 unsafe { T::Interrupt::enable() };
252 } 245 }
@@ -267,11 +260,11 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
267 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 260 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
268 let r = T::regs(); 261 let r = T::regs();
269 for (i, b) in buffer.iter_mut().enumerate() { 262 for (i, b) in buffer.iter_mut().enumerate() {
270 if unsafe { r.uartfr().read().rxfe() } { 263 if r.uartfr().read().rxfe() {
271 return Ok(i); 264 return Ok(i);
272 } 265 }
273 266
274 let dr = unsafe { r.uartdr().read() }; 267 let dr = r.uartdr().read();
275 268
276 if dr.oe() { 269 if dr.oe() {
277 return Err(Error::Overrun); 270 return Err(Error::Overrun);
@@ -292,15 +285,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
292impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { 285impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
293 fn drop(&mut self) { 286 fn drop(&mut self) {
294 if let Some(_) = self.rx_dma { 287 if let Some(_) = self.rx_dma {
295 unsafe { 288 T::Interrupt::disable();
296 T::Interrupt::disable(); 289 // clear dma flags. irq handlers use these to disambiguate among themselves.
297 // clear dma flags. irq handlers use these to disambiguate among themselves. 290 T::regs().uartdmacr().write_clear(|reg| {
298 T::regs().uartdmacr().write_clear(|reg| { 291 reg.set_rxdmae(true);
299 reg.set_rxdmae(true); 292 reg.set_txdmae(true);
300 reg.set_txdmae(true); 293 reg.set_dmaonerr(true);
301 reg.set_dmaonerr(true); 294 });
302 });
303 }
304 } 295 }
305 } 296 }
306} 297}
@@ -332,7 +323,7 @@ pub struct InterruptHandler<T: Instance> {
332 _uart: PhantomData<T>, 323 _uart: PhantomData<T>,
333} 324}
334 325
335impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 326impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
336 unsafe fn on_interrupt() { 327 unsafe fn on_interrupt() {
337 let uart = T::regs(); 328 let uart = T::regs();
338 if !uart.uartdmacr().read().rxdmae() { 329 if !uart.uartdmacr().read().rxdmae() {
@@ -355,14 +346,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
355 // clear error flags before we drain the fifo. errors that have accumulated 346 // clear error flags before we drain the fifo. errors that have accumulated
356 // in the flags will also be present in the fifo. 347 // in the flags will also be present in the fifo.
357 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 348 T::dma_state().rx_errs.store(0, Ordering::Relaxed);
358 unsafe { 349 T::regs().uarticr().write(|w| {
359 T::regs().uarticr().write(|w| { 350 w.set_oeic(true);
360 w.set_oeic(true); 351 w.set_beic(true);
361 w.set_beic(true); 352 w.set_peic(true);
362 w.set_peic(true); 353 w.set_feic(true);
363 w.set_feic(true); 354 });
364 });
365 }
366 355
367 // then drain the fifo. we need to read at most 32 bytes. errors that apply 356 // then drain the fifo. we need to read at most 32 bytes. errors that apply
368 // to fifo bytes will be reported directly. 357 // to fifo bytes will be reported directly.
@@ -379,20 +368,20 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
379 // interrupt flags will have been raised, and those will be picked up immediately 368 // interrupt flags will have been raised, and those will be picked up immediately
380 // by the interrupt handler. 369 // by the interrupt handler.
381 let ch = self.rx_dma.as_mut().unwrap(); 370 let ch = self.rx_dma.as_mut().unwrap();
371 T::regs().uartimsc().write_set(|w| {
372 w.set_oeim(true);
373 w.set_beim(true);
374 w.set_peim(true);
375 w.set_feim(true);
376 });
377 T::regs().uartdmacr().write_set(|reg| {
378 reg.set_rxdmae(true);
379 reg.set_dmaonerr(true);
380 });
382 let transfer = unsafe { 381 let transfer = unsafe {
383 T::regs().uartimsc().write_set(|w| {
384 w.set_oeim(true);
385 w.set_beim(true);
386 w.set_peim(true);
387 w.set_feim(true);
388 });
389 T::regs().uartdmacr().write_set(|reg| {
390 reg.set_rxdmae(true);
391 reg.set_dmaonerr(true);
392 });
393 // If we don't assign future to a variable, the data register pointer 382 // If we don't assign future to a variable, the data register pointer
394 // is held across an await and makes the future non-Send. 383 // is held across an await and makes the future non-Send.
395 crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) 384 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ)
396 }; 385 };
397 386
398 // wait for either the transfer to complete or an error to happen. 387 // wait for either the transfer to complete or an error to happen.
@@ -575,81 +564,79 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
575 config: Config, 564 config: Config,
576 ) { 565 ) {
577 let r = T::regs(); 566 let r = T::regs();
578 unsafe { 567 if let Some(pin) = &tx {
579 if let Some(pin) = &tx { 568 pin.io().ctrl().write(|w| {
580 pin.io().ctrl().write(|w| { 569 w.set_funcsel(2);
581 w.set_funcsel(2); 570 w.set_outover(if config.invert_tx {
582 w.set_outover(if config.invert_tx { 571 Outover::INVERT
583 Outover::INVERT 572 } else {
584 } else { 573 Outover::NORMAL
585 Outover::NORMAL
586 });
587 }); 574 });
588 pin.pad_ctrl().write(|w| w.set_ie(true)); 575 });
589 } 576 pin.pad_ctrl().write(|w| w.set_ie(true));
590 if let Some(pin) = &rx { 577 }
591 pin.io().ctrl().write(|w| { 578 if let Some(pin) = &rx {
592 w.set_funcsel(2); 579 pin.io().ctrl().write(|w| {
593 w.set_inover(if config.invert_rx { 580 w.set_funcsel(2);
594 Inover::INVERT 581 w.set_inover(if config.invert_rx {
595 } else { 582 Inover::INVERT
596 Inover::NORMAL 583 } else {
597 }); 584 Inover::NORMAL
598 }); 585 });
599 pin.pad_ctrl().write(|w| w.set_ie(true)); 586 });
600 } 587 pin.pad_ctrl().write(|w| w.set_ie(true));
601 if let Some(pin) = &cts { 588 }
602 pin.io().ctrl().write(|w| { 589 if let Some(pin) = &cts {
603 w.set_funcsel(2); 590 pin.io().ctrl().write(|w| {
604 w.set_inover(if config.invert_cts { 591 w.set_funcsel(2);
605 Inover::INVERT 592 w.set_inover(if config.invert_cts {
606 } else { 593 Inover::INVERT
607 Inover::NORMAL 594 } else {
608 }); 595 Inover::NORMAL
609 }); 596 });
610 pin.pad_ctrl().write(|w| w.set_ie(true)); 597 });
611 } 598 pin.pad_ctrl().write(|w| w.set_ie(true));
612 if let Some(pin) = &rts { 599 }
613 pin.io().ctrl().write(|w| { 600 if let Some(pin) = &rts {
614 w.set_funcsel(2); 601 pin.io().ctrl().write(|w| {
615 w.set_outover(if config.invert_rts { 602 w.set_funcsel(2);
616 Outover::INVERT 603 w.set_outover(if config.invert_rts {
617 } else { 604 Outover::INVERT
618 Outover::NORMAL 605 } else {
619 }); 606 Outover::NORMAL
620 }); 607 });
621 pin.pad_ctrl().write(|w| w.set_ie(true)); 608 });
622 } 609 pin.pad_ctrl().write(|w| w.set_ie(true));
610 }
623 611
624 Self::set_baudrate_inner(config.baudrate); 612 Self::set_baudrate_inner(config.baudrate);
625 613
626 let (pen, eps) = match config.parity { 614 let (pen, eps) = match config.parity {
627 Parity::ParityNone => (false, false), 615 Parity::ParityNone => (false, false),
628 Parity::ParityOdd => (true, false), 616 Parity::ParityOdd => (true, false),
629 Parity::ParityEven => (true, true), 617 Parity::ParityEven => (true, true),
630 }; 618 };
631 619
632 r.uartlcr_h().write(|w| { 620 r.uartlcr_h().write(|w| {
633 w.set_wlen(config.data_bits.bits()); 621 w.set_wlen(config.data_bits.bits());
634 w.set_stp2(config.stop_bits == StopBits::STOP2); 622 w.set_stp2(config.stop_bits == StopBits::STOP2);
635 w.set_pen(pen); 623 w.set_pen(pen);
636 w.set_eps(eps); 624 w.set_eps(eps);
637 w.set_fen(true); 625 w.set_fen(true);
638 }); 626 });
639 627
640 r.uartifls().write(|w| { 628 r.uartifls().write(|w| {
641 w.set_rxiflsel(0b000); 629 w.set_rxiflsel(0b000);
642 w.set_txiflsel(0b000); 630 w.set_txiflsel(0b000);
643 }); 631 });
644 632
645 r.uartcr().write(|w| { 633 r.uartcr().write(|w| {
646 w.set_uarten(true); 634 w.set_uarten(true);
647 w.set_rxe(true); 635 w.set_rxe(true);
648 w.set_txe(true); 636 w.set_txe(true);
649 w.set_ctsen(cts.is_some()); 637 w.set_ctsen(cts.is_some());
650 w.set_rtsen(rts.is_some()); 638 w.set_rtsen(rts.is_some());
651 }); 639 });
652 }
653 } 640 }
654 641
655 /// sets baudrate on runtime 642 /// sets baudrate on runtime
@@ -674,15 +661,13 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
674 baud_fbrd = 0; 661 baud_fbrd = 0;
675 } 662 }
676 663
677 unsafe { 664 // Load PL011's baud divisor registers
678 // Load PL011's baud divisor registers 665 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
679 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); 666 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
680 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
681 667
682 // PL011 needs a (dummy) line control register write to latch in the 668 // PL011 needs a (dummy) line control register write to latch in the
683 // divisors. We don't want to actually change LCR contents here. 669 // divisors. We don't want to actually change LCR contents here.
684 r.uartlcr_h().modify(|_| {}); 670 r.uartlcr_h().modify(|_| {});
685 }
686 } 671 }
687} 672}
688 673
@@ -731,24 +716,22 @@ mod eh02 {
731 type Error = Error; 716 type Error = Error;
732 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 717 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
733 let r = T::regs(); 718 let r = T::regs();
734 unsafe { 719 if r.uartfr().read().rxfe() {
735 if r.uartfr().read().rxfe() { 720 return Err(nb::Error::WouldBlock);
736 return Err(nb::Error::WouldBlock); 721 }
737 }
738 722
739 let dr = r.uartdr().read(); 723 let dr = r.uartdr().read();
740 724
741 if dr.oe() { 725 if dr.oe() {
742 Err(nb::Error::Other(Error::Overrun)) 726 Err(nb::Error::Other(Error::Overrun))
743 } else if dr.be() { 727 } else if dr.be() {
744 Err(nb::Error::Other(Error::Break)) 728 Err(nb::Error::Other(Error::Break))
745 } else if dr.pe() { 729 } else if dr.pe() {
746 Err(nb::Error::Other(Error::Parity)) 730 Err(nb::Error::Other(Error::Parity))
747 } else if dr.fe() { 731 } else if dr.fe() {
748 Err(nb::Error::Other(Error::Framing)) 732 Err(nb::Error::Other(Error::Framing))
749 } else { 733 } else {
750 Ok(dr.data()) 734 Ok(dr.data())
751 }
752 } 735 }
753 } 736 }
754 } 737 }
@@ -758,22 +741,18 @@ mod eh02 {
758 741
759 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { 742 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
760 let r = T::regs(); 743 let r = T::regs();
761 unsafe { 744 if r.uartfr().read().txff() {
762 if r.uartfr().read().txff() { 745 return Err(nb::Error::WouldBlock);
763 return Err(nb::Error::WouldBlock);
764 }
765
766 r.uartdr().write(|w| w.set_data(word));
767 } 746 }
747
748 r.uartdr().write(|w| w.set_data(word));
768 Ok(()) 749 Ok(())
769 } 750 }
770 751
771 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { 752 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
772 let r = T::regs(); 753 let r = T::regs();
773 unsafe { 754 if !r.uartfr().read().txfe() {
774 if !r.uartfr().read().txfe() { 755 return Err(nb::Error::WouldBlock);
775 return Err(nb::Error::WouldBlock);
776 }
777 } 756 }
778 Ok(()) 757 Ok(())
779 } 758 }
@@ -854,22 +833,20 @@ mod eh1 {
854 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { 833 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
855 fn read(&mut self) -> nb::Result<u8, Self::Error> { 834 fn read(&mut self) -> nb::Result<u8, Self::Error> {
856 let r = T::regs(); 835 let r = T::regs();
857 unsafe { 836 let dr = r.uartdr().read();
858 let dr = r.uartdr().read(); 837
859 838 if dr.oe() {
860 if dr.oe() { 839 Err(nb::Error::Other(Error::Overrun))
861 Err(nb::Error::Other(Error::Overrun)) 840 } else if dr.be() {
862 } else if dr.be() { 841 Err(nb::Error::Other(Error::Break))
863 Err(nb::Error::Other(Error::Break)) 842 } else if dr.pe() {
864 } else if dr.pe() { 843 Err(nb::Error::Other(Error::Parity))
865 Err(nb::Error::Other(Error::Parity)) 844 } else if dr.fe() {
866 } else if dr.fe() { 845 Err(nb::Error::Other(Error::Framing))
867 Err(nb::Error::Other(Error::Framing)) 846 } else if dr.fe() {
868 } else if dr.fe() { 847 Ok(dr.data())
869 Ok(dr.data()) 848 } else {
870 } else { 849 Err(nb::Error::WouldBlock)
871 Err(nb::Error::WouldBlock)
872 }
873 } 850 }
874 } 851 }
875 } 852 }
@@ -930,7 +907,7 @@ mod sealed {
930 const TX_DREQ: u8; 907 const TX_DREQ: u8;
931 const RX_DREQ: u8; 908 const RX_DREQ: u8;
932 909
933 type Interrupt: crate::interrupt::Interrupt; 910 type Interrupt: interrupt::typelevel::Interrupt;
934 911
935 fn regs() -> pac::uart::Uart; 912 fn regs() -> pac::uart::Uart;
936 913
@@ -968,7 +945,7 @@ macro_rules! impl_instance {
968 const TX_DREQ: u8 = $tx_dreq; 945 const TX_DREQ: u8 = $tx_dreq;
969 const RX_DREQ: u8 = $rx_dreq; 946 const RX_DREQ: u8 = $rx_dreq;
970 947
971 type Interrupt = crate::interrupt::$irq; 948 type Interrupt = crate::interrupt::typelevel::$irq;
972 949
973 fn regs() -> pac::uart::Uart { 950 fn regs() -> pac::uart::Uart {
974 pac::$inst 951 pac::$inst
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index cc88226df..b3f3bd927 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -4,15 +4,14 @@ use core::slice;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_cortex_m::interrupt::{self, Binding};
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9use embassy_usb_driver as driver; 8use embassy_usb_driver as driver;
10use embassy_usb_driver::{ 9use embassy_usb_driver::{
11 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, 10 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
12}; 11};
13 12
14use crate::interrupt::Interrupt; 13use crate::interrupt::typelevel::{Binding, Interrupt};
15use crate::{pac, peripherals, Peripheral, RegExt}; 14use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
16 15
17pub(crate) mod sealed { 16pub(crate) mod sealed {
18 pub trait Instance { 17 pub trait Instance {
@@ -22,7 +21,7 @@ pub(crate) mod sealed {
22} 21}
23 22
24pub trait Instance: sealed::Instance + 'static { 23pub trait Instance: sealed::Instance + 'static {
25 type Interrupt: Interrupt; 24 type Interrupt: interrupt::typelevel::Interrupt;
26} 25}
27 26
28impl crate::usb::sealed::Instance for peripherals::USB { 27impl crate::usb::sealed::Instance for peripherals::USB {
@@ -35,12 +34,12 @@ impl crate::usb::sealed::Instance for peripherals::USB {
35} 34}
36 35
37impl crate::usb::Instance for peripherals::USB { 36impl crate::usb::Instance for peripherals::USB {
38 type Interrupt = crate::interrupt::USBCTRL_IRQ; 37 type Interrupt = crate::interrupt::typelevel::USBCTRL_IRQ;
39} 38}
40 39
41const EP_COUNT: usize = 16; 40const EP_COUNT: usize = 16;
42const EP_MEMORY_SIZE: usize = 4096; 41const EP_MEMORY_SIZE: usize = 4096;
43const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.0; 42const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8;
44 43
45const NEW_AW: AtomicWaker = AtomicWaker::new(); 44const NEW_AW: AtomicWaker = AtomicWaker::new();
46static BUS_WAKER: AtomicWaker = NEW_AW; 45static BUS_WAKER: AtomicWaker = NEW_AW;
@@ -112,7 +111,7 @@ impl<'d, T: Instance> Driver<'d, T> {
112 let regs = T::regs(); 111 let regs = T::regs();
113 unsafe { 112 unsafe {
114 // zero fill regs 113 // zero fill regs
115 let p = regs.0 as *mut u32; 114 let p = regs.as_ptr() as *mut u32;
116 for i in 0..0x9c / 4 { 115 for i in 0..0x9c / 4 {
117 p.add(i).write_volatile(0) 116 p.add(i).write_volatile(0)
118 } 117 }
@@ -122,20 +121,20 @@ impl<'d, T: Instance> Driver<'d, T> {
122 for i in 0..0x100 / 4 { 121 for i in 0..0x100 / 4 {
123 p.add(i).write_volatile(0) 122 p.add(i).write_volatile(0)
124 } 123 }
125
126 regs.usb_muxing().write(|w| {
127 w.set_to_phy(true);
128 w.set_softcon(true);
129 });
130 regs.usb_pwr().write(|w| {
131 w.set_vbus_detect(true);
132 w.set_vbus_detect_override_en(true);
133 });
134 regs.main_ctrl().write(|w| {
135 w.set_controller_en(true);
136 });
137 } 124 }
138 125
126 regs.usb_muxing().write(|w| {
127 w.set_to_phy(true);
128 w.set_softcon(true);
129 });
130 regs.usb_pwr().write(|w| {
131 w.set_vbus_detect(true);
132 w.set_vbus_detect_override_en(true);
133 });
134 regs.main_ctrl().write(|w| {
135 w.set_controller_en(true);
136 });
137
139 // Initialize the bus so that it signals that power is available 138 // Initialize the bus so that it signals that power is available
140 BUS_WAKER.wake(); 139 BUS_WAKER.wake();
141 140
@@ -214,22 +213,18 @@ impl<'d, T: Instance> Driver<'d, T> {
214 }; 213 };
215 214
216 match D::dir() { 215 match D::dir() {
217 Direction::Out => unsafe { 216 Direction::Out => T::dpram().ep_out_control(index - 1).write(|w| {
218 T::dpram().ep_out_control(index - 1).write(|w| { 217 w.set_enable(false);
219 w.set_enable(false); 218 w.set_buffer_address(addr);
220 w.set_buffer_address(addr); 219 w.set_interrupt_per_buff(true);
221 w.set_interrupt_per_buff(true); 220 w.set_endpoint_type(ep_type_reg);
222 w.set_endpoint_type(ep_type_reg); 221 }),
223 }) 222 Direction::In => T::dpram().ep_in_control(index - 1).write(|w| {
224 }, 223 w.set_enable(false);
225 Direction::In => unsafe { 224 w.set_buffer_address(addr);
226 T::dpram().ep_in_control(index - 1).write(|w| { 225 w.set_interrupt_per_buff(true);
227 w.set_enable(false); 226 w.set_endpoint_type(ep_type_reg);
228 w.set_buffer_address(addr); 227 }),
229 w.set_interrupt_per_buff(true);
230 w.set_endpoint_type(ep_type_reg);
231 })
232 },
233 } 228 }
234 229
235 Ok(Endpoint { 230 Ok(Endpoint {
@@ -249,7 +244,7 @@ pub struct InterruptHandler<T: Instance> {
249 _uart: PhantomData<T>, 244 _uart: PhantomData<T>,
250} 245}
251 246
252impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 247impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
253 unsafe fn on_interrupt() { 248 unsafe fn on_interrupt() {
254 let regs = T::regs(); 249 let regs = T::regs();
255 //let x = regs.istr().read().0; 250 //let x = regs.istr().read().0;
@@ -316,22 +311,21 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
316 311
317 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 312 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
318 let regs = T::regs(); 313 let regs = T::regs();
319 unsafe { 314 regs.inte().write(|w| {
320 regs.inte().write(|w| { 315 w.set_bus_reset(true);
321 w.set_bus_reset(true); 316 w.set_buff_status(true);
322 w.set_buff_status(true); 317 w.set_dev_resume_from_host(true);
323 w.set_dev_resume_from_host(true); 318 w.set_dev_suspend(true);
324 w.set_dev_suspend(true); 319 w.set_setup_req(true);
325 w.set_setup_req(true); 320 });
326 }); 321 regs.int_ep_ctrl().write(|w| {
327 regs.int_ep_ctrl().write(|w| { 322 w.set_int_ep_active(0xFFFE); // all EPs
328 w.set_int_ep_active(0xFFFE); // all EPs 323 });
329 }); 324 regs.sie_ctrl().write(|w| {
330 regs.sie_ctrl().write(|w| { 325 w.set_ep0_int_1buf(true);
331 w.set_ep0_int_1buf(true); 326 w.set_pullup_en(true);
332 w.set_pullup_en(true); 327 });
333 }) 328
334 }
335 trace!("enabled"); 329 trace!("enabled");
336 330
337 ( 331 (
@@ -356,9 +350,10 @@ pub struct Bus<'d, T: Instance> {
356 350
357impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 351impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
358 async fn poll(&mut self) -> Event { 352 async fn poll(&mut self) -> Event {
359 poll_fn(move |cx| unsafe { 353 poll_fn(move |cx| {
360 BUS_WAKER.register(cx.waker()); 354 BUS_WAKER.register(cx.waker());
361 355
356 // TODO: implement VBUS detection.
362 if !self.inited { 357 if !self.inited {
363 self.inited = true; 358 self.inited = true;
364 return Poll::Ready(Event::PowerDetected); 359 return Poll::Ready(Event::PowerDetected);
@@ -426,14 +421,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
426 421
427 let n = ep_addr.index(); 422 let n = ep_addr.index();
428 match ep_addr.direction() { 423 match ep_addr.direction() {
429 Direction::In => unsafe { 424 Direction::In => {
430 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); 425 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
431 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { 426 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
432 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before 427 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
433 }); 428 });
434 EP_IN_WAKERS[n].wake(); 429 EP_IN_WAKERS[n].wake();
435 }, 430 }
436 Direction::Out => unsafe { 431 Direction::Out => {
437 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); 432 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
438 433
439 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { 434 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
@@ -447,7 +442,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
447 w.set_available(0, true); 442 w.set_available(0, true);
448 }); 443 });
449 EP_OUT_WAKERS[n].wake(); 444 EP_OUT_WAKERS[n].wake();
450 }, 445 }
451 } 446 }
452 } 447 }
453 448
@@ -505,7 +500,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
505 let index = self.info.addr.index(); 500 let index = self.info.addr.index();
506 poll_fn(|cx| { 501 poll_fn(|cx| {
507 EP_IN_WAKERS[index].register(cx.waker()); 502 EP_IN_WAKERS[index].register(cx.waker());
508 let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() }; 503 let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read();
509 if val.enable() { 504 if val.enable() {
510 Poll::Ready(()) 505 Poll::Ready(())
511 } else { 506 } else {
@@ -527,7 +522,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
527 let index = self.info.addr.index(); 522 let index = self.info.addr.index();
528 poll_fn(|cx| { 523 poll_fn(|cx| {
529 EP_OUT_WAKERS[index].register(cx.waker()); 524 EP_OUT_WAKERS[index].register(cx.waker());
530 let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() }; 525 let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read();
531 if val.enable() { 526 if val.enable() {
532 Poll::Ready(()) 527 Poll::Ready(())
533 } else { 528 } else {
@@ -543,7 +538,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
543 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 538 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
544 trace!("READ WAITING, buf.len() = {}", buf.len()); 539 trace!("READ WAITING, buf.len() = {}", buf.len());
545 let index = self.info.addr.index(); 540 let index = self.info.addr.index();
546 let val = poll_fn(|cx| unsafe { 541 let val = poll_fn(|cx| {
547 EP_OUT_WAKERS[index].register(cx.waker()); 542 EP_OUT_WAKERS[index].register(cx.waker());
548 let val = T::dpram().ep_out_buffer_control(index).read(); 543 let val = T::dpram().ep_out_buffer_control(index).read();
549 if val.available(0) { 544 if val.available(0) {
@@ -562,19 +557,17 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
562 557
563 trace!("READ OK, rx_len = {}", rx_len); 558 trace!("READ OK, rx_len = {}", rx_len);
564 559
565 unsafe { 560 let pid = !val.pid(0);
566 let pid = !val.pid(0); 561 T::dpram().ep_out_buffer_control(index).write(|w| {
567 T::dpram().ep_out_buffer_control(index).write(|w| { 562 w.set_pid(0, pid);
568 w.set_pid(0, pid); 563 w.set_length(0, self.info.max_packet_size);
569 w.set_length(0, self.info.max_packet_size); 564 });
570 }); 565 cortex_m::asm::delay(12);
571 cortex_m::asm::delay(12); 566 T::dpram().ep_out_buffer_control(index).write(|w| {
572 T::dpram().ep_out_buffer_control(index).write(|w| { 567 w.set_pid(0, pid);
573 w.set_pid(0, pid); 568 w.set_length(0, self.info.max_packet_size);
574 w.set_length(0, self.info.max_packet_size); 569 w.set_available(0, true);
575 w.set_available(0, true); 570 });
576 });
577 }
578 571
579 Ok(rx_len) 572 Ok(rx_len)
580 } 573 }
@@ -589,7 +582,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
589 trace!("WRITE WAITING"); 582 trace!("WRITE WAITING");
590 583
591 let index = self.info.addr.index(); 584 let index = self.info.addr.index();
592 let val = poll_fn(|cx| unsafe { 585 let val = poll_fn(|cx| {
593 EP_IN_WAKERS[index].register(cx.waker()); 586 EP_IN_WAKERS[index].register(cx.waker());
594 let val = T::dpram().ep_in_buffer_control(index).read(); 587 let val = T::dpram().ep_in_buffer_control(index).read();
595 if val.available(0) { 588 if val.available(0) {
@@ -602,21 +595,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
602 595
603 self.buf.write(buf); 596 self.buf.write(buf);
604 597
605 unsafe { 598 let pid = !val.pid(0);
606 let pid = !val.pid(0); 599 T::dpram().ep_in_buffer_control(index).write(|w| {
607 T::dpram().ep_in_buffer_control(index).write(|w| { 600 w.set_pid(0, pid);
608 w.set_pid(0, pid); 601 w.set_length(0, buf.len() as _);
609 w.set_length(0, buf.len() as _); 602 w.set_full(0, true);
610 w.set_full(0, true); 603 });
611 }); 604 cortex_m::asm::delay(12);
612 cortex_m::asm::delay(12); 605 T::dpram().ep_in_buffer_control(index).write(|w| {
613 T::dpram().ep_in_buffer_control(index).write(|w| { 606 w.set_pid(0, pid);
614 w.set_pid(0, pid); 607 w.set_length(0, buf.len() as _);
615 w.set_length(0, buf.len() as _); 608 w.set_full(0, true);
616 w.set_full(0, true); 609 w.set_available(0, true);
617 w.set_available(0, true); 610 });
618 });
619 }
620 611
621 trace!("WRITE OK"); 612 trace!("WRITE OK");
622 613
@@ -638,9 +629,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
638 loop { 629 loop {
639 trace!("SETUP read waiting"); 630 trace!("SETUP read waiting");
640 let regs = T::regs(); 631 let regs = T::regs();
641 unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) }; 632 regs.inte().write_set(|w| w.set_setup_req(true));
642 633
643 poll_fn(|cx| unsafe { 634 poll_fn(|cx| {
644 EP_OUT_WAKERS[0].register(cx.waker()); 635 EP_OUT_WAKERS[0].register(cx.waker());
645 let regs = T::regs(); 636 let regs = T::regs();
646 if regs.sie_status().read().setup_rec() { 637 if regs.sie_status().read().setup_rec() {
@@ -655,13 +646,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
655 EndpointBuffer::<T>::new(0, 8).read(&mut buf); 646 EndpointBuffer::<T>::new(0, 8).read(&mut buf);
656 647
657 let regs = T::regs(); 648 let regs = T::regs();
658 unsafe { 649 regs.sie_status().write(|w| w.set_setup_rec(true));
659 regs.sie_status().write(|w| w.set_setup_rec(true));
660 650
661 // set PID to 0, so (after toggling) first DATA is PID 1 651 // set PID to 0, so (after toggling) first DATA is PID 1
662 T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false)); 652 T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
663 T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false)); 653 T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
664 }
665 654
666 trace!("SETUP read ok"); 655 trace!("SETUP read ok");
667 return buf; 656 return buf;
@@ -669,23 +658,21 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
669 } 658 }
670 659
671 async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> { 660 async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
672 unsafe { 661 let bufcontrol = T::dpram().ep_out_buffer_control(0);
673 let bufcontrol = T::dpram().ep_out_buffer_control(0); 662 let pid = !bufcontrol.read().pid(0);
674 let pid = !bufcontrol.read().pid(0); 663 bufcontrol.write(|w| {
675 bufcontrol.write(|w| { 664 w.set_length(0, self.max_packet_size);
676 w.set_length(0, self.max_packet_size); 665 w.set_pid(0, pid);
677 w.set_pid(0, pid); 666 });
678 }); 667 cortex_m::asm::delay(12);
679 cortex_m::asm::delay(12); 668 bufcontrol.write(|w| {
680 bufcontrol.write(|w| { 669 w.set_length(0, self.max_packet_size);
681 w.set_length(0, self.max_packet_size); 670 w.set_pid(0, pid);
682 w.set_pid(0, pid); 671 w.set_available(0, true);
683 w.set_available(0, true); 672 });
684 });
685 }
686 673
687 trace!("control: data_out len={} first={} last={}", buf.len(), first, last); 674 trace!("control: data_out len={} first={} last={}", buf.len(), first, last);
688 let val = poll_fn(|cx| unsafe { 675 let val = poll_fn(|cx| {
689 EP_OUT_WAKERS[0].register(cx.waker()); 676 EP_OUT_WAKERS[0].register(cx.waker());
690 let val = T::dpram().ep_out_buffer_control(0).read(); 677 let val = T::dpram().ep_out_buffer_control(0).read();
691 if val.available(0) { 678 if val.available(0) {
@@ -715,24 +702,22 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
715 } 702 }
716 EndpointBuffer::<T>::new(0x100, 64).write(data); 703 EndpointBuffer::<T>::new(0x100, 64).write(data);
717 704
718 unsafe { 705 let bufcontrol = T::dpram().ep_in_buffer_control(0);
719 let bufcontrol = T::dpram().ep_in_buffer_control(0); 706 let pid = !bufcontrol.read().pid(0);
720 let pid = !bufcontrol.read().pid(0); 707 bufcontrol.write(|w| {
721 bufcontrol.write(|w| { 708 w.set_length(0, data.len() as _);
722 w.set_length(0, data.len() as _); 709 w.set_pid(0, pid);
723 w.set_pid(0, pid); 710 w.set_full(0, true);
724 w.set_full(0, true); 711 });
725 }); 712 cortex_m::asm::delay(12);
726 cortex_m::asm::delay(12); 713 bufcontrol.write(|w| {
727 bufcontrol.write(|w| { 714 w.set_length(0, data.len() as _);
728 w.set_length(0, data.len() as _); 715 w.set_pid(0, pid);
729 w.set_pid(0, pid); 716 w.set_full(0, true);
730 w.set_full(0, true); 717 w.set_available(0, true);
731 w.set_available(0, true); 718 });
732 });
733 }
734 719
735 poll_fn(|cx| unsafe { 720 poll_fn(|cx| {
736 EP_IN_WAKERS[0].register(cx.waker()); 721 EP_IN_WAKERS[0].register(cx.waker());
737 let bufcontrol = T::dpram().ep_in_buffer_control(0); 722 let bufcontrol = T::dpram().ep_in_buffer_control(0);
738 if bufcontrol.read().available(0) { 723 if bufcontrol.read().available(0) {
@@ -746,48 +731,44 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
746 731
747 if last { 732 if last {
748 // prepare status phase right away. 733 // prepare status phase right away.
749 unsafe { 734 let bufcontrol = T::dpram().ep_out_buffer_control(0);
750 let bufcontrol = T::dpram().ep_out_buffer_control(0);
751 bufcontrol.write(|w| {
752 w.set_length(0, 0);
753 w.set_pid(0, true);
754 });
755 cortex_m::asm::delay(12);
756 bufcontrol.write(|w| {
757 w.set_length(0, 0);
758 w.set_pid(0, true);
759 w.set_available(0, true);
760 });
761 }
762 }
763
764 Ok(())
765 }
766
767 async fn accept(&mut self) {
768 trace!("control: accept");
769
770 let bufcontrol = T::dpram().ep_in_buffer_control(0);
771 unsafe {
772 bufcontrol.write(|w| { 735 bufcontrol.write(|w| {
773 w.set_length(0, 0); 736 w.set_length(0, 0);
774 w.set_pid(0, true); 737 w.set_pid(0, true);
775 w.set_full(0, true);
776 }); 738 });
777 cortex_m::asm::delay(12); 739 cortex_m::asm::delay(12);
778 bufcontrol.write(|w| { 740 bufcontrol.write(|w| {
779 w.set_length(0, 0); 741 w.set_length(0, 0);
780 w.set_pid(0, true); 742 w.set_pid(0, true);
781 w.set_full(0, true);
782 w.set_available(0, true); 743 w.set_available(0, true);
783 }); 744 });
784 } 745 }
785 746
747 Ok(())
748 }
749
750 async fn accept(&mut self) {
751 trace!("control: accept");
752
753 let bufcontrol = T::dpram().ep_in_buffer_control(0);
754 bufcontrol.write(|w| {
755 w.set_length(0, 0);
756 w.set_pid(0, true);
757 w.set_full(0, true);
758 });
759 cortex_m::asm::delay(12);
760 bufcontrol.write(|w| {
761 w.set_length(0, 0);
762 w.set_pid(0, true);
763 w.set_full(0, true);
764 w.set_available(0, true);
765 });
766
786 // wait for completion before returning, needed so 767 // wait for completion before returning, needed so
787 // set_address() doesn't happen early. 768 // set_address() doesn't happen early.
788 poll_fn(|cx| { 769 poll_fn(|cx| {
789 EP_IN_WAKERS[0].register(cx.waker()); 770 EP_IN_WAKERS[0].register(cx.waker());
790 if unsafe { bufcontrol.read().available(0) } { 771 if bufcontrol.read().available(0) {
791 Poll::Pending 772 Poll::Pending
792 } else { 773 } else {
793 Poll::Ready(()) 774 Poll::Ready(())
@@ -800,14 +781,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
800 trace!("control: reject"); 781 trace!("control: reject");
801 782
802 let regs = T::regs(); 783 let regs = T::regs();
803 unsafe { 784 regs.ep_stall_arm().write_set(|w| {
804 regs.ep_stall_arm().write_set(|w| { 785 w.set_ep0_in(true);
805 w.set_ep0_in(true); 786 w.set_ep0_out(true);
806 w.set_ep0_out(true); 787 });
807 }); 788 T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true));
808 T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); 789 T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
809 T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
810 }
811 } 790 }
812 791
813 async fn accept_set_address(&mut self, addr: u8) { 792 async fn accept_set_address(&mut self, addr: u8) {
@@ -815,6 +794,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
815 794
816 let regs = T::regs(); 795 let regs = T::regs();
817 trace!("setting addr: {}", addr); 796 trace!("setting addr: {}", addr);
818 unsafe { regs.addr_endp().write(|w| w.set_address(addr)) } 797 regs.addr_endp().write(|w| w.set_address(addr))
819 } 798 }
820} 799}
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs
index 78a295ae7..d37795cc9 100644
--- a/embassy-rp/src/watchdog.rs
+++ b/embassy-rp/src/watchdog.rs
@@ -35,45 +35,37 @@ impl Watchdog {
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 pub fn enable_tick_generation(&mut self, cycles: u8) { 37 pub fn enable_tick_generation(&mut self, cycles: u8) {
38 unsafe { 38 let watchdog = pac::WATCHDOG;
39 let watchdog = pac::WATCHDOG; 39 watchdog.tick().write(|w| {
40 watchdog.tick().write(|w| { 40 w.set_enable(true);
41 w.set_enable(true); 41 w.set_cycles(cycles.into())
42 w.set_cycles(cycles.into()) 42 });
43 });
44 }
45 } 43 }
46 44
47 /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode 45 /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
48 /// or when JTAG is accessing bus fabric 46 /// or when JTAG is accessing bus fabric
49 pub fn pause_on_debug(&mut self, pause: bool) { 47 pub fn pause_on_debug(&mut self, pause: bool) {
50 unsafe { 48 let watchdog = pac::WATCHDOG;
51 let watchdog = pac::WATCHDOG; 49 watchdog.ctrl().write(|w| {
52 watchdog.ctrl().write(|w| { 50 w.set_pause_dbg0(pause);
53 w.set_pause_dbg0(pause); 51 w.set_pause_dbg1(pause);
54 w.set_pause_dbg1(pause); 52 w.set_pause_jtag(pause);
55 w.set_pause_jtag(pause); 53 })
56 })
57 }
58 } 54 }
59 55
60 fn load_counter(&self, counter: u32) { 56 fn load_counter(&self, counter: u32) {
61 unsafe { 57 let watchdog = pac::WATCHDOG;
62 let watchdog = pac::WATCHDOG; 58 watchdog.load().write_value(pac::watchdog::regs::Load(counter));
63 watchdog.load().write_value(pac::watchdog::regs::Load(counter));
64 }
65 } 59 }
66 60
67 fn enable(&self, bit: bool) { 61 fn enable(&self, bit: bool) {
68 unsafe { 62 let watchdog = pac::WATCHDOG;
69 let watchdog = pac::WATCHDOG; 63 watchdog.ctrl().write(|w| w.set_enable(bit))
70 watchdog.ctrl().write(|w| w.set_enable(bit))
71 }
72 } 64 }
73 65
74 // Configure which hardware will be reset by the watchdog 66 // Configure which hardware will be reset by the watchdog
75 // (everything except ROSC, XOSC) 67 // (everything except ROSC, XOSC)
76 unsafe fn configure_wdog_reset_triggers(&self) { 68 fn configure_wdog_reset_triggers(&self) {
77 let psm = pac::PSM; 69 let psm = pac::PSM;
78 psm.wdsel().write_value(pac::psm::regs::Wdsel( 70 psm.wdsel().write_value(pac::psm::regs::Wdsel(
79 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize), 71 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize),
@@ -100,23 +92,19 @@ impl Watchdog {
100 self.load_value = delay_us * 2; 92 self.load_value = delay_us * 2;
101 93
102 self.enable(false); 94 self.enable(false);
103 unsafe { 95 self.configure_wdog_reset_triggers();
104 self.configure_wdog_reset_triggers();
105 }
106 self.load_counter(self.load_value); 96 self.load_counter(self.load_value);
107 self.enable(true); 97 self.enable(true);
108 } 98 }
109 99
110 /// Trigger a system reset 100 /// Trigger a system reset
111 pub fn trigger_reset(&mut self) { 101 pub fn trigger_reset(&mut self) {
112 unsafe { 102 self.configure_wdog_reset_triggers();
113 self.configure_wdog_reset_triggers(); 103 self.pause_on_debug(false);
114 self.pause_on_debug(false); 104 self.enable(true);
115 self.enable(true); 105 let watchdog = pac::WATCHDOG;
116 let watchdog = pac::WATCHDOG; 106 watchdog.ctrl().write(|w| {
117 watchdog.ctrl().write(|w| { 107 w.set_trigger(true);
118 w.set_trigger(true); 108 })
119 })
120 }
121 } 109 }
122} 110}
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
new file mode 100644
index 000000000..4b830cab3
--- /dev/null
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -0,0 +1,51 @@
1[package]
2name = "embassy-stm32-wpan"
3version = "0.1.0"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6
7[package.metadata.embassy_docs]
8src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src"
9src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src"
10target = "thumbv7em-none-eabihf"
11features = ["stm32wb55rg"]
12
13[dependencies]
14embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
15embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
16embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
17embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
18embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
19embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
20
21defmt = { version = "0.3", optional = true }
22cortex-m = "0.7.6"
23heapless = "0.7.16"
24aligned = "0.4.1"
25
26bit_field = "0.10.2"
27stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
28stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true }
29
30[features]
31defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
32
33ble = ["dep:stm32wb-hci"]
34mac = []
35
36stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
37stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
38stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
39stm32wb35cc = [ "embassy-stm32/stm32wb35cc" ]
40stm32wb35ce = [ "embassy-stm32/stm32wb35ce" ]
41stm32wb50cg = [ "embassy-stm32/stm32wb50cg" ]
42stm32wb55cc = [ "embassy-stm32/stm32wb55cc" ]
43stm32wb55ce = [ "embassy-stm32/stm32wb55ce" ]
44stm32wb55cg = [ "embassy-stm32/stm32wb55cg" ]
45stm32wb55rc = [ "embassy-stm32/stm32wb55rc" ]
46stm32wb55re = [ "embassy-stm32/stm32wb55re" ]
47stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
48stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
49stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
50stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
51stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ] \ No newline at end of file
diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs
new file mode 100644
index 000000000..94aac070d
--- /dev/null
+++ b/embassy-stm32-wpan/build.rs
@@ -0,0 +1,45 @@
1use std::path::PathBuf;
2use std::{env, fs};
3
4fn main() {
5 match env::vars()
6 .map(|(a, _)| a)
7 .filter(|x| x.starts_with("CARGO_FEATURE_STM32"))
8 .get_one()
9 {
10 Ok(_) => {}
11 Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"),
12 Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"),
13 }
14
15 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
16
17 // ========
18 // stm32wb tl_mbox link sections
19
20 let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string();
21 fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap();
22 println!("cargo:rustc-link-search={}", out_dir.display());
23 println!("cargo:rerun-if-changed=tl_mbox.x.in");
24}
25
26enum GetOneError {
27 None,
28 Multiple,
29}
30
31trait IteratorExt: Iterator {
32 fn get_one(self) -> Result<Self::Item, GetOneError>;
33}
34
35impl<T: Iterator> IteratorExt for T {
36 fn get_one(mut self) -> Result<Self::Item, GetOneError> {
37 match self.next() {
38 None => Err(GetOneError::None),
39 Some(res) => match self.next() {
40 Some(_) => Err(GetOneError::Multiple),
41 None => Ok(res),
42 },
43 }
44 }
45}
diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32-wpan/src/channels.rs
index 25a065ba4..9a2be1cfa 100644
--- a/embassy-stm32/src/tl_mbox/channels.rs
+++ b/embassy-stm32-wpan/src/channels.rs
@@ -50,36 +50,30 @@
50//! 50//!
51 51
52pub mod cpu1 { 52pub mod cpu1 {
53 use crate::tl_mbox::ipcc::IpccChannel; 53 use embassy_stm32::ipcc::IpccChannel;
54 54
55 // Not used currently but reserved
56 pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; 55 pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
57 // Not used currently but reserved
58 pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; 56 pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
59 #[allow(dead_code)] // Not used currently but reserved
60 pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; 57 pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
61 #[allow(dead_code)] // Not used currently but reserved 58 #[allow(dead_code)] // Not used currently but reserved
62 pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; 59 pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
63 #[allow(dead_code)] // Not used currently but reserved 60 #[allow(dead_code)] // Not used currently but reserved
64 pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; 61 pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
65 // Not used currently but reserved
66 pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
67 #[allow(dead_code)] // Not used currently but reserved 62 #[allow(dead_code)] // Not used currently but reserved
63 pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
68 pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 64 pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
69 #[allow(dead_code)] // Not used currently but reserved 65 #[allow(dead_code)] // Not used currently but reserved
70 pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 66 pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
71 #[allow(dead_code)] // Not used currently but reserved 67 #[allow(dead_code)] // Not used currently but reserved
72 pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 68 pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
73 #[allow(dead_code)] // Not used currently but reserved
74 pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6; 69 pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6;
75} 70}
76 71
77pub mod cpu2 { 72pub mod cpu2 {
78 use crate::tl_mbox::ipcc::IpccChannel; 73 use embassy_stm32::ipcc::IpccChannel;
79 74
80 pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; 75 pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1;
81 pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; 76 pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2;
82 #[allow(dead_code)] // Not used currently but reserved
83 pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; 77 pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
84 #[allow(dead_code)] // Not used currently but reserved 78 #[allow(dead_code)] // Not used currently but reserved
85 pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; 79 pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
@@ -88,10 +82,8 @@ pub mod cpu2 {
88 #[allow(dead_code)] // Not used currently but reserved 82 #[allow(dead_code)] // Not used currently but reserved
89 pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; 83 pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
90 #[allow(dead_code)] // Not used currently but reserved 84 #[allow(dead_code)] // Not used currently but reserved
91 pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; 85 pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
92 #[allow(dead_code)] // Not used currently but reserved
93 pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; 86 pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
94 #[allow(dead_code)] // Not used currently but reserved
95 pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5; 87 pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5;
96 #[allow(dead_code)] // Not used currently but reserved 88 #[allow(dead_code)] // Not used currently but reserved
97 pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; 89 pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs
new file mode 100644
index 000000000..8428b6ffc
--- /dev/null
+++ b/embassy-stm32-wpan/src/cmd.rs
@@ -0,0 +1,104 @@
1use core::ptr;
2
3use crate::consts::TlPacketType;
4use crate::PacketHeader;
5
6#[derive(Copy, Clone)]
7#[repr(C, packed)]
8pub struct Cmd {
9 pub cmd_code: u16,
10 pub payload_len: u8,
11 pub payload: [u8; 255],
12}
13
14impl Default for Cmd {
15 fn default() -> Self {
16 Self {
17 cmd_code: 0,
18 payload_len: 0,
19 payload: [0u8; 255],
20 }
21 }
22}
23
24#[derive(Copy, Clone, Default)]
25#[repr(C, packed)]
26pub struct CmdSerial {
27 pub ty: u8,
28 pub cmd: Cmd,
29}
30
31#[derive(Copy, Clone, Default)]
32#[repr(C, packed)]
33pub struct CmdSerialStub {
34 pub ty: u8,
35 pub cmd_code: u16,
36 pub payload_len: u8,
37}
38
39#[derive(Copy, Clone, Default)]
40#[repr(C, packed(4))]
41pub struct CmdPacket {
42 pub header: PacketHeader,
43 pub cmdserial: CmdSerial,
44}
45
46impl CmdPacket {
47 pub unsafe fn write_into(cmd_buf: *mut CmdPacket, packet_type: TlPacketType, cmd_code: u16, payload: &[u8]) {
48 let p_cmd_serial = &mut (*cmd_buf).cmdserial as *mut _ as *mut CmdSerialStub;
49 let p_payload = &mut (*cmd_buf).cmdserial.cmd.payload as *mut _;
50
51 ptr::write_volatile(
52 p_cmd_serial,
53 CmdSerialStub {
54 ty: packet_type as u8,
55 cmd_code,
56 payload_len: payload.len() as u8,
57 },
58 );
59
60 ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
61 }
62}
63
64#[derive(Copy, Clone)]
65#[repr(C, packed)]
66pub struct AclDataSerial {
67 pub ty: u8,
68 pub handle: u16,
69 pub length: u16,
70 pub acl_data: [u8; 1],
71}
72
73#[derive(Copy, Clone)]
74#[repr(C, packed)]
75pub struct AclDataSerialStub {
76 pub ty: u8,
77 pub handle: u16,
78 pub length: u16,
79}
80
81#[derive(Copy, Clone)]
82#[repr(C, packed)]
83pub struct AclDataPacket {
84 pub header: PacketHeader,
85 pub acl_data_serial: AclDataSerial,
86}
87
88impl AclDataPacket {
89 pub unsafe fn write_into(cmd_buf: *mut AclDataPacket, packet_type: TlPacketType, handle: u16, payload: &[u8]) {
90 let p_cmd_serial = &mut (*cmd_buf).acl_data_serial as *mut _ as *mut AclDataSerialStub;
91 let p_payload = &mut (*cmd_buf).acl_data_serial.acl_data as *mut _;
92
93 ptr::write_volatile(
94 p_cmd_serial,
95 AclDataSerialStub {
96 ty: packet_type as u8,
97 handle: handle,
98 length: payload.len() as u16,
99 },
100 );
101
102 ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
103 }
104}
diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs
new file mode 100644
index 000000000..f234151d7
--- /dev/null
+++ b/embassy-stm32-wpan/src/consts.rs
@@ -0,0 +1,93 @@
1use core::convert::TryFrom;
2
3use crate::evt::CsEvt;
4use crate::PacketHeader;
5
6#[derive(Debug)]
7#[repr(C)]
8pub enum TlPacketType {
9 BleCmd = 0x01,
10 AclData = 0x02,
11 BleEvt = 0x04,
12
13 OtCmd = 0x08,
14 OtRsp = 0x09,
15 CliCmd = 0x0A,
16 OtNot = 0x0C,
17 OtAck = 0x0D,
18 CliNot = 0x0E,
19 CliAck = 0x0F,
20
21 SysCmd = 0x10,
22 SysRsp = 0x11,
23 SysEvt = 0x12,
24
25 LocCmd = 0x20,
26 LocRsp = 0x21,
27
28 TracesApp = 0x40,
29 TracesWl = 0x41,
30}
31
32impl TryFrom<u8> for TlPacketType {
33 type Error = ();
34
35 fn try_from(value: u8) -> Result<Self, Self::Error> {
36 match value {
37 0x01 => Ok(TlPacketType::BleCmd),
38 0x02 => Ok(TlPacketType::AclData),
39 0x04 => Ok(TlPacketType::BleEvt),
40 0x08 => Ok(TlPacketType::OtCmd),
41 0x09 => Ok(TlPacketType::OtRsp),
42 0x0A => Ok(TlPacketType::CliCmd),
43 0x0C => Ok(TlPacketType::OtNot),
44 0x0D => Ok(TlPacketType::OtAck),
45 0x0E => Ok(TlPacketType::CliNot),
46 0x0F => Ok(TlPacketType::CliAck),
47 0x10 => Ok(TlPacketType::SysCmd),
48 0x11 => Ok(TlPacketType::SysRsp),
49 0x12 => Ok(TlPacketType::SysEvt),
50 0x20 => Ok(TlPacketType::LocCmd),
51 0x21 => Ok(TlPacketType::LocRsp),
52 0x40 => Ok(TlPacketType::TracesApp),
53 0x41 => Ok(TlPacketType::TracesWl),
54
55 _ => Err(()),
56 }
57 }
58}
59
60pub const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
61pub const TL_EVT_HEADER_SIZE: usize = 3;
62pub const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>();
63
64/**
65 * Queue length of BLE Event
66 * This parameter defines the number of asynchronous events that can be stored in the HCI layer before
67 * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer
68 * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large
69 * enough to store all asynchronous events received in between.
70 * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events
71 * between the HCI command and its event.
72 * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small,
73 * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting
74 * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate
75 * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout).
76 */
77pub const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5;
78pub const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
79pub const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
80
81pub const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
82
83pub const fn divc(x: usize, y: usize) -> usize {
84 (x + y - 1) / y
85}
86
87pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
88#[allow(dead_code)]
89pub const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
90
91pub const TL_BLEEVT_CC_OPCODE: u8 = 0x0E;
92pub const TL_BLEEVT_CS_OPCODE: u8 = 0x0F;
93pub const TL_BLEEVT_VS_OPCODE: u8 = 0xFF;
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs
new file mode 100644
index 000000000..c6528413d
--- /dev/null
+++ b/embassy-stm32-wpan/src/evt.rs
@@ -0,0 +1,151 @@
1use core::marker::PhantomData;
2use core::{ptr, slice};
3
4use super::PacketHeader;
5use crate::consts::TL_EVT_HEADER_SIZE;
6
7/**
8 * The payload of `Evt` for a command status event
9 */
10#[derive(Copy, Clone)]
11#[repr(C, packed)]
12pub struct CsEvt {
13 pub status: u8,
14 pub num_cmd: u8,
15 pub cmd_code: u16,
16}
17
18/**
19 * The payload of `Evt` for a command complete event
20 */
21#[derive(Copy, Clone, Default)]
22#[repr(C, packed)]
23pub struct CcEvt {
24 pub num_cmd: u8,
25 pub cmd_code: u16,
26 pub payload: [u8; 1],
27}
28
29impl CcEvt {
30 pub fn write(&self, buf: &mut [u8]) {
31 unsafe {
32 let len = core::mem::size_of::<CcEvt>();
33 assert!(buf.len() >= len);
34
35 let self_ptr: *const CcEvt = self;
36 let self_buf_ptr: *const u8 = self_ptr.cast();
37
38 core::ptr::copy(self_buf_ptr, buf.as_mut_ptr(), len);
39 }
40 }
41}
42
43#[derive(Copy, Clone, Default)]
44#[repr(C, packed)]
45pub struct AsynchEvt {
46 sub_evt_code: u16,
47 payload: [u8; 1],
48}
49
50#[derive(Copy, Clone)]
51#[repr(C, packed)]
52pub struct Evt {
53 pub evt_code: u8,
54 pub payload_len: u8,
55 pub payload: [u8; 255],
56}
57
58#[derive(Copy, Clone)]
59#[repr(C, packed)]
60pub struct EvtSerial {
61 pub kind: u8,
62 pub evt: Evt,
63}
64
65#[derive(Copy, Clone, Default)]
66#[repr(C, packed)]
67pub struct EvtStub {
68 pub kind: u8,
69 pub evt_code: u8,
70}
71
72/// This format shall be used for all events (asynchronous and command response) reported
73/// by the CPU2 except for the command response of a system command where the header is not there
74/// and the format to be used shall be `EvtSerial`.
75///
76/// ### Note:
77/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
78/// include the header and shall use `EvtPacket` format. Only the command response format on the
79/// system channel is different.
80#[derive(Copy, Clone)]
81#[repr(C, packed)]
82pub struct EvtPacket {
83 pub header: PacketHeader,
84 pub evt_serial: EvtSerial,
85}
86
87impl EvtPacket {
88 pub fn kind(&self) -> u8 {
89 self.evt_serial.kind
90 }
91
92 pub fn evt(&self) -> &Evt {
93 &self.evt_serial.evt
94 }
95}
96
97pub trait MemoryManager {
98 unsafe fn drop_event_packet(evt: *mut EvtPacket);
99}
100
101/// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically
102/// on [`Drop`]
103#[derive(Debug)]
104pub struct EvtBox<T: MemoryManager> {
105 ptr: *mut EvtPacket,
106 mm: PhantomData<T>,
107}
108
109unsafe impl<T: MemoryManager> Send for EvtBox<T> {}
110impl<T: MemoryManager> EvtBox<T> {
111 pub(super) fn new(ptr: *mut EvtPacket) -> Self {
112 Self { ptr, mm: PhantomData }
113 }
114
115 /// Returns information about the event
116 pub fn stub(&self) -> EvtStub {
117 unsafe {
118 let p_evt_stub = &(*self.ptr).evt_serial as *const _ as *const EvtStub;
119
120 ptr::read_volatile(p_evt_stub)
121 }
122 }
123
124 pub fn payload<'a>(&'a self) -> &'a [u8] {
125 unsafe {
126 let p_payload_len = &(*self.ptr).evt_serial.evt.payload_len as *const u8;
127 let p_payload = &(*self.ptr).evt_serial.evt.payload as *const u8;
128
129 let payload_len = ptr::read_volatile(p_payload_len);
130
131 slice::from_raw_parts(p_payload, payload_len as usize)
132 }
133 }
134
135 pub fn serial<'a>(&'a self) -> &'a [u8] {
136 unsafe {
137 let evt_serial: *const EvtSerial = &(*self.ptr).evt_serial;
138 let evt_serial_buf: *const u8 = evt_serial.cast();
139
140 let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
141
142 slice::from_raw_parts(evt_serial_buf, len)
143 }
144 }
145}
146
147impl<T: MemoryManager> Drop for EvtBox<T> {
148 fn drop(&mut self) {
149 unsafe { T::drop_event_packet(self.ptr) };
150 }
151}
diff --git a/embassy-cortex-m/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs
index f8bb0a035..066970813 100644
--- a/embassy-cortex-m/src/fmt.rs
+++ b/embassy-stm32-wpan/src/fmt.rs
@@ -195,9 +195,6 @@ macro_rules! unwrap {
195 } 195 }
196} 196}
197 197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)] 198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError; 199pub struct NoneError;
203 200
diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs
new file mode 100644
index 000000000..89f204f99
--- /dev/null
+++ b/embassy-stm32-wpan/src/lhci.rs
@@ -0,0 +1,112 @@
1use core::ptr;
2
3use crate::cmd::CmdPacket;
4use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE};
5use crate::evt::{CcEvt, EvtPacket, EvtSerial};
6use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE};
7
8const TL_BLEEVT_CC_OPCODE: u8 = 0x0e;
9const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62;
10
11const PACKAGE_DATA_PTR: *const u8 = 0x1FFF_7500 as _;
12const UID64_PTR: *const u32 = 0x1FFF_7580 as _;
13
14#[derive(Debug, Copy, Clone)]
15#[repr(C, packed)]
16pub struct LhciC1DeviceInformationCcrp {
17 pub status: u8,
18 pub rev_id: u16,
19 pub dev_code_id: u16,
20 pub package_type: u8,
21 pub device_type_id: u8,
22 pub st_company_id: u32,
23 pub uid64: u32,
24
25 pub uid96_0: u32,
26 pub uid96_1: u32,
27 pub uid96_2: u32,
28
29 pub safe_boot_info_table: SafeBootInfoTable,
30 pub rss_info_table: RssInfoTable,
31 pub wireless_fw_info_table: WirelessFwInfoTable,
32
33 pub app_fw_inf: u32,
34}
35
36impl Default for LhciC1DeviceInformationCcrp {
37 fn default() -> Self {
38 let DeviceInfoTable {
39 safe_boot_info_table,
40 rss_info_table,
41 wireless_fw_info_table,
42 } = unsafe { ptr::read_volatile(TL_DEVICE_INFO_TABLE.as_ptr()) };
43
44 let device_id = stm32_device_signature::device_id();
45 let uid96_0 = (device_id[3] as u32) << 24
46 | (device_id[2] as u32) << 16
47 | (device_id[1] as u32) << 8
48 | device_id[0] as u32;
49 let uid96_1 = (device_id[7] as u32) << 24
50 | (device_id[6] as u32) << 16
51 | (device_id[5] as u32) << 8
52 | device_id[4] as u32;
53 let uid96_2 = (device_id[11] as u32) << 24
54 | (device_id[10] as u32) << 16
55 | (device_id[9] as u32) << 8
56 | device_id[8] as u32;
57
58 let package_type = unsafe { *PACKAGE_DATA_PTR };
59 let uid64 = unsafe { *UID64_PTR };
60 let st_company_id = unsafe { *UID64_PTR.offset(1) } >> 8 & 0x00FF_FFFF;
61 let device_type_id = (unsafe { *UID64_PTR.offset(1) } & 0x000000FF) as u8;
62
63 LhciC1DeviceInformationCcrp {
64 status: 0,
65 rev_id: 0,
66 dev_code_id: 0,
67 package_type,
68 device_type_id,
69 st_company_id,
70 uid64,
71 uid96_0,
72 uid96_1,
73 uid96_2,
74 safe_boot_info_table,
75 rss_info_table,
76 wireless_fw_info_table,
77 app_fw_inf: (1 << 8), // 0.0.1
78 }
79 }
80}
81
82impl LhciC1DeviceInformationCcrp {
83 pub fn new() -> Self {
84 Self::default()
85 }
86
87 pub fn write(&self, cmd_packet: &mut CmdPacket) {
88 let self_size = core::mem::size_of::<LhciC1DeviceInformationCcrp>();
89
90 unsafe {
91 let cmd_packet_ptr: *mut CmdPacket = cmd_packet;
92 let evet_packet_ptr: *mut EvtPacket = cmd_packet_ptr.cast();
93
94 let evt_serial: *mut EvtSerial = &mut (*evet_packet_ptr).evt_serial;
95 let evt_payload = (*evt_serial).evt.payload.as_mut_ptr();
96 let evt_cc: *mut CcEvt = evt_payload.cast();
97 let evt_cc_payload_buf = (*evt_cc).payload.as_mut_ptr();
98
99 (*evt_serial).kind = TlPacketType::LocRsp as u8;
100 (*evt_serial).evt.evt_code = TL_BLEEVT_CC_OPCODE;
101 (*evt_serial).evt.payload_len = TL_EVT_HEADER_SIZE as u8 + self_size as u8;
102
103 (*evt_cc).cmd_code = LHCI_OPCODE_C1_DEVICE_INF;
104 (*evt_cc).num_cmd = 1;
105
106 let self_ptr: *const LhciC1DeviceInformationCcrp = self;
107 let self_buf = self_ptr.cast();
108
109 ptr::copy(self_buf, evt_cc_payload_buf, self_size);
110 }
111 }
112}
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs
new file mode 100644
index 000000000..99c610583
--- /dev/null
+++ b/embassy-stm32-wpan/src/lib.rs
@@ -0,0 +1,137 @@
1#![no_std]
2#![cfg_attr(feature = "ble", feature(async_fn_in_trait))]
3
4// This must go FIRST so that all the other modules see its macros.
5pub mod fmt;
6
7use core::mem::MaybeUninit;
8use core::sync::atomic::{compiler_fence, Ordering};
9
10use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
11use embassy_stm32::interrupt;
12use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler};
13use embassy_stm32::peripherals::IPCC;
14use sub::mm::MemoryManager;
15use sub::sys::Sys;
16use tables::*;
17use unsafe_linked_list::LinkedListNode;
18
19pub mod channels;
20pub mod cmd;
21pub mod consts;
22pub mod evt;
23pub mod lhci;
24pub mod shci;
25pub mod sub;
26pub mod tables;
27pub mod unsafe_linked_list;
28
29#[cfg(feature = "ble")]
30pub use crate::sub::ble::hci;
31
32type PacketHeader = LinkedListNode;
33
34pub struct TlMbox<'d> {
35 _ipcc: PeripheralRef<'d, IPCC>,
36
37 pub sys_subsystem: Sys,
38 pub mm_subsystem: MemoryManager,
39 #[cfg(feature = "ble")]
40 pub ble_subsystem: sub::ble::Ble,
41 #[cfg(feature = "mac")]
42 pub mac_subsystem: sub::mac::Mac,
43}
44
45impl<'d> TlMbox<'d> {
46 pub fn init(
47 ipcc: impl Peripheral<P = IPCC> + 'd,
48 _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
49 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>,
50 config: Config,
51 ) -> Self {
52 into_ref!(ipcc);
53
54 unsafe {
55 TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
56 device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
57 ble_table: TL_BLE_TABLE.as_ptr(),
58 thread_table: TL_THREAD_TABLE.as_ptr(),
59 sys_table: TL_SYS_TABLE.as_ptr(),
60 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
61 traces_table: TL_TRACES_TABLE.as_ptr(),
62 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
63 // zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
64 // lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
65 // ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
66 });
67
68 TL_SYS_TABLE
69 .as_mut_ptr()
70 .write_volatile(MaybeUninit::zeroed().assume_init());
71 TL_DEVICE_INFO_TABLE
72 .as_mut_ptr()
73 .write_volatile(MaybeUninit::zeroed().assume_init());
74 TL_BLE_TABLE
75 .as_mut_ptr()
76 .write_volatile(MaybeUninit::zeroed().assume_init());
77 TL_THREAD_TABLE
78 .as_mut_ptr()
79 .write_volatile(MaybeUninit::zeroed().assume_init());
80 TL_MEM_MANAGER_TABLE
81 .as_mut_ptr()
82 .write_volatile(MaybeUninit::zeroed().assume_init());
83
84 TL_TRACES_TABLE
85 .as_mut_ptr()
86 .write_volatile(MaybeUninit::zeroed().assume_init());
87 TL_MAC_802_15_4_TABLE
88 .as_mut_ptr()
89 .write_volatile(MaybeUninit::zeroed().assume_init());
90 // TL_ZIGBEE_TABLE
91 // .as_mut_ptr()
92 // .write_volatile(MaybeUninit::zeroed().assume_init());
93 // TL_LLD_TESTS_TABLE
94 // .as_mut_ptr()
95 // .write_volatile(MaybeUninit::zeroed().assume_init());
96 // TL_BLE_LLD_TABLE
97 // .as_mut_ptr()
98 // .write_volatile(MaybeUninit::zeroed().assume_init());
99
100 EVT_POOL
101 .as_mut_ptr()
102 .write_volatile(MaybeUninit::zeroed().assume_init());
103 SYS_SPARE_EVT_BUF
104 .as_mut_ptr()
105 .write_volatile(MaybeUninit::zeroed().assume_init());
106 BLE_SPARE_EVT_BUF
107 .as_mut_ptr()
108 .write_volatile(MaybeUninit::zeroed().assume_init());
109
110 {
111 BLE_CMD_BUFFER
112 .as_mut_ptr()
113 .write_volatile(MaybeUninit::zeroed().assume_init());
114 HCI_ACL_DATA_BUFFER
115 .as_mut_ptr()
116 .write_volatile(MaybeUninit::zeroed().assume_init());
117 CS_BUFFER
118 .as_mut_ptr()
119 .write_volatile(MaybeUninit::zeroed().assume_init());
120 }
121 }
122
123 compiler_fence(Ordering::SeqCst);
124
125 Ipcc::enable(config);
126
127 Self {
128 _ipcc: ipcc,
129 sys_subsystem: sub::sys::Sys::new(),
130 #[cfg(feature = "ble")]
131 ble_subsystem: sub::ble::Ble::new(),
132 #[cfg(feature = "mac")]
133 mac_subsystem: sub::mac::Mac::new(),
134 mm_subsystem: sub::mm::MemoryManager::new(),
135 }
136 }
137}
diff --git a/embassy-stm32-wpan/src/shci.rs b/embassy-stm32-wpan/src/shci.rs
new file mode 100644
index 000000000..30d689716
--- /dev/null
+++ b/embassy-stm32-wpan/src/shci.rs
@@ -0,0 +1,375 @@
1use core::{mem, slice};
2
3use crate::consts::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE};
4
5const SHCI_OGF: u16 = 0x3F;
6
7const fn opcode(ogf: u16, ocf: u16) -> isize {
8 ((ogf << 10) + ocf) as isize
9}
10
11#[allow(dead_code)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub enum SchiCommandStatus {
14 ShciSuccess = 0x00,
15 ShciUnknownCmd = 0x01,
16 ShciMemoryCapacityExceededErrCode = 0x07,
17 ShciErrUnsupportedFeature = 0x11,
18 ShciErrInvalidHciCmdParams = 0x12,
19 ShciErrInvalidParams = 0x42, /* only used for release < v1.13.0 */
20 ShciErrInvalidParamsV2 = 0x92, /* available for release >= v1.13.0 */
21 ShciFusCmdNotSupported = 0xFF,
22}
23
24impl TryFrom<u8> for SchiCommandStatus {
25 type Error = ();
26
27 fn try_from(v: u8) -> Result<Self, Self::Error> {
28 match v {
29 x if x == SchiCommandStatus::ShciSuccess as u8 => Ok(SchiCommandStatus::ShciSuccess),
30 x if x == SchiCommandStatus::ShciUnknownCmd as u8 => Ok(SchiCommandStatus::ShciUnknownCmd),
31 x if x == SchiCommandStatus::ShciMemoryCapacityExceededErrCode as u8 => {
32 Ok(SchiCommandStatus::ShciMemoryCapacityExceededErrCode)
33 }
34 x if x == SchiCommandStatus::ShciErrUnsupportedFeature as u8 => {
35 Ok(SchiCommandStatus::ShciErrUnsupportedFeature)
36 }
37 x if x == SchiCommandStatus::ShciErrInvalidHciCmdParams as u8 => {
38 Ok(SchiCommandStatus::ShciErrInvalidHciCmdParams)
39 }
40 x if x == SchiCommandStatus::ShciErrInvalidParams as u8 => Ok(SchiCommandStatus::ShciErrInvalidParams), /* only used for release < v1.13.0 */
41 x if x == SchiCommandStatus::ShciErrInvalidParamsV2 as u8 => Ok(SchiCommandStatus::ShciErrInvalidParamsV2), /* available for release >= v1.13.0 */
42 x if x == SchiCommandStatus::ShciFusCmdNotSupported as u8 => Ok(SchiCommandStatus::ShciFusCmdNotSupported),
43 _ => Err(()),
44 }
45 }
46}
47
48#[allow(dead_code)]
49#[cfg_attr(feature = "defmt", derive(defmt::Format))]
50pub enum ShciOpcode {
51 // 0x50 reserved
52 // 0x51 reserved
53 FusGetState = opcode(SHCI_OGF, 0x52),
54 // 0x53 reserved
55 FusFirmwareUpgrade = opcode(SHCI_OGF, 0x54),
56 FusFirmwareDelete = opcode(SHCI_OGF, 0x55),
57 FusUpdateAuthKey = opcode(SHCI_OGF, 0x56),
58 FusLockAuthKey = opcode(SHCI_OGF, 0x57),
59 FusStoreUserKey = opcode(SHCI_OGF, 0x58),
60 FusLoadUserKey = opcode(SHCI_OGF, 0x59),
61 FusStartWirelessStack = opcode(SHCI_OGF, 0x5a),
62 // 0x5b reserved
63 // 0x5c reserved
64 FusLockUserKey = opcode(SHCI_OGF, 0x5d),
65 FusUnloadUserKey = opcode(SHCI_OGF, 0x5e),
66 FusActivateAntirollback = opcode(SHCI_OGF, 0x5f),
67 // 0x60 reserved
68 // 0x61 reserved
69 // 0x62 reserved
70 // 0x63 reserved
71 // 0x64 reserved
72 // 0x65 reserved
73 BleInit = opcode(SHCI_OGF, 0x66),
74 ThreadInit = opcode(SHCI_OGF, 0x67),
75 DebugInit = opcode(SHCI_OGF, 0x68),
76 FlashEraseActivity = opcode(SHCI_OGF, 0x69),
77 ConcurrentSetMode = opcode(SHCI_OGF, 0x6a),
78 FlashStoreData = opcode(SHCI_OGF, 0x6b),
79 FlashEraseData = opcode(SHCI_OGF, 0x6c),
80 RadioAllowLowPower = opcode(SHCI_OGF, 0x6d),
81 Mac802_15_4Init = opcode(SHCI_OGF, 0x6e),
82 ReInit = opcode(SHCI_OGF, 0x6f),
83 ZigbeeInit = opcode(SHCI_OGF, 0x70),
84 LldTestsInit = opcode(SHCI_OGF, 0x71),
85 ExtraConfig = opcode(SHCI_OGF, 0x72),
86 SetFlashActivityControl = opcode(SHCI_OGF, 0x73),
87 BleLldInit = opcode(SHCI_OGF, 0x74),
88 Config = opcode(SHCI_OGF, 0x75),
89 ConcurrentGetNextBleEvtTime = opcode(SHCI_OGF, 0x76),
90 ConcurrentEnableNext802_15_4EvtNotification = opcode(SHCI_OGF, 0x77),
91 Mac802_15_4DeInit = opcode(SHCI_OGF, 0x78),
92}
93
94pub const SHCI_C2_CONFIG_EVTMASK1_BIT0_ERROR_NOTIF_ENABLE: u8 = 1 << 0;
95pub const SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 1;
96pub const SHCI_C2_CONFIG_EVTMASK1_BIT2_THREAD_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 2;
97pub const SHCI_C2_CONFIG_EVTMASK1_BIT3_NVM_START_WRITE_ENABLE: u8 = 1 << 3;
98pub const SHCI_C2_CONFIG_EVTMASK1_BIT4_NVM_END_WRITE_ENABLE: u8 = 1 << 4;
99pub const SHCI_C2_CONFIG_EVTMASK1_BIT5_NVM_START_ERASE_ENABLE: u8 = 1 << 5;
100pub const SHCI_C2_CONFIG_EVTMASK1_BIT6_NVM_END_ERASE_ENABLE: u8 = 1 << 6;
101
102#[derive(Clone, Copy)]
103#[repr(C, packed)]
104pub struct ShciConfigParam {
105 pub payload_cmd_size: u8,
106 pub config: u8,
107 pub event_mask: u8,
108 pub spare: u8,
109 pub ble_nvm_ram_address: u32,
110 pub thread_nvm_ram_address: u32,
111 pub revision_id: u16,
112 pub device_id: u16,
113}
114
115impl ShciConfigParam {
116 pub fn payload<'a>(&'a self) -> &'a [u8] {
117 unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) }
118 }
119}
120
121impl Default for ShciConfigParam {
122 fn default() -> Self {
123 Self {
124 payload_cmd_size: (mem::size_of::<Self>() - 1) as u8,
125 config: 0,
126 event_mask: SHCI_C2_CONFIG_EVTMASK1_BIT0_ERROR_NOTIF_ENABLE
127 + SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE
128 + SHCI_C2_CONFIG_EVTMASK1_BIT2_THREAD_NVM_RAM_UPDATE_ENABLE
129 + SHCI_C2_CONFIG_EVTMASK1_BIT3_NVM_START_WRITE_ENABLE
130 + SHCI_C2_CONFIG_EVTMASK1_BIT4_NVM_END_WRITE_ENABLE
131 + SHCI_C2_CONFIG_EVTMASK1_BIT5_NVM_START_ERASE_ENABLE
132 + SHCI_C2_CONFIG_EVTMASK1_BIT6_NVM_END_ERASE_ENABLE,
133 spare: 0,
134 ble_nvm_ram_address: 0,
135 thread_nvm_ram_address: 0,
136 revision_id: 0,
137 device_id: 0,
138 }
139 }
140}
141
142#[derive(Clone, Copy)]
143#[repr(C, packed)]
144pub struct ShciBleInitCmdParam {
145 /// NOT USED - shall be set to 0
146 pub p_ble_buffer_address: u32,
147 /// NOT USED - shall be set to 0
148 pub ble_buffer_size: u32,
149 /// Maximum number of attribute records related to all the required characteristics (excluding the services)
150 /// that can be stored in the GATT database, for the specific BLE user application.
151 /// For each characteristic, the number of attribute records goes from two to five depending on the characteristic properties:
152 /// - minimum of two (one for declaration and one for the value)
153 /// - add one more record for each additional property: notify or indicate, broadcast, extended property.
154 /// The total calculated value must be increased by 9, due to the records related to the standard attribute profile and
155 /// GAP service characteristics, and automatically added when initializing GATT and GAP layers
156 /// - Min value: <number of user attributes> + 9
157 /// - Max value: depending on the GATT database defined by user application
158 pub num_attr_record: u16,
159 /// Defines the maximum number of services that can be stored in the GATT database. Note that the GAP and GATT services
160 /// are automatically added at initialization so this parameter must be the number of user services increased by two.
161 /// - Min value: <number of user service> + 2
162 /// - Max value: depending GATT database defined by user application
163 pub num_attr_serv: u16,
164 /// NOTE: This parameter is ignored by the CPU2 when the parameter "Options" is set to "LL_only" ( see Options description in that structure )
165 ///
166 /// Size of the storage area for the attribute values.
167 /// Each characteristic contributes to the attrValueArrSize value as follows:
168 /// - Characteristic value length plus:
169 /// + 5 bytes if characteristic UUID is 16 bits
170 /// + 19 bytes if characteristic UUID is 128 bits
171 /// + 2 bytes if characteristic has a server configuration descriptor
172 /// + 2 bytes * NumOfLinks if the characteristic has a client configuration descriptor
173 /// + 2 bytes if the characteristic has extended properties
174 /// Each descriptor contributes to the attrValueArrSize value as follows:
175 /// - Descriptor length
176 pub attr_value_arr_size: u16,
177 /// Maximum number of BLE links supported
178 /// - Min value: 1
179 /// - Max value: 8
180 pub num_of_links: u8,
181 /// Disable/enable the extended packet length BLE 5.0 feature
182 /// - Disable: 0
183 /// - Enable: 1
184 pub extended_packet_length_enable: u8,
185 /// NOTE: This parameter is ignored by the CPU2 when the parameter "Options" is set to "LL_only" ( see Options description in that structure )
186 ///
187 /// Maximum number of supported "prepare write request"
188 /// - Min value: given by the macro DEFAULT_PREP_WRITE_LIST_SIZE
189 /// - Max value: a value higher than the minimum required can be specified, but it is not recommended
190 pub prepare_write_list_size: u8,
191 /// NOTE: This parameter is overwritten by the CPU2 with an hardcoded optimal value when the parameter "Options" is set to "LL_only"
192 /// ( see Options description in that structure )
193 ///
194 /// Number of allocated memory blocks for the BLE stack
195 /// - Min value: given by the macro MBLOCKS_CALC
196 /// - Max value: a higher value can improve data throughput performance, but uses more memory
197 pub block_count: u8,
198 /// NOTE: This parameter is ignored by the CPU2 when the parameter "Options" is set to "LL_only" ( see Options description in that structure )
199 ///
200 /// Maximum ATT MTU size supported
201 /// - Min value: 23
202 /// - Max value: 512
203 pub att_mtu: u16,
204 /// The sleep clock accuracy (ppm value) that used in BLE connected slave mode to calculate the window widening
205 /// (in combination with the sleep clock accuracy sent by master in CONNECT_REQ PDU),
206 /// refer to BLE 5.0 specifications - Vol 6 - Part B - chap 4.5.7 and 4.2.2
207 /// - Min value: 0
208 /// - Max value: 500 (worst possible admitted by specification)
209 pub slave_sca: u16,
210 /// The sleep clock accuracy handled in master mode. It is used to determine the connection and advertising events timing.
211 /// It is transmitted to the slave in CONNEC_REQ PDU used by the slave to calculate the window widening,
212 /// see SlaveSca and Bluetooth Core Specification v5.0 Vol 6 - Part B - chap 4.5.7 and 4.2.2
213 /// Possible values:
214 /// - 251 ppm to 500 ppm: 0
215 /// - 151 ppm to 250 ppm: 1
216 /// - 101 ppm to 150 ppm: 2
217 /// - 76 ppm to 100 ppm: 3
218 /// - 51 ppm to 75 ppm: 4
219 /// - 31 ppm to 50 ppm: 5
220 /// - 21 ppm to 30 ppm: 6
221 /// - 0 ppm to 20 ppm: 7
222 pub master_sca: u8,
223 /// Some information for Low speed clock mapped in bits field
224 /// - bit 0:
225 /// - 1: Calibration for the RF system wakeup clock source
226 /// - 0: No calibration for the RF system wakeup clock source
227 /// - bit 1:
228 /// - 1: STM32W5M Module device
229 /// - 0: Other devices as STM32WBxx SOC, STM32WB1M module
230 /// - bit 2:
231 /// - 1: HSE/1024 Clock config
232 /// - 0: LSE Clock config
233 pub ls_source: u8,
234 /// This parameter determines the maximum duration of a slave connection event. When this duration is reached the slave closes
235 /// the current connections event (whatever is the CE_length parameter specified by the master in HCI_CREATE_CONNECTION HCI command),
236 /// expressed in units of 625/256 µs (~2.44 µs)
237 /// - Min value: 0 (if 0 is specified, the master and slave perform only a single TX-RX exchange per connection event)
238 /// - Max value: 1638400 (4000 ms). A higher value can be specified (max 0xFFFFFFFF) but results in a maximum connection time
239 /// of 4000 ms as specified. In this case the parameter is not applied, and the predicted CE length calculated on slave is not shortened
240 pub max_conn_event_length: u32,
241 /// Startup time of the high speed (16 or 32 MHz) crystal oscillator in units of 625/256 µs (~2.44 µs).
242 /// - Min value: 0
243 /// - Max value: 820 (~2 ms). A higher value can be specified, but the value that implemented in stack is forced to ~2 ms
244 pub hs_startup_time: u16,
245 /// Viterbi implementation in BLE LL reception.
246 /// - 0: Enable
247 /// - 1: Disable
248 pub viterbi_enable: u8,
249 /// - bit 0:
250 /// - 1: LL only
251 /// - 0: LL + host
252 /// - bit 1:
253 /// - 1: no service change desc.
254 /// - 0: with service change desc.
255 /// - bit 2:
256 /// - 1: device name Read-Only
257 /// - 0: device name R/W
258 /// - bit 3:
259 /// - 1: extended advertizing supported
260 /// - 0: extended advertizing not supported
261 /// - bit 4:
262 /// - 1: CS Algo #2 supported
263 /// - 0: CS Algo #2 not supported
264 /// - bit 5:
265 /// - 1: Reduced GATT database in NVM
266 /// - 0: Full GATT database in NVM
267 /// - bit 6:
268 /// - 1: GATT caching is used
269 /// - 0: GATT caching is not used
270 /// - bit 7:
271 /// - 1: LE Power Class 1
272 /// - 0: LE Power Classe 2-3
273 /// - other bits: complete with Options_extension flag
274 pub options: u8,
275 /// Reserved for future use - shall be set to 0
276 pub hw_version: u8,
277 // /**
278 // * Maximum number of connection-oriented channels in initiator mode.
279 // * Range: 0 .. 64
280 // */
281 // pub max_coc_initiator_nbr: u8,
282 //
283 // /**
284 // * Minimum transmit power in dBm supported by the Controller.
285 // * Range: -127 .. 20
286 // */
287 // pub min_tx_power: i8,
288 //
289 // /**
290 // * Maximum transmit power in dBm supported by the Controller.
291 // * Range: -127 .. 20
292 // */
293 // pub max_tx_power: i8,
294 //
295 // /**
296 // * RX model configuration
297 // * - bit 0: 1: agc_rssi model improved vs RF blockers 0: Legacy agc_rssi model
298 // * - other bits: reserved ( shall be set to 0)
299 // */
300 // pub rx_model_config: u8,
301 //
302 // /* Maximum number of advertising sets.
303 // * Range: 1 .. 8 with limitation:
304 // * This parameter is linked to max_adv_data_len such as both compliant with allocated Total memory computed with BLE_EXT_ADV_BUFFER_SIZE based
305 // * on Max Extended advertising configuration supported.
306 // * This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set
307 // */
308 // pub max_adv_set_nbr: u8,
309 //
310 // /* Maximum advertising data length (in bytes)
311 // * Range: 31 .. 1650 with limitation:
312 // * This parameter is linked to max_adv_set_nbr such as both compliant with allocated Total memory computed with BLE_EXT_ADV_BUFFER_SIZE based
313 // * on Max Extended advertising configuration supported.
314 // * This parameter is considered by the CPU2 when Options has SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV flag set
315 // */
316 // pub max_adv_data_len: u16,
317 //
318 // /* RF TX Path Compensation Value (16-bit signed integer). Units: 0.1 dB.
319 // * Range: -1280 .. 1280
320 // */
321 // pub tx_path_compens: i16,
322 //
323 // /* RF RX Path Compensation Value (16-bit signed integer). Units: 0.1 dB.
324 // * Range: -1280 .. 1280
325 // */
326 // pub rx_path_compens: i16,
327 //
328 // /* BLE core specification version (8-bit unsigned integer).
329 // * values as: 11(5.2), 12(5.3)
330 // */
331 // pub ble_core_version: u8,
332 //
333 // /**
334 // * Options flags extension
335 // * - bit 0: 1: appearance Writable 0: appearance Read-Only
336 // * - bit 1: 1: Enhanced ATT supported 0: Enhanced ATT not supported
337 // * - other bits: reserved ( shall be set to 0)
338 // */
339 // pub options_extension: u8,
340}
341
342impl ShciBleInitCmdParam {
343 pub fn payload<'a>(&'a self) -> &'a [u8] {
344 unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) }
345 }
346}
347
348impl Default for ShciBleInitCmdParam {
349 fn default() -> Self {
350 Self {
351 p_ble_buffer_address: 0,
352 ble_buffer_size: 0,
353 num_attr_record: 68,
354 num_attr_serv: 8,
355 attr_value_arr_size: 1344,
356 num_of_links: 2,
357 extended_packet_length_enable: 1,
358 prepare_write_list_size: 0x3A,
359 block_count: 0x79,
360 att_mtu: 156,
361 slave_sca: 500,
362 master_sca: 0,
363 ls_source: 1,
364 max_conn_event_length: 0xFFFFFFFF,
365 hs_startup_time: 0x148,
366 viterbi_enable: 1,
367 options: 0,
368 hw_version: 0,
369 }
370 }
371}
372
373pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
374#[allow(dead_code)] // Not used currently but reserved
375const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs
new file mode 100644
index 000000000..cd32692e1
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/ble.rs
@@ -0,0 +1,96 @@
1use core::marker::PhantomData;
2use core::ptr;
3
4use embassy_stm32::ipcc::Ipcc;
5use hci::Opcode;
6
7use crate::cmd::CmdPacket;
8use crate::consts::{TlPacketType, TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE};
9use crate::evt::{EvtBox, EvtPacket, EvtStub};
10use crate::sub::mm;
11use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
12use crate::unsafe_linked_list::LinkedListNode;
13use crate::{channels, evt};
14
15pub struct Ble {
16 phantom: PhantomData<Ble>,
17}
18
19impl Ble {
20 pub(crate) fn new() -> Self {
21 unsafe {
22 LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
23
24 TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
25 pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
26 pcs_buffer: CS_BUFFER.as_ptr().cast(),
27 pevt_queue: EVT_QUEUE.as_ptr().cast(),
28 phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
29 });
30 }
31
32 Self { phantom: PhantomData }
33 }
34 /// `HW_IPCC_BLE_EvtNot`
35 pub async fn tl_read(&self) -> EvtBox<Self> {
36 Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe {
37 if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) {
38 Some(EvtBox::new(node_ptr.cast()))
39 } else {
40 None
41 }
42 })
43 .await
44 }
45
46 /// `TL_BLE_SendCmd`
47 pub async fn tl_write(&self, opcode: u16, payload: &[u8]) {
48 Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe {
49 CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload);
50 })
51 .await;
52 }
53
54 /// `TL_BLE_SendAclData`
55 pub async fn acl_write(&self, handle: u16, payload: &[u8]) {
56 Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe {
57 CmdPacket::write_into(
58 HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _,
59 TlPacketType::AclData,
60 handle,
61 payload,
62 );
63 })
64 .await;
65 }
66}
67
68impl evt::MemoryManager for Ble {
69 /// SAFETY: passing a pointer to something other than a managed event packet is UB
70 unsafe fn drop_event_packet(evt: *mut EvtPacket) {
71 let stub = unsafe {
72 let p_evt_stub = &(*evt).evt_serial as *const _ as *const EvtStub;
73
74 ptr::read_volatile(p_evt_stub)
75 };
76
77 if !(stub.evt_code == TL_BLEEVT_CS_OPCODE || stub.evt_code == TL_BLEEVT_CC_OPCODE) {
78 mm::MemoryManager::drop_event_packet(evt);
79 }
80 }
81}
82
83pub extern crate stm32wb_hci as hci;
84
85impl hci::Controller for Ble {
86 async fn controller_write(&mut self, opcode: Opcode, payload: &[u8]) {
87 self.tl_write(opcode.0, payload).await;
88 }
89
90 async fn controller_read_into(&self, buf: &mut [u8]) {
91 let evt_box = self.tl_read().await;
92 let evt_serial = evt_box.serial();
93
94 buf[..evt_serial.len()].copy_from_slice(evt_serial);
95 }
96}
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs
new file mode 100644
index 000000000..fd8af8609
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac.rs
@@ -0,0 +1,113 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::ptr;
4use core::sync::atomic::{AtomicBool, Ordering};
5use core::task::Poll;
6
7use embassy_futures::poll_once;
8use embassy_stm32::ipcc::Ipcc;
9use embassy_sync::waitqueue::AtomicWaker;
10
11use crate::cmd::CmdPacket;
12use crate::consts::TlPacketType;
13use crate::evt::{EvtBox, EvtPacket};
14use crate::tables::{
15 Mac802_15_4Table, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_MAC_802_15_4_TABLE,
16};
17use crate::{channels, evt};
18
19static MAC_WAKER: AtomicWaker = AtomicWaker::new();
20static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
21
22pub struct Mac {
23 phantom: PhantomData<Mac>,
24}
25
26impl Mac {
27 pub(crate) fn new() -> Self {
28 unsafe {
29 TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
30 p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
31 p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
32 evt_queue: ptr::null_mut(),
33 });
34 }
35
36 Self { phantom: PhantomData }
37 }
38
39 /// `HW_IPCC_MAC_802_15_4_EvtNot`
40 ///
41 /// This function will stall if the previous `EvtBox` has not been dropped
42 pub async fn read(&self) -> EvtBox<Self> {
43 // Wait for the last event box to be dropped
44 poll_fn(|cx| {
45 MAC_WAKER.register(cx.waker());
46 if MAC_EVT_OUT.load(Ordering::SeqCst) {
47 Poll::Pending
48 } else {
49 Poll::Ready(())
50 }
51 })
52 .await;
53
54 // Return a new event box
55 Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe {
56 // The closure is not async, therefore the closure must execute to completion (cannot be dropped)
57 // Therefore, the event box is guaranteed to be cleaned up if it's not leaked
58 MAC_EVT_OUT.store(true, Ordering::SeqCst);
59
60 Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _))
61 })
62 .await
63 }
64
65 /// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
66 pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
67 self.write(opcode, payload).await;
68 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
69
70 unsafe {
71 let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket;
72 let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8;
73
74 ptr::read_volatile(p_mac_rsp_evt)
75 }
76 }
77
78 /// `TL_MAC_802_15_4_SendCmd`
79 pub async fn write(&self, opcode: u16, payload: &[u8]) {
80 Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
81 CmdPacket::write_into(
82 MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
83 TlPacketType::OtCmd,
84 opcode,
85 payload,
86 );
87 })
88 .await;
89 }
90}
91
92impl evt::MemoryManager for Mac {
93 /// SAFETY: passing a pointer to something other than a managed event packet is UB
94 unsafe fn drop_event_packet(_: *mut EvtPacket) {
95 // Write the ack
96 CmdPacket::write_into(
97 MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _,
98 TlPacketType::OtAck,
99 0,
100 &[],
101 );
102
103 // Clear the rx flag
104 let _ = poll_once(Ipcc::receive::<bool>(
105 channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL,
106 || None,
107 ));
108
109 // Allow a new read call
110 MAC_EVT_OUT.store(false, Ordering::SeqCst);
111 MAC_WAKER.wake();
112 }
113}
diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs
new file mode 100644
index 000000000..1f2ecac2e
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mm.rs
@@ -0,0 +1,80 @@
1//! Memory manager routines
2use core::future::poll_fn;
3use core::marker::PhantomData;
4use core::mem::MaybeUninit;
5use core::task::Poll;
6
7use cortex_m::interrupt;
8use embassy_stm32::ipcc::Ipcc;
9use embassy_sync::waitqueue::AtomicWaker;
10
11use crate::consts::POOL_SIZE;
12use crate::evt::EvtPacket;
13use crate::tables::{
14 MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE,
15};
16use crate::unsafe_linked_list::LinkedListNode;
17use crate::{channels, evt};
18
19static MM_WAKER: AtomicWaker = AtomicWaker::new();
20static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
21
22pub struct MemoryManager {
23 phantom: PhantomData<MemoryManager>,
24}
25
26impl MemoryManager {
27 pub(crate) fn new() -> Self {
28 unsafe {
29 LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
30 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
31
32 TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
33 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
34 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
35 blepool: EVT_POOL.as_ptr().cast(),
36 blepoolsize: POOL_SIZE as u32,
37 pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(),
38 traces_evt_pool: core::ptr::null(),
39 tracespoolsize: 0,
40 });
41 }
42
43 Self { phantom: PhantomData }
44 }
45
46 pub async fn run_queue(&self) {
47 loop {
48 poll_fn(|cx| unsafe {
49 MM_WAKER.register(cx.waker());
50 if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
51 Poll::Pending
52 } else {
53 Poll::Ready(())
54 }
55 })
56 .await;
57
58 Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || {
59 interrupt::free(|_| unsafe {
60 // CS required while moving nodes
61 while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
62 LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
63 }
64 })
65 })
66 .await;
67 }
68 }
69}
70
71impl evt::MemoryManager for MemoryManager {
72 /// SAFETY: passing a pointer to something other than a managed event packet is UB
73 unsafe fn drop_event_packet(evt: *mut EvtPacket) {
74 interrupt::free(|_| unsafe {
75 LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
76 });
77
78 MM_WAKER.wake();
79 }
80}
diff --git a/embassy-stm32-wpan/src/sub/mod.rs b/embassy-stm32-wpan/src/sub/mod.rs
new file mode 100644
index 000000000..bee3dbdf1
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mod.rs
@@ -0,0 +1,6 @@
1#[cfg(feature = "ble")]
2pub mod ble;
3#[cfg(feature = "mac")]
4pub mod mac;
5pub mod mm;
6pub mod sys;
diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs
new file mode 100644
index 000000000..af652860d
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/sys.rs
@@ -0,0 +1,87 @@
1use core::marker::PhantomData;
2use core::ptr;
3
4use crate::cmd::CmdPacket;
5use crate::consts::TlPacketType;
6use crate::evt::{CcEvt, EvtBox, EvtPacket};
7#[allow(unused_imports)]
8use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode};
9use crate::sub::mm;
10use crate::tables::{SysTable, WirelessFwInfoTable};
11use crate::unsafe_linked_list::LinkedListNode;
12use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
13
14pub struct Sys {
15 phantom: PhantomData<Sys>,
16}
17
18impl Sys {
19 /// TL_Sys_Init
20 pub(crate) fn new() -> Self {
21 unsafe {
22 LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
23
24 TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
25 pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
26 sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
27 });
28 }
29
30 Self { phantom: PhantomData }
31 }
32
33 /// Returns CPU2 wireless firmware information (if present).
34 pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
35 let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table };
36
37 // Zero version indicates that CPU2 wasn't active and didn't fill the information table
38 if info.version != 0 {
39 Some(info)
40 } else {
41 None
42 }
43 }
44
45 pub async fn write(&self, opcode: ShciOpcode, payload: &[u8]) {
46 Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || unsafe {
47 CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode as u16, payload);
48 })
49 .await;
50 }
51
52 /// `HW_IPCC_SYS_CmdEvtNot`
53 pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus {
54 self.write(opcode, payload).await;
55 Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
56
57 unsafe {
58 let p_event_packet = SYS_CMD_BUF.as_ptr() as *const EvtPacket;
59 let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
60 let p_payload = &((*p_command_event).payload) as *const u8;
61
62 ptr::read_volatile(p_payload).try_into().unwrap()
63 }
64 }
65
66 #[cfg(feature = "mac")]
67 pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus {
68 self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await
69 }
70
71 #[cfg(feature = "ble")]
72 pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus {
73 self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
74 }
75
76 /// `HW_IPCC_SYS_EvtNot`
77 pub async fn read(&self) -> EvtBox<mm::MemoryManager> {
78 Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe {
79 if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
80 Some(EvtBox::new(node_ptr.cast()))
81 } else {
82 None
83 }
84 })
85 .await
86 }
87}
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs
new file mode 100644
index 000000000..1b5dcdf2e
--- /dev/null
+++ b/embassy-stm32-wpan/src/tables.rs
@@ -0,0 +1,264 @@
1use core::mem::MaybeUninit;
2
3use aligned::{Aligned, A4};
4use bit_field::BitField;
5
6use crate::cmd::{AclDataPacket, CmdPacket};
7use crate::consts::{POOL_SIZE, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE};
8use crate::unsafe_linked_list::LinkedListNode;
9
10#[derive(Debug, Copy, Clone)]
11#[repr(C, packed)]
12pub struct SafeBootInfoTable {
13 version: u32,
14}
15
16#[derive(Debug, Copy, Clone)]
17#[repr(C, packed)]
18pub struct RssInfoTable {
19 pub version: u32,
20 pub memory_size: u32,
21 pub rss_info: u32,
22}
23
24/**
25 * Version
26 * [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version
27 * [4:7] = branch - 0: Mass Market - x: ...
28 * [8:15] = Subversion
29 * [16:23] = Version minor
30 * [24:31] = Version major
31 *
32 * Memory Size
33 * [0:7] = Flash ( Number of 4k sector)
34 * [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension )
35 * [16:23] = SRAM2b ( Number of 1k sector)
36 * [24:31] = SRAM2a ( Number of 1k sector)
37 */
38#[derive(Debug, Copy, Clone)]
39#[repr(C, packed)]
40pub struct WirelessFwInfoTable {
41 pub version: u32,
42 pub memory_size: u32,
43 pub thread_info: u32,
44 pub ble_info: u32,
45}
46
47impl WirelessFwInfoTable {
48 pub fn version_major(&self) -> u8 {
49 let version = self.version;
50 (version.get_bits(24..31) & 0xff) as u8
51 }
52
53 pub fn version_minor(&self) -> u8 {
54 let version = self.version;
55 (version.clone().get_bits(16..23) & 0xff) as u8
56 }
57
58 pub fn subversion(&self) -> u8 {
59 let version = self.version;
60 (version.clone().get_bits(8..15) & 0xff) as u8
61 }
62
63 /// Size of FLASH, expressed in number of 4K sectors.
64 pub fn flash_size(&self) -> u8 {
65 let memory_size = self.memory_size;
66 (memory_size.clone().get_bits(0..7) & 0xff) as u8
67 }
68
69 /// Size of SRAM2a, expressed in number of 1K sectors.
70 pub fn sram2a_size(&self) -> u8 {
71 let memory_size = self.memory_size;
72 (memory_size.clone().get_bits(24..31) & 0xff) as u8
73 }
74
75 /// Size of SRAM2b, expressed in number of 1K sectors.
76 pub fn sram2b_size(&self) -> u8 {
77 let memory_size = self.memory_size;
78 (memory_size.clone().get_bits(16..23) & 0xff) as u8
79 }
80}
81
82#[derive(Debug, Clone)]
83#[repr(C, align(4))]
84pub struct DeviceInfoTable {
85 pub safe_boot_info_table: SafeBootInfoTable,
86 pub rss_info_table: RssInfoTable,
87 pub wireless_fw_info_table: WirelessFwInfoTable,
88}
89
90#[derive(Debug)]
91#[repr(C, align(4))]
92pub struct BleTable {
93 pub pcmd_buffer: *mut CmdPacket,
94 pub pcs_buffer: *const u8,
95 pub pevt_queue: *const u8,
96 pub phci_acl_data_buffer: *mut AclDataPacket,
97}
98
99#[derive(Debug)]
100#[repr(C, align(4))]
101pub struct ThreadTable {
102 pub nostack_buffer: *const u8,
103 pub clicmdrsp_buffer: *const u8,
104 pub otcmdrsp_buffer: *const u8,
105}
106
107// TODO: use later
108#[derive(Debug)]
109#[repr(C, align(4))]
110pub struct LldTestsTable {
111 pub clicmdrsp_buffer: *const u8,
112 pub m0cmd_buffer: *const u8,
113}
114
115// TODO: use later
116#[derive(Debug)]
117#[repr(C, align(4))]
118pub struct BleLldTable {
119 pub cmdrsp_buffer: *const u8,
120 pub m0cmd_buffer: *const u8,
121}
122
123// TODO: use later
124#[derive(Debug)]
125#[repr(C, align(4))]
126pub struct ZigbeeTable {
127 pub notif_m0_to_m4_buffer: *const u8,
128 pub appli_cmd_m4_to_m0_bufer: *const u8,
129 pub request_m0_to_m4_buffer: *const u8,
130}
131
132#[derive(Debug)]
133#[repr(C, align(4))]
134pub struct SysTable {
135 pub pcmd_buffer: *mut CmdPacket,
136 pub sys_queue: *const LinkedListNode,
137}
138
139#[derive(Debug)]
140#[repr(C, align(4))]
141pub struct MemManagerTable {
142 pub spare_ble_buffer: *const u8,
143 pub spare_sys_buffer: *const u8,
144
145 pub blepool: *const u8,
146 pub blepoolsize: u32,
147
148 pub pevt_free_buffer_queue: *mut LinkedListNode,
149
150 pub traces_evt_pool: *const u8,
151 pub tracespoolsize: u32,
152}
153
154#[derive(Debug)]
155#[repr(C, align(4))]
156pub struct TracesTable {
157 pub traces_queue: *const u8,
158}
159
160#[derive(Debug)]
161#[repr(C, align(4))]
162pub struct Mac802_15_4Table {
163 pub p_cmdrsp_buffer: *const u8,
164 pub p_notack_buffer: *const u8,
165 pub evt_queue: *const u8,
166}
167
168/// Reference table. Contains pointers to all other tables.
169#[derive(Debug, Copy, Clone)]
170#[repr(C)]
171pub struct RefTable {
172 pub device_info_table: *const DeviceInfoTable,
173 pub ble_table: *const BleTable,
174 pub thread_table: *const ThreadTable,
175 pub sys_table: *const SysTable,
176 pub mem_manager_table: *const MemManagerTable,
177 pub traces_table: *const TracesTable,
178 pub mac_802_15_4_table: *const Mac802_15_4Table,
179}
180
181// --------------------- ref table ---------------------
182#[link_section = "TL_REF_TABLE"]
183pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
184
185#[link_section = "MB_MEM1"]
186pub static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
187
188#[link_section = "MB_MEM1"]
189pub static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
190
191#[link_section = "MB_MEM1"]
192pub static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
193
194// #[link_section = "MB_MEM1"]
195// pub static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit();
196
197// #[link_section = "MB_MEM1"]
198// pub static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit();
199
200#[link_section = "MB_MEM1"]
201pub static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
202
203#[link_section = "MB_MEM1"]
204pub static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
205
206#[link_section = "MB_MEM1"]
207pub static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
208
209#[link_section = "MB_MEM1"]
210pub static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
211
212// #[link_section = "MB_MEM1"]
213// pub static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit();
214
215// --------------------- tables ---------------------
216#[link_section = "MB_MEM1"]
217pub static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
218
219#[allow(dead_code)]
220#[link_section = "MB_MEM1"]
221pub static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
222
223#[link_section = "MB_MEM2"]
224pub static mut CS_BUFFER: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]>> =
225 MaybeUninit::uninit();
226
227#[link_section = "MB_MEM2"]
228pub static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
229
230#[link_section = "MB_MEM2"]
231pub static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
232
233// --------------------- app tables ---------------------
234#[cfg(feature = "mac")]
235#[link_section = "MB_MEM2"]
236pub static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
237
238#[cfg(feature = "mac")]
239#[link_section = "MB_MEM2"]
240pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit<
241 Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>,
242> = MaybeUninit::uninit();
243
244#[link_section = "MB_MEM2"]
245pub static mut EVT_POOL: MaybeUninit<Aligned<A4, [u8; POOL_SIZE]>> = MaybeUninit::uninit();
246
247#[link_section = "MB_MEM2"]
248pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
249
250#[link_section = "MB_MEM2"]
251pub static mut SYS_SPARE_EVT_BUF: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
252 MaybeUninit::uninit();
253
254#[link_section = "MB_MEM1"]
255pub static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
256
257#[link_section = "MB_MEM2"]
258pub static mut BLE_SPARE_EVT_BUF: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
259 MaybeUninit::uninit();
260
261#[link_section = "MB_MEM2"]
262// fuck these "magic" numbers from ST ---v---v
263pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> =
264 MaybeUninit::uninit();
diff --git a/embassy-stm32-wpan/src/unsafe_linked_list.rs b/embassy-stm32-wpan/src/unsafe_linked_list.rs
new file mode 100644
index 000000000..d8bc29763
--- /dev/null
+++ b/embassy-stm32-wpan/src/unsafe_linked_list.rs
@@ -0,0 +1,257 @@
1//! Unsafe linked list.
2//! Translated from ST's C by `c2rust` tool.
3
4#![allow(
5 dead_code,
6 mutable_transmutes,
7 non_camel_case_types,
8 non_snake_case,
9 non_upper_case_globals,
10 unused_assignments,
11 unused_mut
12)]
13
14use core::ptr;
15
16use cortex_m::interrupt;
17
18#[derive(Copy, Clone)]
19#[repr(C, packed(4))]
20pub struct LinkedListNode {
21 pub next: *mut LinkedListNode,
22 pub prev: *mut LinkedListNode,
23}
24
25impl Default for LinkedListNode {
26 fn default() -> Self {
27 LinkedListNode {
28 next: core::ptr::null_mut(),
29 prev: core::ptr::null_mut(),
30 }
31 }
32}
33
34impl LinkedListNode {
35 pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) {
36 ptr::write_volatile(
37 p_list_head,
38 LinkedListNode {
39 next: p_list_head,
40 prev: p_list_head,
41 },
42 );
43 }
44
45 pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool {
46 interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head)
47 }
48
49 /// Insert `node` after `list_head` and before the next node
50 pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
51 interrupt::free(|_| {
52 let mut list_head = ptr::read_volatile(p_list_head);
53 if p_list_head != list_head.next {
54 let mut node_next = ptr::read_volatile(list_head.next);
55 let node = LinkedListNode {
56 next: list_head.next,
57 prev: p_list_head,
58 };
59
60 list_head.next = p_node;
61 node_next.prev = p_node;
62
63 // All nodes must be written because they will all be seen by another core
64 ptr::write_volatile(p_node, node);
65 ptr::write_volatile(node.next, node_next);
66 ptr::write_volatile(p_list_head, list_head);
67 } else {
68 let node = LinkedListNode {
69 next: list_head.next,
70 prev: p_list_head,
71 };
72
73 list_head.next = p_node;
74 list_head.prev = p_node;
75
76 // All nodes must be written because they will all be seen by another core
77 ptr::write_volatile(p_node, node);
78 ptr::write_volatile(p_list_head, list_head);
79 }
80 });
81 }
82
83 /// Insert `node` before `list_tail` and after the second-to-last node
84 pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
85 interrupt::free(|_| {
86 let mut list_tail = ptr::read_volatile(p_list_tail);
87 if p_list_tail != list_tail.prev {
88 let mut node_prev = ptr::read_volatile(list_tail.prev);
89 let node = LinkedListNode {
90 next: p_list_tail,
91 prev: list_tail.prev,
92 };
93
94 list_tail.prev = p_node;
95 node_prev.next = p_node;
96
97 // All nodes must be written because they will all be seen by another core
98 ptr::write_volatile(p_node, node);
99 ptr::write_volatile(node.prev, node_prev);
100 ptr::write_volatile(p_list_tail, list_tail);
101 } else {
102 let node = LinkedListNode {
103 next: p_list_tail,
104 prev: list_tail.prev,
105 };
106
107 list_tail.prev = p_node;
108 list_tail.next = p_node;
109
110 // All nodes must be written because they will all be seen by another core
111 ptr::write_volatile(p_node, node);
112 ptr::write_volatile(p_list_tail, list_tail);
113 }
114 });
115 }
116
117 /// Remove `node` from the linked list
118 pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
119 interrupt::free(|_| {
120 // trace!("remove node: {:x}", p_node);
121 // apparently linked list nodes are not always aligned.
122 // if more hardfaults occur, more of these may need to be converted to unaligned.
123 let node = ptr::read_unaligned(p_node);
124 // trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next);
125
126 if node.next != node.prev {
127 let mut node_next = ptr::read_volatile(node.next);
128 let mut node_prev = ptr::read_volatile(node.prev);
129
130 node_prev.next = node.next;
131 node_next.prev = node.prev;
132
133 ptr::write_volatile(node.next, node_next);
134 ptr::write_volatile(node.prev, node_prev);
135 } else {
136 let mut node_next = ptr::read_volatile(node.next);
137
138 node_next.next = node.next;
139 node_next.prev = node.prev;
140
141 ptr::write_volatile(node.next, node_next);
142 }
143 });
144 }
145
146 /// Remove `list_head` and return a pointer to the `node`.
147 pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
148 interrupt::free(|_| {
149 let list_head = ptr::read_volatile(p_list_head);
150
151 if list_head.next == p_list_head {
152 None
153 } else {
154 // Allowed because a removed node is not seen by another core
155 let p_node = list_head.next;
156 Self::remove_node(p_node);
157
158 Some(p_node)
159 }
160 })
161 }
162
163 /// Remove `list_tail` and return a pointer to the `node`.
164 pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
165 interrupt::free(|_| {
166 let list_tail = ptr::read_volatile(p_list_tail);
167
168 if list_tail.prev == p_list_tail {
169 None
170 } else {
171 // Allowed because a removed node is not seen by another core
172 let p_node = list_tail.prev;
173 Self::remove_node(p_node);
174
175 Some(p_node)
176 }
177 })
178 }
179
180 pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
181 interrupt::free(|_| {
182 (*node).next = (*ref_node).next;
183 (*node).prev = ref_node;
184 (*ref_node).next = node;
185 (*(*node).next).prev = node;
186 });
187
188 todo!("this function has not been converted to volatile semantics");
189 }
190
191 pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
192 interrupt::free(|_| {
193 (*node).next = ref_node;
194 (*node).prev = (*ref_node).prev;
195 (*ref_node).prev = node;
196 (*(*node).prev).next = node;
197 });
198
199 todo!("this function has not been converted to volatile semantics");
200 }
201
202 pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
203 interrupt::free(|_| {
204 let mut size = 0;
205 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
206
207 temp = (*list_head).next;
208 while temp != list_head {
209 size += 1;
210 temp = (*temp).next
211 }
212
213 size
214 });
215
216 todo!("this function has not been converted to volatile semantics");
217 }
218
219 pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
220 interrupt::free(|_| {
221 let ref_node = ptr::read_volatile(p_ref_node);
222
223 // Allowed because a removed node is not seen by another core
224 ref_node.next
225 })
226 }
227
228 pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
229 interrupt::free(|_| {
230 let ref_node = ptr::read_volatile(p_ref_node);
231
232 // Allowed because a removed node is not seen by another core
233 ref_node.prev
234 })
235 }
236}
237
238#[allow(dead_code)]
239unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) {
240 info!("iterating list from node: {:x}", p_node);
241 let mut p_current_node = p_node;
242 let mut i = 0;
243 loop {
244 let current_node = ptr::read_volatile(p_current_node);
245 info!(
246 "node (prev, current, next): {:x}, {:x}, {:x}",
247 current_node.prev, p_current_node, current_node.next
248 );
249
250 i += 1;
251 if i > 10 || current_node.next == p_node {
252 break;
253 }
254
255 p_current_node = current_node.next;
256 }
257}
diff --git a/embassy-stm32/tl_mbox.x.in b/embassy-stm32-wpan/tl_mbox.x.in
index b6eecb429..b6eecb429 100644
--- a/embassy-stm32/tl_mbox.x.in
+++ b/embassy-stm32-wpan/tl_mbox.x.in
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 4e29bb32f..b3fe9c1f5 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -32,11 +32,9 @@ flavors = [
32 32
33[dependencies] 33[dependencies]
34embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 34embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
35embassy-executor = { version = "0.2.0", path = "../embassy-executor" }
36embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } 35embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
37embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 36embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
38embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]} 37embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] }
39embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
40embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 38embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
41embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 39embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
42embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } 40embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
@@ -59,7 +57,7 @@ sdio-host = "0.5.0"
59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
60critical-section = "1.1" 58critical-section = "1.1"
61atomic-polyfill = "1.0.1" 59atomic-polyfill = "1.0.1"
62stm32-metapac = "9" 60stm32-metapac = "12"
63vcell = "0.1.3" 61vcell = "0.1.3"
64bxcan = "0.7.0" 62bxcan = "0.7.0"
65nb = "1.0.0" 63nb = "1.0.0"
@@ -76,11 +74,13 @@ critical-section = { version = "1.1", features = ["std"] }
76[build-dependencies] 74[build-dependencies]
77proc-macro2 = "1.0.36" 75proc-macro2 = "1.0.36"
78quote = "1.0.15" 76quote = "1.0.15"
79stm32-metapac = { version = "9", default-features = false, features = ["metadata"]} 77stm32-metapac = { version = "12", default-features = false, features = ["metadata"]}
80 78
81[features] 79[features]
82default = ["stm32-metapac/rt"] 80default = ["rt"]
83defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] 81rt = ["stm32-metapac/rt"]
82
83defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
84memory-x = ["stm32-metapac/memory-x"] 84memory-x = ["stm32-metapac/memory-x"]
85exti = [] 85exti = []
86 86
@@ -99,7 +99,7 @@ time-driver-tim12 = ["_time-driver"]
99time-driver-tim15 = ["_time-driver"] 99time-driver-tim15 = ["_time-driver"]
100 100
101# Enable nightly-only features 101# Enable nightly-only features
102nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] 102nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
103 103
104# Reexport stm32-metapac at `embassy_stm32::pac`. 104# Reexport stm32-metapac at `embassy_stm32::pac`.
105# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. 105# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 730c78f5e..fa66da1f6 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -160,13 +160,11 @@ fn main() {
160 } 160 }
161 161
162 g.extend(quote! { 162 g.extend(quote! {
163 pub mod interrupt { 163 embassy_hal_common::interrupt_mod!(
164 use crate::pac::Interrupt as InterruptEnum;
165 use embassy_cortex_m::interrupt::_export::declare;
166 #( 164 #(
167 declare!(#irqs); 165 #irqs,
168 )* 166 )*
169 } 167 );
170 }); 168 });
171 169
172 // ======== 170 // ========
@@ -297,6 +295,7 @@ fn main() {
297 let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch)); 295 let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch));
298 296
299 g.extend(quote! { 297 g.extend(quote! {
298 #[cfg(feature = "rt")]
300 #[crate::interrupt] 299 #[crate::interrupt]
301 unsafe fn #irq () { 300 unsafe fn #irq () {
302 #( 301 #(
@@ -323,7 +322,7 @@ fn main() {
323 let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); 322 let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
324 let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); 323 let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
325 quote! { 324 quote! {
326 critical_section::with(|_| unsafe { 325 critical_section::with(|_| {
327 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); 326 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
328 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); 327 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
329 }); 328 });
@@ -354,13 +353,13 @@ fn main() {
354 }) 353 })
355 } 354 }
356 fn enable() { 355 fn enable() {
357 critical_section::with(|_| unsafe { 356 critical_section::with(|_| {
358 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); 357 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
359 #after_enable 358 #after_enable
360 }) 359 })
361 } 360 }
362 fn disable() { 361 fn disable() {
363 critical_section::with(|_| unsafe { 362 critical_section::with(|_| {
364 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); 363 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
365 }) 364 })
366 } 365 }
@@ -700,6 +699,8 @@ fn main() {
700 // SDMMCv1 uses the same channel for both directions, so just implement for RX 699 // SDMMCv1 uses the same channel for both directions, so just implement for RX
701 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 700 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
702 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), 701 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
702 (("dac", "CH1"), quote!(crate::dac::DmaCh1)),
703 (("dac", "CH2"), quote!(crate::dac::DmaCh2)),
703 ] 704 ]
704 .into(); 705 .into();
705 706
@@ -912,16 +913,6 @@ fn main() {
912 println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]); 913 println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]);
913 } 914 }
914 915
915 // ========
916 // stm32wb tl_mbox link sections
917
918 if chip_name.starts_with("stm32wb") {
919 let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string();
920 fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap();
921 println!("cargo:rustc-link-search={}", out_dir.display());
922 println!("cargo:rerun-if-changed=tl_mbox.x.in");
923 }
924
925 // ======= 916 // =======
926 // Features for targeting groups of chips 917 // Features for targeting groups of chips
927 918
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index d30ec001d..2322204d5 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -32,26 +32,22 @@ impl<'d, T: Instance> Adc<'d, T> {
32 into_ref!(adc); 32 into_ref!(adc);
33 T::enable(); 33 T::enable();
34 T::reset(); 34 T::reset();
35 unsafe { 35 T::regs().cr2().modify(|reg| reg.set_adon(true));
36 T::regs().cr2().modify(|reg| reg.set_adon(true));
37 }
38 36
39 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) 37 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
40 // for at least two ADC clock cycles 38 // for at least two ADC clock cycles
41 delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1); 39 delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1);
42 40
43 unsafe { 41 // Reset calibration
44 // Reset calibration 42 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
45 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 43 while T::regs().cr2().read().rstcal() {
46 while T::regs().cr2().read().rstcal() { 44 // spin
47 // spin 45 }
48 } 46
49 47 // Calibrate
50 // Calibrate 48 T::regs().cr2().modify(|reg| reg.set_cal(true));
51 T::regs().cr2().modify(|reg| reg.set_cal(true)); 49 while T::regs().cr2().read().cal() {
52 while T::regs().cr2().read().cal() { 50 // spin
53 // spin
54 }
55 } 51 }
56 52
57 // One cycle after calibration 53 // One cycle after calibration
@@ -81,20 +77,16 @@ impl<'d, T: Instance> Adc<'d, T> {
81 } 77 }
82 78
83 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { 79 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
84 unsafe { 80 T::regs().cr2().modify(|reg| {
85 T::regs().cr2().modify(|reg| { 81 reg.set_tsvrefe(true);
86 reg.set_tsvrefe(true); 82 });
87 })
88 }
89 Vref {} 83 Vref {}
90 } 84 }
91 85
92 pub fn enable_temperature(&self) -> Temperature { 86 pub fn enable_temperature(&self) -> Temperature {
93 unsafe { 87 T::regs().cr2().modify(|reg| {
94 T::regs().cr2().modify(|reg| { 88 reg.set_tsvrefe(true);
95 reg.set_tsvrefe(true); 89 });
96 })
97 }
98 Temperature {} 90 Temperature {}
99 } 91 }
100 92
@@ -104,41 +96,37 @@ impl<'d, T: Instance> Adc<'d, T> {
104 96
105 /// Perform a single conversion. 97 /// Perform a single conversion.
106 fn convert(&mut self) -> u16 { 98 fn convert(&mut self) -> u16 {
107 unsafe { 99 T::regs().cr2().modify(|reg| {
108 T::regs().cr2().modify(|reg| { 100 reg.set_adon(true);
109 reg.set_adon(true); 101 reg.set_swstart(true);
110 reg.set_swstart(true); 102 });
111 }); 103 while T::regs().cr2().read().swstart() {}
112 while T::regs().cr2().read().swstart() {} 104 while !T::regs().sr().read().eoc() {}
113 while !T::regs().sr().read().eoc() {} 105
114 106 T::regs().dr().read().0 as u16
115 T::regs().dr().read().0 as u16
116 }
117 } 107 }
118 108
119 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 109 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
120 unsafe { 110 Self::set_channel_sample_time(pin.channel(), self.sample_time);
121 Self::set_channel_sample_time(pin.channel(), self.sample_time); 111 T::regs().cr1().modify(|reg| {
122 T::regs().cr1().modify(|reg| { 112 reg.set_scan(false);
123 reg.set_scan(false); 113 reg.set_discen(false);
124 reg.set_discen(false); 114 });
125 }); 115 T::regs().sqr1().modify(|reg| reg.set_l(0));
126 T::regs().sqr1().modify(|reg| reg.set_l(0)); 116
127 117 T::regs().cr2().modify(|reg| {
128 T::regs().cr2().modify(|reg| { 118 reg.set_cont(false);
129 reg.set_cont(false); 119 reg.set_exttrig(true);
130 reg.set_exttrig(true); 120 reg.set_swstart(false);
131 reg.set_swstart(false); 121 reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
132 reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART); 122 });
133 });
134 }
135 123
136 // Configure the channel to sample 124 // Configure the channel to sample
137 unsafe { T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())) } 125 T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
138 self.convert() 126 self.convert()
139 } 127 }
140 128
141 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 129 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
142 let sample_time = sample_time.into(); 130 let sample_time = sample_time.into();
143 if ch <= 9 { 131 if ch <= 9 {
144 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); 132 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 82a8c3efb..d9af0c55e 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -57,18 +57,14 @@ impl<'d, T: Instance> Adc<'d, T> {
57 // 57 //
58 // 6.3.20 Vbat monitoring characteristics 58 // 6.3.20 Vbat monitoring characteristics
59 // ts_vbat ≥ 4μs 59 // ts_vbat ≥ 4μs
60 unsafe { 60 T::regs().ccr().modify(|reg| reg.set_vbaten(true));
61 T::regs().ccr().modify(|reg| reg.set_vbaten(true));
62 }
63 Vbat 61 Vbat
64 } 62 }
65 63
66 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref { 64 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
67 // Table 28. Embedded internal reference voltage 65 // Table 28. Embedded internal reference voltage
68 // tstart = 10μs 66 // tstart = 10μs
69 unsafe { 67 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
70 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
71 }
72 delay.delay_us(10); 68 delay.delay_us(10);
73 Vref 69 Vref
74 } 70 }
@@ -79,27 +75,23 @@ impl<'d, T: Instance> Adc<'d, T> {
79 // 6.3.19 Temperature sensor characteristics 75 // 6.3.19 Temperature sensor characteristics
80 // tstart ≤ 10μs 76 // tstart ≤ 10μs
81 // ts_temp ≥ 4μs 77 // ts_temp ≥ 4μs
82 unsafe { 78 T::regs().ccr().modify(|reg| reg.set_tsen(true));
83 T::regs().ccr().modify(|reg| reg.set_tsen(true));
84 }
85 delay.delay_us(10); 79 delay.delay_us(10);
86 Temperature 80 Temperature
87 } 81 }
88 82
89 fn calibrate(&self) { 83 fn calibrate(&self) {
90 unsafe { 84 // A.7.1 ADC calibration code example
91 // A.7.1 ADC calibration code example 85 if T::regs().cr().read().aden() {
92 if T::regs().cr().read().aden() { 86 T::regs().cr().modify(|reg| reg.set_addis(true));
93 T::regs().cr().modify(|reg| reg.set_addis(true)); 87 }
94 } 88 while T::regs().cr().read().aden() {
95 while T::regs().cr().read().aden() { 89 // spin
96 // spin 90 }
97 } 91 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
98 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); 92 T::regs().cr().modify(|reg| reg.set_adcal(true));
99 T::regs().cr().modify(|reg| reg.set_adcal(true)); 93 while T::regs().cr().read().adcal() {
100 while T::regs().cr().read().adcal() { 94 // spin
101 // spin
102 }
103 } 95 }
104 } 96 }
105 97
@@ -108,9 +100,7 @@ impl<'d, T: Instance> Adc<'d, T> {
108 } 100 }
109 101
110 pub fn set_resolution(&mut self, resolution: Resolution) { 102 pub fn set_resolution(&mut self, resolution: Resolution) {
111 unsafe { 103 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
112 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
113 }
114 } 104 }
115 105
116 pub fn read<P>(&mut self, pin: &mut P) -> u16 106 pub fn read<P>(&mut self, pin: &mut P) -> u16
@@ -118,18 +108,16 @@ impl<'d, T: Instance> Adc<'d, T> {
118 P: AdcPin<T> + crate::gpio::sealed::Pin, 108 P: AdcPin<T> + crate::gpio::sealed::Pin,
119 { 109 {
120 let channel = pin.channel(); 110 let channel = pin.channel();
121 unsafe { 111 pin.set_as_analog();
122 pin.set_as_analog(); 112 self.read_channel(channel)
123 self.read_channel(channel)
124 }
125 } 113 }
126 114
127 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 115 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
128 let channel = channel.channel(); 116 let channel = channel.channel();
129 unsafe { self.read_channel(channel) } 117 self.read_channel(channel)
130 } 118 }
131 119
132 unsafe fn read_channel(&mut self, channel: u8) -> u16 { 120 fn read_channel(&mut self, channel: u8) -> u16 {
133 // A.7.2 ADC enable sequence code example 121 // A.7.2 ADC enable sequence code example
134 if T::regs().isr().read().adrdy() { 122 if T::regs().isr().read().adrdy() {
135 T::regs().isr().modify(|reg| reg.set_adrdy(true)); 123 T::regs().isr().modify(|reg| reg.set_adrdy(true));
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 11a51f993..091c1d447 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -100,13 +100,10 @@ where
100 T::reset(); 100 T::reset();
101 101
102 let presc = Prescaler::from_pclk2(T::frequency()); 102 let presc = Prescaler::from_pclk2(T::frequency());
103 unsafe { 103 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
104 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); 104 T::regs().cr2().modify(|reg| {
105 105 reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
106 T::regs().cr2().modify(|reg| { 106 });
107 reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
108 });
109 }
110 107
111 delay.delay_us(ADC_POWERUP_TIME_US); 108 delay.delay_us(ADC_POWERUP_TIME_US);
112 109
@@ -121,19 +118,15 @@ where
121 } 118 }
122 119
123 pub fn set_resolution(&mut self, resolution: Resolution) { 120 pub fn set_resolution(&mut self, resolution: Resolution) {
124 unsafe { 121 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
125 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
126 }
127 } 122 }
128 123
129 /// Enables internal voltage reference and returns [VrefInt], which can be used in 124 /// Enables internal voltage reference and returns [VrefInt], which can be used in
130 /// [Adc::read_internal()] to perform conversion. 125 /// [Adc::read_internal()] to perform conversion.
131 pub fn enable_vrefint(&self) -> VrefInt { 126 pub fn enable_vrefint(&self) -> VrefInt {
132 unsafe { 127 T::common_regs().ccr().modify(|reg| {
133 T::common_regs().ccr().modify(|reg| { 128 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
134 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); 129 });
135 });
136 }
137 130
138 VrefInt {} 131 VrefInt {}
139 } 132 }
@@ -144,11 +137,9 @@ where
144 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, 137 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
145 /// temperature sensor will return vbat value. 138 /// temperature sensor will return vbat value.
146 pub fn enable_temperature(&self) -> Temperature { 139 pub fn enable_temperature(&self) -> Temperature {
147 unsafe { 140 T::common_regs().ccr().modify(|reg| {
148 T::common_regs().ccr().modify(|reg| { 141 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
149 reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); 142 });
150 });
151 }
152 143
153 Temperature {} 144 Temperature {}
154 } 145 }
@@ -156,37 +147,33 @@ where
156 /// Enables vbat input and returns [Vbat], which can be used in 147 /// Enables vbat input and returns [Vbat], which can be used in
157 /// [Adc::read_internal()] to perform conversion. 148 /// [Adc::read_internal()] to perform conversion.
158 pub fn enable_vbat(&self) -> Vbat { 149 pub fn enable_vbat(&self) -> Vbat {
159 unsafe { 150 T::common_regs().ccr().modify(|reg| {
160 T::common_regs().ccr().modify(|reg| { 151 reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
161 reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); 152 });
162 });
163 }
164 153
165 Vbat {} 154 Vbat {}
166 } 155 }
167 156
168 /// Perform a single conversion. 157 /// Perform a single conversion.
169 fn convert(&mut self) -> u16 { 158 fn convert(&mut self) -> u16 {
170 unsafe { 159 // clear end of conversion flag
171 // clear end of conversion flag 160 T::regs().sr().modify(|reg| {
172 T::regs().sr().modify(|reg| { 161 reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE);
173 reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); 162 });
174 }); 163
175 164 // Start conversion
176 // Start conversion 165 T::regs().cr2().modify(|reg| {
177 T::regs().cr2().modify(|reg| { 166 reg.set_swstart(true);
178 reg.set_swstart(true); 167 });
179 }); 168
180 169 while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED {
181 while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { 170 // spin //wait for actual start
182 // spin //wait for actual start
183 }
184 while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE {
185 // spin //wait for finish
186 }
187
188 T::regs().dr().read().0 as u16
189 } 171 }
172 while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE {
173 // spin //wait for finish
174 }
175
176 T::regs().dr().read().0 as u16
190 } 177 }
191 178
192 pub fn read<P>(&mut self, pin: &mut P) -> u16 179 pub fn read<P>(&mut self, pin: &mut P) -> u16
@@ -194,18 +181,16 @@ where
194 P: AdcPin<T>, 181 P: AdcPin<T>,
195 P: crate::gpio::sealed::Pin, 182 P: crate::gpio::sealed::Pin,
196 { 183 {
197 unsafe { 184 pin.set_as_analog();
198 pin.set_as_analog();
199 185
200 self.read_channel(pin.channel()) 186 self.read_channel(pin.channel())
201 }
202 } 187 }
203 188
204 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 189 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
205 unsafe { self.read_channel(channel.channel()) } 190 self.read_channel(channel.channel())
206 } 191 }
207 192
208 unsafe fn read_channel(&mut self, channel: u8) -> u16 { 193 fn read_channel(&mut self, channel: u8) -> u16 {
209 // Configure ADC 194 // Configure ADC
210 195
211 // Select channel 196 // Select channel
@@ -219,7 +204,7 @@ where
219 val 204 val
220 } 205 }
221 206
222 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 207 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
223 let sample_time = sample_time.into(); 208 let sample_time = sample_time.into();
224 if ch <= 9 { 209 if ch <= 9 {
225 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); 210 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 90aa7d3b9..3a6e58cf6 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -12,7 +12,7 @@ pub const VREF_CALIB_MV: u32 = 3000;
12/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock 12/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
13/// configuration. 13/// configuration.
14fn enable() { 14fn enable() {
15 critical_section::with(|_| unsafe { 15 critical_section::with(|_| {
16 #[cfg(stm32h7)] 16 #[cfg(stm32h7)]
17 crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); 17 crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
18 #[cfg(stm32g0)] 18 #[cfg(stm32g0)]
@@ -62,29 +62,25 @@ impl<'d, T: Instance> Adc<'d, T> {
62 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { 62 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
63 into_ref!(adc); 63 into_ref!(adc);
64 enable(); 64 enable();
65 unsafe { 65 T::regs().cr().modify(|reg| {
66 T::regs().cr().modify(|reg| { 66 #[cfg(not(adc_g0))]
67 #[cfg(not(adc_g0))] 67 reg.set_deeppwd(false);
68 reg.set_deeppwd(false); 68 reg.set_advregen(true);
69 reg.set_advregen(true); 69 });
70 }); 70
71 71 #[cfg(adc_g0)]
72 #[cfg(adc_g0)] 72 T::regs().cfgr1().modify(|reg| {
73 T::regs().cfgr1().modify(|reg| { 73 reg.set_chselrmod(false);
74 reg.set_chselrmod(false); 74 });
75 });
76 }
77 75
78 delay.delay_us(20); 76 delay.delay_us(20);
79 77
80 unsafe { 78 T::regs().cr().modify(|reg| {
81 T::regs().cr().modify(|reg| { 79 reg.set_adcal(true);
82 reg.set_adcal(true); 80 });
83 });
84 81
85 while T::regs().cr().read().adcal() { 82 while T::regs().cr().read().adcal() {
86 // spin 83 // spin
87 }
88 } 84 }
89 85
90 delay.delay_us(1); 86 delay.delay_us(1);
@@ -96,11 +92,9 @@ impl<'d, T: Instance> Adc<'d, T> {
96 } 92 }
97 93
98 pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { 94 pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
99 unsafe { 95 T::common_regs().ccr().modify(|reg| {
100 T::common_regs().ccr().modify(|reg| { 96 reg.set_vrefen(true);
101 reg.set_vrefen(true); 97 });
102 });
103 }
104 98
105 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us 99 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
106 // to stabilize the internal voltage reference, we wait a little more. 100 // to stabilize the internal voltage reference, we wait a little more.
@@ -112,21 +106,17 @@ impl<'d, T: Instance> Adc<'d, T> {
112 } 106 }
113 107
114 pub fn enable_temperature(&self) -> Temperature { 108 pub fn enable_temperature(&self) -> Temperature {
115 unsafe { 109 T::common_regs().ccr().modify(|reg| {
116 T::common_regs().ccr().modify(|reg| { 110 reg.set_ch17sel(true);
117 reg.set_ch17sel(true); 111 });
118 });
119 }
120 112
121 Temperature {} 113 Temperature {}
122 } 114 }
123 115
124 pub fn enable_vbat(&self) -> Vbat { 116 pub fn enable_vbat(&self) -> Vbat {
125 unsafe { 117 T::common_regs().ccr().modify(|reg| {
126 T::common_regs().ccr().modify(|reg| { 118 reg.set_ch18sel(true);
127 reg.set_ch18sel(true); 119 });
128 });
129 }
130 120
131 Vbat {} 121 Vbat {}
132 } 122 }
@@ -136,12 +126,10 @@ impl<'d, T: Instance> Adc<'d, T> {
136 } 126 }
137 127
138 pub fn set_resolution(&mut self, resolution: Resolution) { 128 pub fn set_resolution(&mut self, resolution: Resolution) {
139 unsafe { 129 #[cfg(not(stm32g0))]
140 #[cfg(not(stm32g0))] 130 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
141 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 131 #[cfg(stm32g0)]
142 #[cfg(stm32g0)] 132 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
143 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
144 }
145 } 133 }
146 134
147 /* 135 /*
@@ -155,82 +143,76 @@ impl<'d, T: Instance> Adc<'d, T> {
155 143
156 /// Perform a single conversion. 144 /// Perform a single conversion.
157 fn convert(&mut self) -> u16 { 145 fn convert(&mut self) -> u16 {
158 unsafe { 146 T::regs().isr().modify(|reg| {
159 T::regs().isr().modify(|reg| { 147 reg.set_eos(true);
160 reg.set_eos(true); 148 reg.set_eoc(true);
161 reg.set_eoc(true); 149 });
162 }); 150
163 151 // Start conversion
164 // Start conversion 152 T::regs().cr().modify(|reg| {
165 T::regs().cr().modify(|reg| { 153 reg.set_adstart(true);
166 reg.set_adstart(true); 154 });
167 }); 155
168 156 while !T::regs().isr().read().eos() {
169 while !T::regs().isr().read().eos() { 157 // spin
170 // spin
171 }
172
173 T::regs().dr().read().0 as u16
174 } 158 }
159
160 T::regs().dr().read().0 as u16
175 } 161 }
176 162
177 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 163 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
178 unsafe { 164 // Make sure bits are off
179 // Make sure bits are off 165 while T::regs().cr().read().addis() {
180 while T::regs().cr().read().addis() { 166 // spin
181 // spin 167 }
182 } 168
183 169 // Enable ADC
184 // Enable ADC 170 T::regs().isr().modify(|reg| {
185 T::regs().isr().modify(|reg| { 171 reg.set_adrdy(true);
186 reg.set_adrdy(true); 172 });
187 }); 173 T::regs().cr().modify(|reg| {
188 T::regs().cr().modify(|reg| { 174 reg.set_aden(true);
189 reg.set_aden(true); 175 });
190 }); 176
191 177 while !T::regs().isr().read().adrdy() {
192 while !T::regs().isr().read().adrdy() { 178 // spin
193 // spin
194 }
195
196 // Configure channel
197 Self::set_channel_sample_time(pin.channel(), self.sample_time);
198
199 // Select channel
200 #[cfg(not(stm32g0))]
201 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
202 #[cfg(stm32g0)]
203 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
204
205 // Some models are affected by an erratum:
206 // If we perform conversions slower than 1 kHz, the first read ADC value can be
207 // corrupted, so we discard it and measure again.
208 //
209 // STM32L471xx: Section 2.7.3
210 // STM32G4: Section 2.7.3
211 #[cfg(any(rcc_l4, rcc_g4))]
212 let _ = self.convert();
213
214 let val = self.convert();
215
216 T::regs().cr().modify(|reg| reg.set_addis(true));
217
218 val
219 } 179 }
180
181 // Configure channel
182 Self::set_channel_sample_time(pin.channel(), self.sample_time);
183
184 // Select channel
185 #[cfg(not(stm32g0))]
186 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
187 #[cfg(stm32g0)]
188 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
189
190 // Some models are affected by an erratum:
191 // If we perform conversions slower than 1 kHz, the first read ADC value can be
192 // corrupted, so we discard it and measure again.
193 //
194 // STM32L471xx: Section 2.7.3
195 // STM32G4: Section 2.7.3
196 #[cfg(any(rcc_l4, rcc_g4))]
197 let _ = self.convert();
198
199 let val = self.convert();
200
201 T::regs().cr().modify(|reg| reg.set_addis(true));
202
203 val
220 } 204 }
221 205
222 #[cfg(stm32g0)] 206 #[cfg(stm32g0)]
223 unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 207 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
224 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 208 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
225 } 209 }
226 210
227 #[cfg(not(stm32g0))] 211 #[cfg(not(stm32g0))]
228 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 212 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
229 let sample_time = sample_time.into(); 213 let sample_time = sample_time.into();
230 if ch <= 9 { 214 T::regs()
231 T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); 215 .smpr(ch as usize / 10)
232 } else { 216 .modify(|reg| reg.set_smp(ch as usize % 10, sample_time));
233 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
234 }
235 } 217 }
236} 218}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 4707b7c95..c51c6840f 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -46,8 +46,8 @@ foreach_peripheral!(
46 (adc, ADC1) => { 46 (adc, ADC1) => {
47 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { 47 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
48 fn frequency() -> crate::time::Hertz { 48 fn frequency() -> crate::time::Hertz {
49 critical_section::with(|_| unsafe { 49 critical_section::with(|_| {
50 match crate::rcc::get_freqs().adc { 50 match unsafe { crate::rcc::get_freqs() }.adc {
51 Some(ck) => ck, 51 Some(ck) => ck,
52 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") 52 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
53 } 53 }
@@ -55,7 +55,7 @@ foreach_peripheral!(
55 } 55 }
56 56
57 fn enable() { 57 fn enable() {
58 critical_section::with(|_| unsafe { 58 critical_section::with(|_| {
59 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) 59 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
60 }); 60 });
61 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); 61 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
@@ -63,7 +63,7 @@ foreach_peripheral!(
63 63
64 fn disable() { 64 fn disable() {
65 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 65 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
66 critical_section::with(|_| unsafe { 66 critical_section::with(|_| {
67 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); 67 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
68 }) 68 })
69 } 69 }
@@ -72,7 +72,7 @@ foreach_peripheral!(
72 72
73 fn reset() { 73 fn reset() {
74 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 74 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
75 critical_section::with(|_| unsafe { 75 critical_section::with(|_| {
76 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); 76 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
77 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); 77 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
78 }); 78 });
@@ -85,8 +85,8 @@ foreach_peripheral!(
85 (adc, ADC2) => { 85 (adc, ADC2) => {
86 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { 86 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
87 fn frequency() -> crate::time::Hertz { 87 fn frequency() -> crate::time::Hertz {
88 critical_section::with(|_| unsafe { 88 critical_section::with(|_| {
89 match crate::rcc::get_freqs().adc { 89 match unsafe { crate::rcc::get_freqs() }.adc {
90 Some(ck) => ck, 90 Some(ck) => ck,
91 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") 91 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
92 } 92 }
@@ -94,7 +94,7 @@ foreach_peripheral!(
94 } 94 }
95 95
96 fn enable() { 96 fn enable() {
97 critical_section::with(|_| unsafe { 97 critical_section::with(|_| {
98 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) 98 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
99 }); 99 });
100 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); 100 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
@@ -102,7 +102,7 @@ foreach_peripheral!(
102 102
103 fn disable() { 103 fn disable() {
104 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 104 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
105 critical_section::with(|_| unsafe { 105 critical_section::with(|_| {
106 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); 106 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
107 }) 107 })
108 } 108 }
@@ -111,7 +111,7 @@ foreach_peripheral!(
111 111
112 fn reset() { 112 fn reset() {
113 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 113 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
114 critical_section::with(|_| unsafe { 114 critical_section::with(|_| {
115 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); 115 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
116 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); 116 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
117 }); 117 });
@@ -124,8 +124,8 @@ foreach_peripheral!(
124 (adc, ADC3) => { 124 (adc, ADC3) => {
125 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { 125 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
126 fn frequency() -> crate::time::Hertz { 126 fn frequency() -> crate::time::Hertz {
127 critical_section::with(|_| unsafe { 127 critical_section::with(|_| {
128 match crate::rcc::get_freqs().adc { 128 match unsafe { crate::rcc::get_freqs() }.adc {
129 Some(ck) => ck, 129 Some(ck) => ck,
130 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") 130 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
131 } 131 }
@@ -133,22 +133,22 @@ foreach_peripheral!(
133 } 133 }
134 134
135 fn enable() { 135 fn enable() {
136 critical_section::with(|_| unsafe { 136 critical_section::with(|_| {
137 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) 137 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
138 }); 138 });
139 } 139 }
140 140
141 fn disable() { 141 fn disable() {
142 critical_section::with(|_| unsafe { 142 critical_section::with(|_| {
143 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); 143 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
144 }) 144 })
145 } 145 }
146 146
147 fn reset() { 147 fn reset() {
148 critical_section::with(|_| unsafe { 148 critical_section::with(|_| {
149 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); 149 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
150 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); 150 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
151 }); 151 });
152 } 152 }
153 } 153 }
154 154
@@ -232,9 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> {
232 232
233 let prescaler = Prescaler::from_ker_ck(T::frequency()); 233 let prescaler = Prescaler::from_ker_ck(T::frequency());
234 234
235 unsafe { 235 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
236 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
237 }
238 236
239 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 237 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
240 info!("ADC frequency set to {} Hz", frequency.0); 238 info!("ADC frequency set to {} Hz", frequency.0);
@@ -251,9 +249,7 @@ impl<'d, T: Instance> Adc<'d, T> {
251 } else { 249 } else {
252 Boost::LT50 250 Boost::LT50
253 }; 251 };
254 unsafe { 252 T::regs().cr().modify(|w| w.set_boost(boost));
255 T::regs().cr().modify(|w| w.set_boost(boost));
256 }
257 253
258 let mut s = Self { 254 let mut s = Self {
259 adc, 255 adc,
@@ -272,84 +268,68 @@ impl<'d, T: Instance> Adc<'d, T> {
272 } 268 }
273 269
274 fn power_up(&mut self, delay: &mut impl DelayUs<u16>) { 270 fn power_up(&mut self, delay: &mut impl DelayUs<u16>) {
275 unsafe { 271 T::regs().cr().modify(|reg| {
276 T::regs().cr().modify(|reg| { 272 reg.set_deeppwd(false);
277 reg.set_deeppwd(false); 273 reg.set_advregen(true);
278 reg.set_advregen(true); 274 });
279 });
280 }
281 275
282 delay.delay_us(10); 276 delay.delay_us(10);
283 } 277 }
284 278
285 fn configure_differential_inputs(&mut self) { 279 fn configure_differential_inputs(&mut self) {
286 unsafe { 280 T::regs().difsel().modify(|w| {
287 T::regs().difsel().modify(|w| { 281 for n in 0..20 {
288 for n in 0..20 { 282 w.set_difsel(n, Difsel::SINGLEENDED);
289 w.set_difsel(n, Difsel::SINGLEENDED); 283 }
290 } 284 });
291 })
292 };
293 } 285 }
294 286
295 fn calibrate(&mut self) { 287 fn calibrate(&mut self) {
296 unsafe { 288 T::regs().cr().modify(|w| {
297 T::regs().cr().modify(|w| { 289 w.set_adcaldif(Adcaldif::SINGLEENDED);
298 w.set_adcaldif(Adcaldif::SINGLEENDED); 290 w.set_adcallin(true);
299 w.set_adcallin(true); 291 });
300 });
301 292
302 T::regs().cr().modify(|w| w.set_adcal(true)); 293 T::regs().cr().modify(|w| w.set_adcal(true));
303 294
304 while T::regs().cr().read().adcal() {} 295 while T::regs().cr().read().adcal() {}
305 }
306 } 296 }
307 297
308 fn enable(&mut self) { 298 fn enable(&mut self) {
309 unsafe { 299 T::regs().isr().write(|w| w.set_adrdy(true));
310 T::regs().isr().write(|w| w.set_adrdy(true)); 300 T::regs().cr().modify(|w| w.set_aden(true));
311 T::regs().cr().modify(|w| w.set_aden(true)); 301 while !T::regs().isr().read().adrdy() {}
312 while !T::regs().isr().read().adrdy() {} 302 T::regs().isr().write(|w| w.set_adrdy(true));
313 T::regs().isr().write(|w| w.set_adrdy(true));
314 }
315 } 303 }
316 304
317 fn configure(&mut self) { 305 fn configure(&mut self) {
318 // single conversion mode, software trigger 306 // single conversion mode, software trigger
319 unsafe { 307 T::regs().cfgr().modify(|w| {
320 T::regs().cfgr().modify(|w| { 308 w.set_cont(false);
321 w.set_cont(false); 309 w.set_exten(Exten::DISABLED);
322 w.set_exten(Exten::DISABLED); 310 });
323 })
324 }
325 } 311 }
326 312
327 pub fn enable_vrefint(&self) -> VrefInt { 313 pub fn enable_vrefint(&self) -> VrefInt {
328 unsafe { 314 T::common_regs().ccr().modify(|reg| {
329 T::common_regs().ccr().modify(|reg| { 315 reg.set_vrefen(true);
330 reg.set_vrefen(true); 316 });
331 });
332 }
333 317
334 VrefInt {} 318 VrefInt {}
335 } 319 }
336 320
337 pub fn enable_temperature(&self) -> Temperature { 321 pub fn enable_temperature(&self) -> Temperature {
338 unsafe { 322 T::common_regs().ccr().modify(|reg| {
339 T::common_regs().ccr().modify(|reg| { 323 reg.set_vsenseen(true);
340 reg.set_vsenseen(true); 324 });
341 });
342 }
343 325
344 Temperature {} 326 Temperature {}
345 } 327 }
346 328
347 pub fn enable_vbat(&self) -> Vbat { 329 pub fn enable_vbat(&self) -> Vbat {
348 unsafe { 330 T::common_regs().ccr().modify(|reg| {
349 T::common_regs().ccr().modify(|reg| { 331 reg.set_vbaten(true);
350 reg.set_vbaten(true); 332 });
351 });
352 }
353 333
354 Vbat {} 334 Vbat {}
355 } 335 }
@@ -359,30 +339,26 @@ impl<'d, T: Instance> Adc<'d, T> {
359 } 339 }
360 340
361 pub fn set_resolution(&mut self, resolution: Resolution) { 341 pub fn set_resolution(&mut self, resolution: Resolution) {
362 unsafe { 342 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
363 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
364 }
365 } 343 }
366 344
367 /// Perform a single conversion. 345 /// Perform a single conversion.
368 fn convert(&mut self) -> u16 { 346 fn convert(&mut self) -> u16 {
369 unsafe { 347 T::regs().isr().modify(|reg| {
370 T::regs().isr().modify(|reg| { 348 reg.set_eos(true);
371 reg.set_eos(true); 349 reg.set_eoc(true);
372 reg.set_eoc(true); 350 });
373 });
374
375 // Start conversion
376 T::regs().cr().modify(|reg| {
377 reg.set_adstart(true);
378 });
379
380 while !T::regs().isr().read().eos() {
381 // spin
382 }
383 351
384 T::regs().dr().read().0 as u16 352 // Start conversion
353 T::regs().cr().modify(|reg| {
354 reg.set_adstart(true);
355 });
356
357 while !T::regs().isr().read().eos() {
358 // spin
385 } 359 }
360
361 T::regs().dr().read().0 as u16
386 } 362 }
387 363
388 pub fn read<P>(&mut self, pin: &mut P) -> u16 364 pub fn read<P>(&mut self, pin: &mut P) -> u16
@@ -390,18 +366,16 @@ impl<'d, T: Instance> Adc<'d, T> {
390 P: AdcPin<T>, 366 P: AdcPin<T>,
391 P: crate::gpio::sealed::Pin, 367 P: crate::gpio::sealed::Pin,
392 { 368 {
393 unsafe { 369 pin.set_as_analog();
394 pin.set_as_analog();
395 370
396 self.read_channel(pin.channel()) 371 self.read_channel(pin.channel())
397 }
398 } 372 }
399 373
400 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 374 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
401 unsafe { self.read_channel(channel.channel()) } 375 self.read_channel(channel.channel())
402 } 376 }
403 377
404 unsafe fn read_channel(&mut self, channel: u8) -> u16 { 378 fn read_channel(&mut self, channel: u8) -> u16 {
405 // Configure channel 379 // Configure channel
406 Self::set_channel_sample_time(channel, self.sample_time); 380 Self::set_channel_sample_time(channel, self.sample_time);
407 381
@@ -417,7 +391,7 @@ impl<'d, T: Instance> Adc<'d, T> {
417 self.convert() 391 self.convert()
418 } 392 }
419 393
420 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 394 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
421 let sample_time = sample_time.into(); 395 let sample_time = sample_time.into();
422 if ch <= 9 { 396 if ch <= 9 {
423 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); 397 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index bd92b35a0..73861776a 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -1,66 +1,358 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
1use core::ops::{Deref, DerefMut}; 3use core::ops::{Deref, DerefMut};
4use core::task::Poll;
2 5
3pub use bxcan; 6pub use bxcan;
7use bxcan::{Data, ExtendedId, Frame, Id, StandardId};
4use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
9use futures::FutureExt;
5 10
6use crate::gpio::sealed::AFType; 11use crate::gpio::sealed::AFType;
12use crate::interrupt::typelevel::Interrupt;
13use crate::pac::can::vals::{Lec, RirIde};
7use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
8use crate::{peripherals, Peripheral}; 15use crate::time::Hertz;
16use crate::{interrupt, peripherals, Peripheral};
17
18/// Interrupt handler.
19pub struct TxInterruptHandler<T: Instance> {
20 _phantom: PhantomData<T>,
21}
22
23impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptHandler<T> {
24 unsafe fn on_interrupt() {
25 T::regs().tsr().write(|v| {
26 v.set_rqcp(0, true);
27 v.set_rqcp(1, true);
28 v.set_rqcp(2, true);
29 });
30
31 T::state().tx_waker.wake();
32 }
33}
34
35pub struct Rx0InterruptHandler<T: Instance> {
36 _phantom: PhantomData<T>,
37}
38
39impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> {
40 unsafe fn on_interrupt() {
41 // info!("rx0 irq");
42 Can::<T>::receive_fifo(RxFifo::Fifo0);
43 }
44}
45
46pub struct Rx1InterruptHandler<T: Instance> {
47 _phantom: PhantomData<T>,
48}
49
50impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> {
51 unsafe fn on_interrupt() {
52 // info!("rx1 irq");
53 Can::<T>::receive_fifo(RxFifo::Fifo1);
54 }
55}
56
57pub struct SceInterruptHandler<T: Instance> {
58 _phantom: PhantomData<T>,
59}
60
61impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> {
62 unsafe fn on_interrupt() {
63 // info!("sce irq");
64 let msr = T::regs().msr();
65 let msr_val = msr.read();
66
67 if msr_val.erri() {
68 msr.modify(|v| v.set_erri(true));
69 T::state().err_waker.wake();
70 }
71 }
72}
9 73
10pub struct Can<'d, T: Instance> { 74pub struct Can<'d, T: Instance> {
11 can: bxcan::Can<BxcanInstance<'d, T>>, 75 can: bxcan::Can<BxcanInstance<'d, T>>,
12} 76}
13 77
78#[derive(Debug)]
79pub enum BusError {
80 Stuff,
81 Form,
82 Acknowledge,
83 BitRecessive,
84 BitDominant,
85 Crc,
86 Software,
87 BusOff,
88 BusPassive,
89 BusWarning,
90}
91
14impl<'d, T: Instance> Can<'d, T> { 92impl<'d, T: Instance> Can<'d, T> {
15 /// Creates a new Bxcan instance, blocking for 11 recessive bits to sync with the CAN bus. 93 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
94 /// You must call [Can::enable_non_blocking] to use the peripheral.
16 pub fn new( 95 pub fn new(
17 peri: impl Peripheral<P = T> + 'd, 96 peri: impl Peripheral<P = T> + 'd,
18 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 97 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
19 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 98 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
99 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
100 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
101 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
102 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
103 + 'd,
20 ) -> Self { 104 ) -> Self {
21 into_ref!(peri, rx, tx); 105 into_ref!(peri, rx, tx);
22 106
23 unsafe { 107 rx.set_as_af(rx.af_num(), AFType::Input);
24 rx.set_as_af(rx.af_num(), AFType::Input); 108 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
25 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
26 }
27 109
28 T::enable(); 110 T::enable();
29 T::reset(); 111 T::reset();
30 112
31 Self { 113 {
32 can: bxcan::Can::builder(BxcanInstance(peri)).enable(), 114 use crate::pac::can::vals::{Errie, Fmpie, Tmeie};
115
116 T::regs().ier().write(|w| {
117 // TODO: fix metapac
118
119 w.set_errie(Errie::from_bits(1));
120 w.set_fmpie(0, Fmpie::from_bits(1));
121 w.set_fmpie(1, Fmpie::from_bits(1));
122 w.set_tmeie(Tmeie::from_bits(1));
123 });
124
125 T::regs().mcr().write(|w| {
126 // Enable timestamps on rx messages
127
128 w.set_ttcm(true);
129 });
130 }
131
132 unsafe {
133 T::TXInterrupt::unpend();
134 T::TXInterrupt::enable();
135
136 T::RX0Interrupt::unpend();
137 T::RX0Interrupt::enable();
138
139 T::RX1Interrupt::unpend();
140 T::RX1Interrupt::enable();
141
142 T::SCEInterrupt::unpend();
143 T::SCEInterrupt::enable();
33 } 144 }
145
146 rx.set_as_af(rx.af_num(), AFType::Input);
147 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
148
149 let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
150 Self { can }
34 } 151 }
35 152
36 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. 153 pub fn set_bitrate(&mut self, bitrate: u32) {
37 /// You must call [Can::enable_non_blocking] to use the peripheral. 154 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
38 pub fn new_disabled( 155 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
39 peri: impl Peripheral<P = T> + 'd, 156 }
40 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
41 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
42 ) -> Self {
43 into_ref!(peri, rx, tx);
44 157
45 unsafe { 158 /// Queues the message to be sent but exerts backpressure
46 rx.set_as_af(rx.af_num(), AFType::Input); 159 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
47 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 160 poll_fn(|cx| {
161 T::state().tx_waker.register(cx.waker());
162 if let Ok(status) = self.can.transmit(frame) {
163 return Poll::Ready(status);
164 }
165
166 Poll::Pending
167 })
168 .await
169 }
170
171 pub async fn flush(&self, mb: bxcan::Mailbox) {
172 poll_fn(|cx| {
173 T::state().tx_waker.register(cx.waker());
174 if T::regs().tsr().read().tme(mb.index()) {
175 return Poll::Ready(());
176 }
177
178 Poll::Pending
179 })
180 .await;
181 }
182
183 /// Returns a tuple of the time the message was received and the message frame
184 pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> {
185 poll_fn(|cx| {
186 T::state().err_waker.register(cx.waker());
187 if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) {
188 return Poll::Ready(Ok((time, frame)));
189 } else if let Some(err) = self.curr_error() {
190 return Poll::Ready(Err(err));
191 }
192
193 Poll::Pending
194 })
195 .await
196 }
197
198 fn curr_error(&self) -> Option<BusError> {
199 let err = { T::regs().esr().read() };
200 if err.boff() {
201 return Some(BusError::BusOff);
202 } else if err.epvf() {
203 return Some(BusError::BusPassive);
204 } else if err.ewgf() {
205 return Some(BusError::BusWarning);
206 } else if let Some(err) = err.lec().into_bus_err() {
207 return Some(err);
48 } 208 }
209 None
210 }
49 211
50 T::enable(); 212 unsafe fn receive_fifo(fifo: RxFifo) {
51 T::reset(); 213 let state = T::state();
214 let regs = T::regs();
215 let fifo_idx = match fifo {
216 RxFifo::Fifo0 => 0usize,
217 RxFifo::Fifo1 => 1usize,
218 };
219 let rfr = regs.rfr(fifo_idx);
220 let fifo = regs.rx(fifo_idx);
221
222 loop {
223 // If there are no pending messages, there is nothing to do
224 if rfr.read().fmp() == 0 {
225 return;
226 }
227
228 let rir = fifo.rir().read();
229 let id = if rir.ide() == RirIde::STANDARD {
230 Id::from(StandardId::new_unchecked(rir.stid()))
231 } else {
232 let stid = (rir.stid() & 0x7FF) as u32;
233 let exid = rir.exid() & 0x3FFFF;
234 let id = (stid << 18) | (exid as u32);
235 Id::from(ExtendedId::new_unchecked(id))
236 };
237 let data_len = fifo.rdtr().read().dlc() as usize;
238 let mut data: [u8; 8] = [0; 8];
239 data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
240 data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
241
242 let time = fifo.rdtr().read().time();
243 let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap());
244
245 rfr.modify(|v| v.set_rfom(true));
246
247 /*
248 NOTE: consensus was reached that if rx_queue is full, packets should be dropped
249 */
250 let _ = state.rx_queue.try_send((time, frame));
251 }
252 }
253
254 pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
255 const BS1_MAX: u8 = 16;
256 const BS2_MAX: u8 = 8;
257 const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
258
259 let periph_clock = periph_clock.0;
260
261 if can_bitrate < 1000 {
262 return None;
263 }
264
265 // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
266 // CAN in Automation, 2003
267 //
268 // According to the source, optimal quanta per bit are:
269 // Bitrate Optimal Maximum
270 // 1000 kbps 8 10
271 // 500 kbps 16 17
272 // 250 kbps 16 17
273 // 125 kbps 16 17
274 let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
275
276 // Computing (prescaler * BS):
277 // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
278 // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
279 // let:
280 // BS = 1 + BS1 + BS2 -- Number of time quanta per bit
281 // PRESCALER_BS = PRESCALER * BS
282 // ==>
283 // PRESCALER_BS = PCLK / BITRATE
284 let prescaler_bs = periph_clock / can_bitrate;
52 285
53 Self { 286 // Searching for such prescaler value so that the number of quanta per bit is highest.
54 can: bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(), 287 let mut bs1_bs2_sum = max_quanta_per_bit - 1;
288 while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
289 if bs1_bs2_sum <= 2 {
290 return None; // No solution
291 }
292 bs1_bs2_sum -= 1;
293 }
294
295 let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
296 if (prescaler < 1) || (prescaler > 1024) {
297 return None; // No solution
298 }
299
300 // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
301 // We need to find such values so that the sample point is as close as possible to the optimal value,
302 // which is 87.5%, which is 7/8.
303 //
304 // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
305 // {{bs2 -> (1 + bs1)/7}}
306 //
307 // Hence:
308 // bs2 = (1 + bs1) / 7
309 // bs1 = (7 * bs1_bs2_sum - 1) / 8
310 //
311 // Sample point location can be computed as follows:
312 // Sample point location = (1 + bs1) / (1 + bs1 + bs2)
313 //
314 // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
315 // - With rounding to nearest
316 // - With rounding to zero
317 let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
318 let mut bs2 = bs1_bs2_sum - bs1;
319 core::assert!(bs1_bs2_sum > bs1);
320
321 let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
322 if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
323 // Nope, too far; now rounding to zero
324 bs1 = (7 * bs1_bs2_sum - 1) / 8;
325 bs2 = bs1_bs2_sum - bs1;
326 }
327
328 // Check is BS1 and BS2 are in range
329 if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
330 return None;
55 } 331 }
332
333 // Check if final bitrate matches the requested
334 if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
335 return None;
336 }
337
338 // One is recommended by DS-015, CANOpen, and DeviceNet
339 let sjw = 1;
340
341 // Pack into BTR register values
342 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1))
56 } 343 }
57} 344}
58 345
346enum RxFifo {
347 Fifo0,
348 Fifo1,
349}
350
59impl<'d, T: Instance> Drop for Can<'d, T> { 351impl<'d, T: Instance> Drop for Can<'d, T> {
60 fn drop(&mut self) { 352 fn drop(&mut self) {
61 // Cannot call `free()` because it moves the instance. 353 // Cannot call `free()` because it moves the instance.
62 // Manually reset the peripheral. 354 // Manually reset the peripheral.
63 unsafe { T::regs().mcr().write(|w| w.set_reset(true)) } 355 T::regs().mcr().write(|w| w.set_reset(true));
64 T::disable(); 356 T::disable();
65 } 357 }
66} 358}
@@ -80,14 +372,52 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> {
80} 372}
81 373
82pub(crate) mod sealed { 374pub(crate) mod sealed {
375 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
376 use embassy_sync::channel::Channel;
377 use embassy_sync::waitqueue::AtomicWaker;
378
379 pub struct State {
380 pub tx_waker: AtomicWaker,
381 pub err_waker: AtomicWaker,
382 pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>,
383 }
384
385 impl State {
386 pub const fn new() -> Self {
387 Self {
388 tx_waker: AtomicWaker::new(),
389 err_waker: AtomicWaker::new(),
390 rx_queue: Channel::new(),
391 }
392 }
393 }
394
83 pub trait Instance { 395 pub trait Instance {
84 const REGISTERS: *mut bxcan::RegisterBlock; 396 const REGISTERS: *mut bxcan::RegisterBlock;
85 397
86 fn regs() -> &'static crate::pac::can::Can; 398 fn regs() -> &'static crate::pac::can::Can;
399 fn state() -> &'static State;
87 } 400 }
88} 401}
89 402
90pub trait Instance: sealed::Instance + RccPeripheral {} 403pub trait TXInstance {
404 type TXInterrupt: crate::interrupt::typelevel::Interrupt;
405}
406
407pub trait RX0Instance {
408 type RX0Interrupt: crate::interrupt::typelevel::Interrupt;
409}
410
411pub trait RX1Instance {
412 type RX1Interrupt: crate::interrupt::typelevel::Interrupt;
413}
414
415pub trait SCEInstance {
416 type SCEInterrupt: crate::interrupt::typelevel::Interrupt;
417}
418
419pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {}
420pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
91 421
92pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); 422pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
93 423
@@ -98,15 +428,44 @@ unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
98foreach_peripheral!( 428foreach_peripheral!(
99 (can, $inst:ident) => { 429 (can, $inst:ident) => {
100 impl sealed::Instance for peripherals::$inst { 430 impl sealed::Instance for peripherals::$inst {
101 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _; 431 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
102 432
103 fn regs() -> &'static crate::pac::can::Can { 433 fn regs() -> &'static crate::pac::can::Can {
104 &crate::pac::$inst 434 &crate::pac::$inst
105 } 435 }
436
437 fn state() -> &'static sealed::State {
438 static STATE: sealed::State = sealed::State::new();
439 &STATE
440 }
106 } 441 }
107 442
108 impl Instance for peripherals::$inst {} 443 impl Instance for peripherals::$inst {}
109 444
445 foreach_interrupt!(
446 ($inst,can,CAN,TX,$irq:ident) => {
447 impl TXInstance for peripherals::$inst {
448 type TXInterrupt = crate::interrupt::typelevel::$irq;
449 }
450 };
451 ($inst,can,CAN,RX0,$irq:ident) => {
452 impl RX0Instance for peripherals::$inst {
453 type RX0Interrupt = crate::interrupt::typelevel::$irq;
454 }
455 };
456 ($inst,can,CAN,RX1,$irq:ident) => {
457 impl RX1Instance for peripherals::$inst {
458 type RX1Interrupt = crate::interrupt::typelevel::$irq;
459 }
460 };
461 ($inst,can,CAN,SCE,$irq:ident) => {
462 impl SCEInstance for peripherals::$inst {
463 type SCEInterrupt = crate::interrupt::typelevel::$irq;
464 }
465 };
466 );
467
468 impl InterruptableInstance for peripherals::$inst {}
110 }; 469 };
111); 470);
112 471
@@ -147,3 +506,36 @@ foreach_peripheral!(
147 506
148pin_trait!(RxPin, Instance); 507pin_trait!(RxPin, Instance);
149pin_trait!(TxPin, Instance); 508pin_trait!(TxPin, Instance);
509
510trait Index {
511 fn index(&self) -> usize;
512}
513
514impl Index for bxcan::Mailbox {
515 fn index(&self) -> usize {
516 match self {
517 bxcan::Mailbox::Mailbox0 => 0,
518 bxcan::Mailbox::Mailbox1 => 1,
519 bxcan::Mailbox::Mailbox2 => 2,
520 }
521 }
522}
523
524trait IntoBusError {
525 fn into_bus_err(self) -> Option<BusError>;
526}
527
528impl IntoBusError for Lec {
529 fn into_bus_err(self) -> Option<BusError> {
530 match self {
531 Lec::STUFF => Some(BusError::Stuff),
532 Lec::FORM => Some(BusError::Form),
533 Lec::ACK => Some(BusError::Acknowledge),
534 Lec::BITRECESSIVE => Some(BusError::BitRecessive),
535 Lec::BITDOMINANT => Some(BusError::BitDominant),
536 Lec::CRC => Some(BusError::Crc),
537 Lec::CUSTOM => Some(BusError::Software),
538 _ => None,
539 }
540 }
541}
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index 393089eed..3946a2d47 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -27,26 +27,24 @@ impl<'d> Crc<'d> {
27 27
28 /// Resets the CRC unit to default value (0xFFFF_FFFF) 28 /// Resets the CRC unit to default value (0xFFFF_FFFF)
29 pub fn reset(&mut self) { 29 pub fn reset(&mut self) {
30 unsafe { PAC_CRC.cr().write(|w| w.set_reset(true)) }; 30 PAC_CRC.cr().write(|w| w.set_reset(true));
31 } 31 }
32 32
33 /// Feeds a word to the peripheral and returns the current CRC value 33 /// Feeds a word to the peripheral and returns the current CRC value
34 pub fn feed_word(&mut self, word: u32) -> u32 { 34 pub fn feed_word(&mut self, word: u32) -> u32 {
35 // write a single byte to the device, and return the result 35 // write a single byte to the device, and return the result
36 unsafe { 36 PAC_CRC.dr().write_value(word);
37 PAC_CRC.dr().write_value(word);
38 }
39 self.read() 37 self.read()
40 } 38 }
41 /// Feed a slice of words to the peripheral and return the result. 39 /// Feed a slice of words to the peripheral and return the result.
42 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 40 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
43 for word in words { 41 for word in words {
44 unsafe { PAC_CRC.dr().write_value(*word) } 42 PAC_CRC.dr().write_value(*word);
45 } 43 }
46 44
47 self.read() 45 self.read()
48 } 46 }
49 pub fn read(&self) -> u32 { 47 pub fn read(&self) -> u32 {
50 unsafe { PAC_CRC.dr().read() } 48 PAC_CRC.dr().read()
51 } 49 }
52} 50}
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index 8acb3a770..f337055a7 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -85,95 +85,79 @@ impl<'d> Crc<'d> {
85 } 85 }
86 86
87 pub fn reset(&mut self) { 87 pub fn reset(&mut self) {
88 unsafe { 88 PAC_CRC.cr().modify(|w| w.set_reset(true));
89 PAC_CRC.cr().modify(|w| w.set_reset(true));
90 }
91 } 89 }
92 90
93 /// Reconfigures the CRC peripheral. Doesn't reset. 91 /// Reconfigures the CRC peripheral. Doesn't reset.
94 fn reconfigure(&mut self) { 92 fn reconfigure(&mut self) {
95 unsafe { 93 // Init CRC value
96 // Init CRC value 94 PAC_CRC.init().write_value(self._config.crc_init_value);
97 PAC_CRC.init().write_value(self._config.crc_init_value); 95 #[cfg(crc_v3)]
98 #[cfg(crc_v3)] 96 PAC_CRC.pol().write_value(self._config.crc_poly);
99 PAC_CRC.pol().write_value(self._config.crc_poly);
100 97
101 // configure CR components 98 // configure CR components
102 // (reverse I/O, polysize, poly) 99 // (reverse I/O, polysize, poly)
103 PAC_CRC.cr().write(|w| { 100 PAC_CRC.cr().write(|w| {
104 // configure reverse output 101 // configure reverse output
105 w.set_rev_out(match self._config.reverse_out { 102 w.set_rev_out(match self._config.reverse_out {
106 true => vals::RevOut::REVERSED, 103 true => vals::RevOut::REVERSED,
107 false => vals::RevOut::NORMAL, 104 false => vals::RevOut::NORMAL,
108 }); 105 });
109 // configure reverse input 106 // configure reverse input
110 w.set_rev_in(match self._config.reverse_in { 107 w.set_rev_in(match self._config.reverse_in {
111 InputReverseConfig::None => vals::RevIn::NORMAL, 108 InputReverseConfig::None => vals::RevIn::NORMAL,
112 InputReverseConfig::Byte => vals::RevIn::BYTE, 109 InputReverseConfig::Byte => vals::RevIn::BYTE,
113 InputReverseConfig::Halfword => vals::RevIn::HALFWORD, 110 InputReverseConfig::Halfword => vals::RevIn::HALFWORD,
114 InputReverseConfig::Word => vals::RevIn::WORD, 111 InputReverseConfig::Word => vals::RevIn::WORD,
115 }); 112 });
116 // configure the polynomial. 113 // configure the polynomial.
117 #[cfg(crc_v3)] 114 #[cfg(crc_v3)]
118 w.set_polysize(match self._config.poly_size { 115 w.set_polysize(match self._config.poly_size {
119 PolySize::Width7 => vals::Polysize::POLYSIZE7, 116 PolySize::Width7 => vals::Polysize::POLYSIZE7,
120 PolySize::Width8 => vals::Polysize::POLYSIZE8, 117 PolySize::Width8 => vals::Polysize::POLYSIZE8,
121 PolySize::Width16 => vals::Polysize::POLYSIZE16, 118 PolySize::Width16 => vals::Polysize::POLYSIZE16,
122 PolySize::Width32 => vals::Polysize::POLYSIZE32, 119 PolySize::Width32 => vals::Polysize::POLYSIZE32,
123 }); 120 });
124 }) 121 });
125 }
126 122
127 self.reset(); 123 self.reset();
128 } 124 }
129 125
130 /// Feeds a byte into the CRC peripheral. Returns the computed checksum. 126 /// Feeds a byte into the CRC peripheral. Returns the computed checksum.
131 pub fn feed_byte(&mut self, byte: u8) -> u32 { 127 pub fn feed_byte(&mut self, byte: u8) -> u32 {
132 unsafe { 128 PAC_CRC.dr8().write_value(byte);
133 PAC_CRC.dr8().write_value(byte); 129 PAC_CRC.dr().read()
134 PAC_CRC.dr().read()
135 }
136 } 130 }
137 131
138 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. 132 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
139 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { 133 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
140 for byte in bytes { 134 for byte in bytes {
141 unsafe { 135 PAC_CRC.dr8().write_value(*byte);
142 PAC_CRC.dr8().write_value(*byte);
143 }
144 } 136 }
145 unsafe { PAC_CRC.dr().read() } 137 PAC_CRC.dr().read()
146 } 138 }
147 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. 139 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
148 pub fn feed_halfword(&mut self, halfword: u16) -> u32 { 140 pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
149 unsafe { 141 PAC_CRC.dr16().write_value(halfword);
150 PAC_CRC.dr16().write_value(halfword); 142 PAC_CRC.dr().read()
151 PAC_CRC.dr().read()
152 }
153 } 143 }
154 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. 144 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
155 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { 145 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
156 for halfword in halfwords { 146 for halfword in halfwords {
157 unsafe { 147 PAC_CRC.dr16().write_value(*halfword);
158 PAC_CRC.dr16().write_value(*halfword);
159 }
160 } 148 }
161 unsafe { PAC_CRC.dr().read() } 149 PAC_CRC.dr().read()
162 } 150 }
163 /// Feeds a words into the CRC peripheral. Returns the computed checksum. 151 /// Feeds a words into the CRC peripheral. Returns the computed checksum.
164 pub fn feed_word(&mut self, word: u32) -> u32 { 152 pub fn feed_word(&mut self, word: u32) -> u32 {
165 unsafe { 153 PAC_CRC.dr().write_value(word as u32);
166 PAC_CRC.dr().write_value(word as u32); 154 PAC_CRC.dr().read()
167 PAC_CRC.dr().read()
168 }
169 } 155 }
170 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. 156 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
171 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 157 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
172 for word in words { 158 for word in words {
173 unsafe { 159 PAC_CRC.dr().write_value(*word as u32);
174 PAC_CRC.dr().write_value(*word as u32);
175 }
176 } 160 }
177 unsafe { PAC_CRC.dr().read() } 161 PAC_CRC.dr().read()
178 } 162 }
179} 163}
diff --git a/embassy-stm32/src/dac.rs b/embassy-stm32/src/dac.rs
deleted file mode 100644
index 60e856c78..000000000
--- a/embassy-stm32/src/dac.rs
+++ /dev/null
@@ -1,278 +0,0 @@
1#![macro_use]
2
3use embassy_hal_common::{into_ref, PeripheralRef};
4
5use crate::pac::dac;
6use crate::rcc::RccPeripheral;
7use crate::{peripherals, Peripheral};
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq)]
10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11pub enum Error {
12 UnconfiguredChannel,
13 InvalidValue,
14}
15
16#[derive(Debug, Copy, Clone, Eq, PartialEq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Channel {
19 Ch1,
20 Ch2,
21}
22
23impl Channel {
24 fn index(&self) -> usize {
25 match self {
26 Channel::Ch1 => 0,
27 Channel::Ch2 => 1,
28 }
29 }
30}
31
32#[derive(Debug, Copy, Clone, Eq, PartialEq)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub enum Ch1Trigger {
35 Tim6,
36 Tim3,
37 Tim7,
38 Tim15,
39 Tim2,
40 Exti9,
41 Software,
42}
43
44impl Ch1Trigger {
45 fn tsel(&self) -> dac::vals::Tsel1 {
46 match self {
47 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
48 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
49 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
50 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
51 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
52 Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
53 Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
54 }
55 }
56}
57
58#[derive(Debug, Copy, Clone, Eq, PartialEq)]
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
60pub enum Ch2Trigger {
61 Tim6,
62 Tim8,
63 Tim7,
64 Tim5,
65 Tim2,
66 Tim4,
67 Exti9,
68 Software,
69}
70
71impl Ch2Trigger {
72 fn tsel(&self) -> dac::vals::Tsel2 {
73 match self {
74 Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
75 Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
76 Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
77 Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
78 Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
79 Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
80 Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
81 Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
82 }
83 }
84}
85
86#[derive(Debug, Copy, Clone, Eq, PartialEq)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub enum Alignment {
89 Left,
90 Right,
91}
92
93#[derive(Debug, Copy, Clone, Eq, PartialEq)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95pub enum Value {
96 Bit8(u8),
97 Bit12(u16, Alignment),
98}
99
100pub struct Dac<'d, T: Instance> {
101 channels: u8,
102 _peri: PeripheralRef<'d, T>,
103}
104
105impl<'d, T: Instance> Dac<'d, T> {
106 pub fn new_1ch(peri: impl Peripheral<P = T> + 'd, _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd) -> Self {
107 into_ref!(peri);
108 Self::new_inner(peri, 1)
109 }
110
111 pub fn new_2ch(
112 peri: impl Peripheral<P = T> + 'd,
113 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
114 _ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
115 ) -> Self {
116 into_ref!(peri);
117 Self::new_inner(peri, 2)
118 }
119
120 fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self {
121 T::enable();
122 T::reset();
123
124 unsafe {
125 T::regs().cr().modify(|reg| {
126 for ch in 0..channels {
127 reg.set_en(ch as usize, true);
128 }
129 });
130 }
131
132 Self { channels, _peri: peri }
133 }
134
135 /// Check the channel is configured
136 fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> {
137 if ch == Channel::Ch2 && self.channels < 2 {
138 Err(Error::UnconfiguredChannel)
139 } else {
140 Ok(())
141 }
142 }
143
144 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
145 self.check_channel_exists(ch)?;
146 unsafe {
147 T::regs().cr().modify(|reg| {
148 reg.set_en(ch.index(), on);
149 })
150 }
151 Ok(())
152 }
153
154 pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
155 self.set_channel_enable(ch, true)
156 }
157
158 pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
159 self.set_channel_enable(ch, false)
160 }
161
162 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
163 self.check_channel_exists(Channel::Ch1)?;
164 unwrap!(self.disable_channel(Channel::Ch1));
165 unsafe {
166 T::regs().cr().modify(|reg| {
167 reg.set_tsel1(trigger.tsel());
168 })
169 }
170 Ok(())
171 }
172
173 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
174 self.check_channel_exists(Channel::Ch2)?;
175 unwrap!(self.disable_channel(Channel::Ch2));
176 unsafe {
177 T::regs().cr().modify(|reg| {
178 reg.set_tsel2(trigger.tsel());
179 })
180 }
181 Ok(())
182 }
183
184 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
185 self.check_channel_exists(ch)?;
186 unsafe {
187 T::regs().swtrigr().write(|reg| {
188 reg.set_swtrig(ch.index(), true);
189 });
190 }
191 Ok(())
192 }
193
194 pub fn trigger_all(&mut self) {
195 unsafe {
196 T::regs().swtrigr().write(|reg| {
197 reg.set_swtrig(Channel::Ch1.index(), true);
198 reg.set_swtrig(Channel::Ch2.index(), true);
199 })
200 }
201 }
202
203 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
204 self.check_channel_exists(ch)?;
205 match value {
206 Value::Bit8(v) => unsafe {
207 T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v));
208 },
209 Value::Bit12(v, Alignment::Left) => unsafe {
210 T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v));
211 },
212 Value::Bit12(v, Alignment::Right) => unsafe {
213 T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v));
214 },
215 }
216 Ok(())
217 }
218}
219
220pub(crate) mod sealed {
221 pub trait Instance {
222 fn regs() -> &'static crate::pac::dac::Dac;
223 }
224}
225
226pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
227
228pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
229
230foreach_peripheral!(
231 (dac, $inst:ident) => {
232 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
233 #[cfg(rcc_h7)]
234 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
235 fn frequency() -> crate::time::Hertz {
236 critical_section::with(|_| unsafe {
237 crate::rcc::get_freqs().apb1
238 })
239 }
240
241 fn reset() {
242 critical_section::with(|_| unsafe {
243 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
244 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
245 })
246 }
247
248 fn enable() {
249 critical_section::with(|_| unsafe {
250 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
251 })
252 }
253
254 fn disable() {
255 critical_section::with(|_| unsafe {
256 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false));
257 })
258 }
259 }
260
261 #[cfg(rcc_h7)]
262 impl crate::rcc::RccPeripheral for peripherals::$inst {}
263
264 impl crate::dac::sealed::Instance for peripherals::$inst {
265 fn regs() -> &'static crate::pac::dac::Dac {
266 &crate::pac::$inst
267 }
268 }
269
270 impl crate::dac::Instance for peripherals::$inst {}
271 };
272);
273
274macro_rules! impl_dac_pin {
275 ($inst:ident, $pin:ident, $ch:expr) => {
276 impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
277 };
278}
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
new file mode 100644
index 000000000..1dc13949d
--- /dev/null
+++ b/embassy-stm32/src/dac/mod.rs
@@ -0,0 +1,570 @@
1#![macro_use]
2
3//! Provide access to the STM32 digital-to-analog converter (DAC).
4use core::marker::PhantomData;
5
6use embassy_hal_common::{into_ref, PeripheralRef};
7
8use crate::pac::dac;
9use crate::rcc::RccPeripheral;
10use crate::{peripherals, Peripheral};
11
12#[derive(Debug, Copy, Clone, Eq, PartialEq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14/// Curstom Errors
15pub enum Error {
16 UnconfiguredChannel,
17 InvalidValue,
18}
19
20#[derive(Debug, Copy, Clone, Eq, PartialEq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22/// DAC Channels
23pub enum Channel {
24 Ch1,
25 Ch2,
26}
27
28impl Channel {
29 const fn index(&self) -> usize {
30 match self {
31 Channel::Ch1 => 0,
32 Channel::Ch2 => 1,
33 }
34 }
35}
36
37#[derive(Debug, Copy, Clone, Eq, PartialEq)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39/// Trigger sources for CH1
40pub enum Ch1Trigger {
41 Tim6,
42 Tim3,
43 Tim7,
44 Tim15,
45 Tim2,
46 Exti9,
47 Software,
48}
49
50impl Ch1Trigger {
51 fn tsel(&self) -> dac::vals::Tsel1 {
52 match self {
53 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
54 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
55 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
56 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
57 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
58 Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
59 Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
60 }
61 }
62}
63
64#[derive(Debug, Copy, Clone, Eq, PartialEq)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66/// Trigger sources for CH2
67pub enum Ch2Trigger {
68 Tim6,
69 Tim8,
70 Tim7,
71 Tim5,
72 Tim2,
73 Tim4,
74 Exti9,
75 Software,
76}
77
78impl Ch2Trigger {
79 fn tsel(&self) -> dac::vals::Tsel2 {
80 match self {
81 Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
82 Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
83 Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
84 Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
85 Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
86 Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
87 Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
88 Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
89 }
90 }
91}
92
93#[derive(Debug, Copy, Clone, Eq, PartialEq)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95/// Single 8 or 12 bit value that can be output by the DAC
96pub enum Value {
97 // 8 bit value
98 Bit8(u8),
99 // 12 bit value stored in a u16, left-aligned
100 Bit12Left(u16),
101 // 12 bit value stored in a u16, right-aligned
102 Bit12Right(u16),
103}
104
105#[derive(Debug, Copy, Clone, Eq, PartialEq)]
106#[cfg_attr(feature = "defmt", derive(defmt::Format))]
107/// Array variant of [`Value`]
108pub enum ValueArray<'a> {
109 // 8 bit values
110 Bit8(&'a [u8]),
111 // 12 bit value stored in a u16, left-aligned
112 Bit12Left(&'a [u16]),
113 // 12 bit values stored in a u16, right-aligned
114 Bit12Right(&'a [u16]),
115}
116/// Provide common functions for DAC channels
117pub trait DacChannel<T: Instance, Tx> {
118 const CHANNEL: Channel;
119
120 /// Enable trigger of the given channel
121 fn set_trigger_enable(&mut self, on: bool) -> Result<(), Error> {
122 T::regs().cr().modify(|reg| {
123 reg.set_ten(Self::CHANNEL.index(), on);
124 });
125 Ok(())
126 }
127
128 /// Set mode register of the given channel
129 #[cfg(dac_v2)]
130 fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> {
131 T::regs().mcr().modify(|reg| {
132 reg.set_mode(Self::CHANNEL.index(), val);
133 });
134 Ok(())
135 }
136
137 /// Set enable register of the given channel
138 fn set_channel_enable(&mut self, on: bool) -> Result<(), Error> {
139 T::regs().cr().modify(|reg| {
140 reg.set_en(Self::CHANNEL.index(), on);
141 });
142 Ok(())
143 }
144
145 /// Enable the DAC channel `ch`
146 fn enable_channel(&mut self) -> Result<(), Error> {
147 self.set_channel_enable(true)
148 }
149
150 /// Disable the DAC channel `ch`
151 fn disable_channel(&mut self) -> Result<(), Error> {
152 self.set_channel_enable(false)
153 }
154
155 /// Perform a software trigger on `ch`
156 fn trigger(&mut self) {
157 T::regs().swtrigr().write(|reg| {
158 reg.set_swtrig(Self::CHANNEL.index(), true);
159 });
160 }
161
162 /// Set a value to be output by the DAC on trigger.
163 ///
164 /// The `value` is written to the corresponding "data holding register".
165 fn set(&mut self, value: Value) -> Result<(), Error> {
166 match value {
167 Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
168 Value::Bit12Left(v) => T::regs().dhr12l(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
169 Value::Bit12Right(v) => T::regs().dhr12r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
170 }
171 Ok(())
172 }
173}
174
175/// Hold two DAC channels
176///
177/// Note: This consumes the DAC `Instance` only once, allowing to get both channels simultaneously.
178///
179/// # Example for obtaining both DAC channels
180///
181/// ```ignore
182/// // DMA channels and pins may need to be changed for your controller
183/// let (dac_ch1, dac_ch2) =
184/// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
185/// ```
186pub struct Dac<'d, T: Instance, TxCh1, TxCh2> {
187 ch1: DacCh1<'d, T, TxCh1>,
188 ch2: DacCh2<'d, T, TxCh2>,
189}
190
191/// DAC CH1
192///
193/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
194pub struct DacCh1<'d, T: Instance, Tx> {
195 /// To consume T
196 _peri: PeripheralRef<'d, T>,
197 #[allow(unused)] // For chips whose DMA is not (yet) supported
198 dma: PeripheralRef<'d, Tx>,
199}
200
201/// DAC CH2
202///
203/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
204pub struct DacCh2<'d, T: Instance, Tx> {
205 /// Instead of PeripheralRef to consume T
206 phantom: PhantomData<&'d mut T>,
207 #[allow(unused)] // For chips whose DMA is not (yet) supported
208 dma: PeripheralRef<'d, Tx>,
209}
210
211impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
212 /// Obtain DAC CH1
213 pub fn new(
214 peri: impl Peripheral<P = T> + 'd,
215 dma: impl Peripheral<P = Tx> + 'd,
216 _pin: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
217 ) -> Self {
218 into_ref!(peri, dma);
219 T::enable();
220 T::reset();
221
222 let mut dac = Self { _peri: peri, dma };
223
224 // Configure each activated channel. All results can be `unwrap`ed since they
225 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
226 #[cfg(dac_v2)]
227 dac.set_channel_mode(0).unwrap();
228 dac.enable_channel().unwrap();
229 dac.set_trigger_enable(true).unwrap();
230
231 dac
232 }
233
234 /// Select a new trigger for this channel
235 ///
236 /// **Important**: This disables the channel!
237 pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
238 unwrap!(self.disable_channel());
239 T::regs().cr().modify(|reg| {
240 reg.set_tsel1(trigger.tsel());
241 });
242 Ok(())
243 }
244
245 /// Write `data` to the DAC CH1 via DMA.
246 ///
247 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
248 /// This will configure a circular DMA transfer that periodically outputs the `data`.
249 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
250 ///
251 /// **Important:** Channel 1 has to be configured for the DAC instance!
252 #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
253 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
254 where
255 Tx: DmaCh1<T>,
256 {
257 let channel = Channel::Ch1.index();
258 debug!("Writing to channel {}", channel);
259
260 // Enable DAC and DMA
261 T::regs().cr().modify(|w| {
262 w.set_en(channel, true);
263 w.set_dmaen(channel, true);
264 });
265
266 let tx_request = self.dma.request();
267 let dma_channel = &self.dma;
268
269 let tx_options = crate::dma::TransferOptions {
270 circular,
271 half_transfer_ir: false,
272 complete_transfer_ir: !circular,
273 ..Default::default()
274 };
275
276 // Initiate the correct type of DMA transfer depending on what data is passed
277 let tx_f = match data {
278 ValueArray::Bit8(buf) => unsafe {
279 crate::dma::Transfer::new_write(
280 dma_channel,
281 tx_request,
282 buf,
283 T::regs().dhr8r(channel).as_ptr() as *mut u8,
284 tx_options,
285 )
286 },
287 ValueArray::Bit12Left(buf) => unsafe {
288 crate::dma::Transfer::new_write(
289 dma_channel,
290 tx_request,
291 buf,
292 T::regs().dhr12l(channel).as_ptr() as *mut u16,
293 tx_options,
294 )
295 },
296 ValueArray::Bit12Right(buf) => unsafe {
297 crate::dma::Transfer::new_write(
298 dma_channel,
299 tx_request,
300 buf,
301 T::regs().dhr12r(channel).as_ptr() as *mut u16,
302 tx_options,
303 )
304 },
305 };
306
307 tx_f.await;
308
309 // finish dma
310 // TODO: Do we need to check any status registers here?
311 T::regs().cr().modify(|w| {
312 // Disable the DAC peripheral
313 w.set_en(channel, false);
314 // Disable the DMA. TODO: Is this necessary?
315 w.set_dmaen(channel, false);
316 });
317
318 Ok(())
319 }
320}
321
322impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
323 /// Obtain DAC CH2
324 pub fn new(
325 _peri: impl Peripheral<P = T> + 'd,
326 dma: impl Peripheral<P = Tx> + 'd,
327 _pin: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
328 ) -> Self {
329 into_ref!(_peri, dma);
330 T::enable();
331 T::reset();
332
333 let mut dac = Self {
334 phantom: PhantomData,
335 dma,
336 };
337
338 // Configure each activated channel. All results can be `unwrap`ed since they
339 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
340 #[cfg(dac_v2)]
341 dac.set_channel_mode(0).unwrap();
342 dac.enable_channel().unwrap();
343 dac.set_trigger_enable(true).unwrap();
344
345 dac
346 }
347
348 /// Select a new trigger for this channel
349 pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
350 unwrap!(self.disable_channel());
351 T::regs().cr().modify(|reg| {
352 reg.set_tsel2(trigger.tsel());
353 });
354 Ok(())
355 }
356
357 /// Write `data` to the DAC CH2 via DMA.
358 ///
359 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
360 /// This will configure a circular DMA transfer that periodically outputs the `data`.
361 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
362 ///
363 /// **Important:** Channel 2 has to be configured for the DAC instance!
364 #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
365 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
366 where
367 Tx: DmaCh2<T>,
368 {
369 let channel = Channel::Ch2.index();
370 debug!("Writing to channel {}", channel);
371
372 // Enable DAC and DMA
373 T::regs().cr().modify(|w| {
374 w.set_en(channel, true);
375 w.set_dmaen(channel, true);
376 });
377
378 let tx_request = self.dma.request();
379 let dma_channel = &self.dma;
380
381 let tx_options = crate::dma::TransferOptions {
382 circular,
383 half_transfer_ir: false,
384 complete_transfer_ir: !circular,
385 ..Default::default()
386 };
387
388 // Initiate the correct type of DMA transfer depending on what data is passed
389 let tx_f = match data {
390 ValueArray::Bit8(buf) => unsafe {
391 crate::dma::Transfer::new_write(
392 dma_channel,
393 tx_request,
394 buf,
395 T::regs().dhr8r(channel).as_ptr() as *mut u8,
396 tx_options,
397 )
398 },
399 ValueArray::Bit12Left(buf) => unsafe {
400 crate::dma::Transfer::new_write(
401 dma_channel,
402 tx_request,
403 buf,
404 T::regs().dhr12l(channel).as_ptr() as *mut u16,
405 tx_options,
406 )
407 },
408 ValueArray::Bit12Right(buf) => unsafe {
409 crate::dma::Transfer::new_write(
410 dma_channel,
411 tx_request,
412 buf,
413 T::regs().dhr12r(channel).as_ptr() as *mut u16,
414 tx_options,
415 )
416 },
417 };
418
419 tx_f.await;
420
421 // finish dma
422 // TODO: Do we need to check any status registers here?
423 T::regs().cr().modify(|w| {
424 // Disable the DAC peripheral
425 w.set_en(channel, false);
426 // Disable the DMA. TODO: Is this necessary?
427 w.set_dmaen(channel, false);
428 });
429
430 Ok(())
431 }
432}
433
434impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
435 /// Create a new DAC instance with both channels.
436 ///
437 /// This is used to obtain two independent channels via `split()` for use e.g. with DMA.
438 pub fn new(
439 peri: impl Peripheral<P = T> + 'd,
440 dma_ch1: impl Peripheral<P = TxCh1> + 'd,
441 dma_ch2: impl Peripheral<P = TxCh2> + 'd,
442 _pin_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
443 _pin_ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
444 ) -> Self {
445 into_ref!(peri, dma_ch1, dma_ch2);
446 T::enable();
447 T::reset();
448
449 let mut dac_ch1 = DacCh1 {
450 _peri: peri,
451 dma: dma_ch1,
452 };
453
454 let mut dac_ch2 = DacCh2 {
455 phantom: PhantomData,
456 dma: dma_ch2,
457 };
458
459 // Configure each activated channel. All results can be `unwrap`ed since they
460 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
461 #[cfg(dac_v2)]
462 dac_ch1.set_channel_mode(0).unwrap();
463 dac_ch1.enable_channel().unwrap();
464 dac_ch1.set_trigger_enable(true).unwrap();
465
466 #[cfg(dac_v2)]
467 dac_ch2.set_channel_mode(0).unwrap();
468 dac_ch2.enable_channel().unwrap();
469 dac_ch2.set_trigger_enable(true).unwrap();
470
471 Self {
472 ch1: dac_ch1,
473 ch2: dac_ch2,
474 }
475 }
476
477 /// Split the DAC into CH1 and CH2 for independent use.
478 pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) {
479 (self.ch1, self.ch2)
480 }
481
482 /// Get mutable reference to CH1
483 pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> {
484 &mut self.ch1
485 }
486
487 /// Get mutable reference to CH2
488 pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> {
489 &mut self.ch2
490 }
491
492 /// Get reference to CH1
493 pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> {
494 &self.ch1
495 }
496
497 /// Get reference to CH2
498 pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> {
499 &self.ch2
500 }
501}
502
503impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> {
504 const CHANNEL: Channel = Channel::Ch1;
505}
506
507impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> {
508 const CHANNEL: Channel = Channel::Ch2;
509}
510
511pub(crate) mod sealed {
512 pub trait Instance {
513 fn regs() -> &'static crate::pac::dac::Dac;
514 }
515}
516
517pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
518dma_trait!(DmaCh1, Instance);
519dma_trait!(DmaCh2, Instance);
520
521/// Marks a pin that can be used with the DAC
522pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
523
524foreach_peripheral!(
525 (dac, $inst:ident) => {
526 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
527 #[cfg(rcc_h7)]
528 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
529 fn frequency() -> crate::time::Hertz {
530 critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
531 }
532
533 fn reset() {
534 critical_section::with(|_| {
535 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
536 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
537 })
538 }
539
540 fn enable() {
541 critical_section::with(|_| {
542 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
543 })
544 }
545
546 fn disable() {
547 critical_section::with(|_| {
548 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
549 })
550 }
551 }
552
553 #[cfg(rcc_h7)]
554 impl crate::rcc::RccPeripheral for peripherals::$inst {}
555
556 impl crate::dac::sealed::Instance for peripherals::$inst {
557 fn regs() -> &'static crate::pac::dac::Dac {
558 &crate::pac::$inst
559 }
560 }
561
562 impl crate::dac::Instance for peripherals::$inst {}
563 };
564);
565
566macro_rules! impl_dac_pin {
567 ($inst:ident, $pin:ident, $ch:expr) => {
568 impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
569 };
570}
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index c13915a1b..78b026cb6 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -8,7 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
8use crate::dma::Transfer; 8use crate::dma::Transfer;
9use crate::gpio::sealed::AFType; 9use crate::gpio::sealed::AFType;
10use crate::gpio::Speed; 10use crate::gpio::Speed;
11use crate::interrupt::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, Peripheral}; 12use crate::{interrupt, Peripheral};
13 13
14/// Interrupt handler. 14/// Interrupt handler.
@@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> {
16 _phantom: PhantomData<T>, 16 _phantom: PhantomData<T>,
17} 17}
18 18
19impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 19impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
20 unsafe fn on_interrupt() { 20 unsafe fn on_interrupt() {
21 let ris = crate::pac::DCMI.ris().read(); 21 let ris = crate::pac::DCMI.ris().read();
22 if ris.err_ris() { 22 if ris.err_ris() {
@@ -96,8 +96,7 @@ impl Default for Config {
96macro_rules! config_pins { 96macro_rules! config_pins {
97 ($($pin:ident),*) => { 97 ($($pin:ident),*) => {
98 into_ref!($($pin),*); 98 into_ref!($($pin),*);
99 // NOTE(unsafe) Exclusive access to the registers 99 critical_section::with(|_| {
100 critical_section::with(|_| unsafe {
101 $( 100 $(
102 $pin.set_as_af($pin.af_num(), AFType::Input); 101 $pin.set_as_af($pin.af_num(), AFType::Input);
103 $pin.set_speed(Speed::VeryHigh); 102 $pin.set_speed(Speed::VeryHigh);
@@ -119,7 +118,7 @@ where
119 pub fn new_8bit( 118 pub fn new_8bit(
120 peri: impl Peripheral<P = T> + 'd, 119 peri: impl Peripheral<P = T> + 'd,
121 dma: impl Peripheral<P = Dma> + 'd, 120 dma: impl Peripheral<P = Dma> + 'd,
122 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 121 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
123 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 122 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
124 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 123 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
125 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 124 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -143,7 +142,7 @@ where
143 pub fn new_10bit( 142 pub fn new_10bit(
144 peri: impl Peripheral<P = T> + 'd, 143 peri: impl Peripheral<P = T> + 'd,
145 dma: impl Peripheral<P = Dma> + 'd, 144 dma: impl Peripheral<P = Dma> + 'd,
146 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 145 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
147 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 146 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
148 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 147 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
149 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 148 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -169,7 +168,7 @@ where
169 pub fn new_12bit( 168 pub fn new_12bit(
170 peri: impl Peripheral<P = T> + 'd, 169 peri: impl Peripheral<P = T> + 'd,
171 dma: impl Peripheral<P = Dma> + 'd, 170 dma: impl Peripheral<P = Dma> + 'd,
172 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 171 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
173 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 172 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
174 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 173 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
175 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 174 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -197,7 +196,7 @@ where
197 pub fn new_14bit( 196 pub fn new_14bit(
198 peri: impl Peripheral<P = T> + 'd, 197 peri: impl Peripheral<P = T> + 'd,
199 dma: impl Peripheral<P = Dma> + 'd, 198 dma: impl Peripheral<P = Dma> + 'd,
200 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 199 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
201 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 200 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
202 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 201 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
203 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 202 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -227,7 +226,7 @@ where
227 pub fn new_es_8bit( 226 pub fn new_es_8bit(
228 peri: impl Peripheral<P = T> + 'd, 227 peri: impl Peripheral<P = T> + 'd,
229 dma: impl Peripheral<P = Dma> + 'd, 228 dma: impl Peripheral<P = Dma> + 'd,
230 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 229 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
231 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 230 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
232 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 231 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
233 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 232 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -249,7 +248,7 @@ where
249 pub fn new_es_10bit( 248 pub fn new_es_10bit(
250 peri: impl Peripheral<P = T> + 'd, 249 peri: impl Peripheral<P = T> + 'd,
251 dma: impl Peripheral<P = Dma> + 'd, 250 dma: impl Peripheral<P = Dma> + 'd,
252 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 251 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
253 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 252 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
254 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 253 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
255 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 254 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -273,7 +272,7 @@ where
273 pub fn new_es_12bit( 272 pub fn new_es_12bit(
274 peri: impl Peripheral<P = T> + 'd, 273 peri: impl Peripheral<P = T> + 'd,
275 dma: impl Peripheral<P = Dma> + 'd, 274 dma: impl Peripheral<P = Dma> + 'd,
276 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 275 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
277 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 276 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
278 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 277 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
279 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 278 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -299,7 +298,7 @@ where
299 pub fn new_es_14bit( 298 pub fn new_es_14bit(
300 peri: impl Peripheral<P = T> + 'd, 299 peri: impl Peripheral<P = T> + 'd,
301 dma: impl Peripheral<P = Dma> + 'd, 300 dma: impl Peripheral<P = Dma> + 'd,
302 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 301 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
303 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 302 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
304 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 303 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
305 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 304 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@@ -334,17 +333,15 @@ where
334 T::reset(); 333 T::reset();
335 T::enable(); 334 T::enable();
336 335
337 unsafe { 336 peri.regs().cr().modify(|r| {
338 peri.regs().cr().modify(|r| { 337 r.set_cm(true); // disable continuous mode (snapshot mode)
339 r.set_cm(true); // disable continuous mode (snapshot mode) 338 r.set_ess(use_embedded_synchronization);
340 r.set_ess(use_embedded_synchronization); 339 r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge);
341 r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge); 340 r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High);
342 r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High); 341 r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High);
343 r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High); 342 r.set_fcrc(0x00); // capture every frame
344 r.set_fcrc(0x00); // capture every frame 343 r.set_edm(edm); // extended data mode
345 r.set_edm(edm); // extended data mode 344 });
346 });
347 }
348 345
349 T::Interrupt::unpend(); 346 T::Interrupt::unpend();
350 unsafe { T::Interrupt::enable() }; 347 unsafe { T::Interrupt::enable() };
@@ -352,7 +349,7 @@ where
352 Self { inner: peri, dma } 349 Self { inner: peri, dma }
353 } 350 }
354 351
355 unsafe fn toggle(enable: bool) { 352 fn toggle(enable: bool) {
356 crate::pac::DCMI.cr().modify(|r| { 353 crate::pac::DCMI.cr().modify(|r| {
357 r.set_enable(enable); 354 r.set_enable(enable);
358 r.set_capture(enable); 355 r.set_capture(enable);
@@ -360,23 +357,19 @@ where
360 } 357 }
361 358
362 fn enable_irqs() { 359 fn enable_irqs() {
363 unsafe { 360 crate::pac::DCMI.ier().modify(|r| {
364 crate::pac::DCMI.ier().modify(|r| { 361 r.set_err_ie(true);
365 r.set_err_ie(true); 362 r.set_ovr_ie(true);
366 r.set_ovr_ie(true); 363 r.set_frame_ie(true);
367 r.set_frame_ie(true); 364 });
368 });
369 }
370 } 365 }
371 366
372 fn clear_interrupt_flags() { 367 fn clear_interrupt_flags() {
373 unsafe { 368 crate::pac::DCMI.icr().write(|r| {
374 crate::pac::DCMI.icr().write(|r| { 369 r.set_ovr_isc(true);
375 r.set_ovr_isc(true); 370 r.set_err_isc(true);
376 r.set_err_isc(true); 371 r.set_frame_isc(true);
377 r.set_frame_isc(true); 372 })
378 })
379 }
380 } 373 }
381 374
382 /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer. 375 /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer.
@@ -392,41 +385,30 @@ where
392 return self.capture_giant(buffer).await; 385 return self.capture_giant(buffer).await;
393 } 386 }
394 } 387 }
388
395 async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { 389 async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
396 let r = self.inner.regs(); 390 let r = self.inner.regs();
397 let src = r.dr().ptr() as *mut u32; 391 let src = r.dr().as_ptr() as *mut u32;
398 let request = self.dma.request(); 392 let request = self.dma.request();
399 let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; 393 let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) };
400 394
401 Self::clear_interrupt_flags(); 395 Self::clear_interrupt_flags();
402 Self::enable_irqs(); 396 Self::enable_irqs();
403 397
404 unsafe { Self::toggle(true) }; 398 Self::toggle(true);
405 399
406 let result = poll_fn(|cx| { 400 let result = poll_fn(|cx| {
407 STATE.waker.register(cx.waker()); 401 STATE.waker.register(cx.waker());
408 402
409 let ris = unsafe { crate::pac::DCMI.ris().read() }; 403 let ris = crate::pac::DCMI.ris().read();
410 if ris.err_ris() { 404 if ris.err_ris() {
411 unsafe { 405 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
412 crate::pac::DCMI.icr().write(|r| {
413 r.set_err_isc(true);
414 })
415 };
416 Poll::Ready(Err(Error::PeripheralError)) 406 Poll::Ready(Err(Error::PeripheralError))
417 } else if ris.ovr_ris() { 407 } else if ris.ovr_ris() {
418 unsafe { 408 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
419 crate::pac::DCMI.icr().write(|r| {
420 r.set_ovr_isc(true);
421 })
422 };
423 Poll::Ready(Err(Error::Overrun)) 409 Poll::Ready(Err(Error::Overrun))
424 } else if ris.frame_ris() { 410 } else if ris.frame_ris() {
425 unsafe { 411 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
426 crate::pac::DCMI.icr().write(|r| {
427 r.set_frame_isc(true);
428 })
429 };
430 Poll::Ready(Ok(())) 412 Poll::Ready(Ok(()))
431 } else { 413 } else {
432 Poll::Pending 414 Poll::Pending
@@ -435,7 +417,7 @@ where
435 417
436 let (_, result) = embassy_futures::join::join(dma_read, result).await; 418 let (_, result) = embassy_futures::join::join(dma_read, result).await;
437 419
438 unsafe { Self::toggle(false) }; 420 Self::toggle(false);
439 421
440 result 422 result
441 } 423 }
@@ -468,7 +450,7 @@ where
468 let request = channel.request(); 450 let request = channel.request();
469 451
470 let r = self.inner.regs(); 452 let r = self.inner.regs();
471 let src = r.dr().ptr() as *mut u32; 453 let src = r.dr().as_ptr() as *mut u32;
472 454
473 let mut transfer = unsafe { 455 let mut transfer = unsafe {
474 crate::dma::DoubleBuffered::new_read( 456 crate::dma::DoubleBuffered::new_read(
@@ -526,38 +508,26 @@ where
526 let result = poll_fn(|cx| { 508 let result = poll_fn(|cx| {
527 STATE.waker.register(cx.waker()); 509 STATE.waker.register(cx.waker());
528 510
529 let ris = unsafe { crate::pac::DCMI.ris().read() }; 511 let ris = crate::pac::DCMI.ris().read();
530 if ris.err_ris() { 512 if ris.err_ris() {
531 unsafe { 513 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
532 crate::pac::DCMI.icr().write(|r| {
533 r.set_err_isc(true);
534 })
535 };
536 Poll::Ready(Err(Error::PeripheralError)) 514 Poll::Ready(Err(Error::PeripheralError))
537 } else if ris.ovr_ris() { 515 } else if ris.ovr_ris() {
538 unsafe { 516 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
539 crate::pac::DCMI.icr().write(|r| {
540 r.set_ovr_isc(true);
541 })
542 };
543 Poll::Ready(Err(Error::Overrun)) 517 Poll::Ready(Err(Error::Overrun))
544 } else if ris.frame_ris() { 518 } else if ris.frame_ris() {
545 unsafe { 519 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
546 crate::pac::DCMI.icr().write(|r| {
547 r.set_frame_isc(true);
548 })
549 };
550 Poll::Ready(Ok(())) 520 Poll::Ready(Ok(()))
551 } else { 521 } else {
552 Poll::Pending 522 Poll::Pending
553 } 523 }
554 }); 524 });
555 525
556 unsafe { Self::toggle(true) }; 526 Self::toggle(true);
557 527
558 let (_, result) = embassy_futures::join::join(dma_result, result).await; 528 let (_, result) = embassy_futures::join::join(dma_result, result).await;
559 529
560 unsafe { Self::toggle(false) }; 530 Self::toggle(false);
561 531
562 result 532 result
563 } 533 }
@@ -570,7 +540,7 @@ mod sealed {
570} 540}
571 541
572pub trait Instance: sealed::Instance + 'static { 542pub trait Instance: sealed::Instance + 'static {
573 type Interrupt: Interrupt; 543 type Interrupt: interrupt::typelevel::Interrupt;
574} 544}
575 545
576pin_trait!(D0Pin, Instance); 546pin_trait!(D0Pin, Instance);
@@ -602,7 +572,7 @@ macro_rules! impl_peripheral {
602 } 572 }
603 573
604 impl Instance for crate::peripherals::$inst { 574 impl Instance for crate::peripherals::$inst {
605 type Interrupt = crate::interrupt::$irq; 575 type Interrupt = crate::interrupt::typelevel::$irq;
606 } 576 }
607 }; 577 };
608} 578}
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 7a1ecda35..5a87888b7 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -6,7 +6,6 @@ use core::sync::atomic::{fence, Ordering};
6use core::task::{Context, Poll, Waker}; 6use core::task::{Context, Poll, Waker};
7 7
8use atomic_polyfill::AtomicUsize; 8use atomic_polyfill::AtomicUsize;
9use embassy_cortex_m::interrupt::Priority;
10use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
11use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
12 11
@@ -14,18 +13,30 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
14use super::word::{Word, WordSize}; 13use super::word::{Word, WordSize};
15use super::Dir; 14use super::Dir;
16use crate::_generated::BDMA_CHANNEL_COUNT; 15use crate::_generated::BDMA_CHANNEL_COUNT;
17use crate::interrupt::Interrupt; 16use crate::interrupt::typelevel::Interrupt;
17use crate::interrupt::Priority;
18use crate::pac; 18use crate::pac;
19use crate::pac::bdma::{regs, vals}; 19use crate::pac::bdma::{regs, vals};
20 20
21#[derive(Debug, Copy, Clone, PartialEq, Eq)] 21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))] 22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[non_exhaustive] 23#[non_exhaustive]
24pub struct TransferOptions {} 24pub struct TransferOptions {
25 /// Enable circular DMA
26 pub circular: bool,
27 /// Enable half transfer interrupt
28 pub half_transfer_ir: bool,
29 /// Enable transfer complete interrupt
30 pub complete_transfer_ir: bool,
31}
25 32
26impl Default for TransferOptions { 33impl Default for TransferOptions {
27 fn default() -> Self { 34 fn default() -> Self {
28 Self {} 35 Self {
36 circular: false,
37 half_transfer_ir: false,
38 complete_transfer_ir: true,
39 }
29 } 40 }
30} 41}
31 42
@@ -70,8 +81,8 @@ static STATE: State = State::new();
70pub(crate) unsafe fn init(irq_priority: Priority) { 81pub(crate) unsafe fn init(irq_priority: Priority) {
71 foreach_interrupt! { 82 foreach_interrupt! {
72 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { 83 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
73 crate::interrupt::$irq::set_priority(irq_priority); 84 crate::interrupt::typelevel::$irq::set_priority(irq_priority);
74 crate::interrupt::$irq::enable(); 85 crate::interrupt::typelevel::$irq::enable();
75 }; 86 };
76 } 87 }
77 crate::_generated::init_bdma(); 88 crate::_generated::init_bdma();
@@ -107,7 +118,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
107 let cr = dma.ch(channel_num).cr(); 118 let cr = dma.ch(channel_num).cr();
108 119
109 if isr.teif(channel_num) { 120 if isr.teif(channel_num) {
110 panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); 121 panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
111 } 122 }
112 123
113 if isr.htif(channel_num) && cr.read().htie() { 124 if isr.htif(channel_num) && cr.read().htie() {
@@ -253,7 +264,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
253 mem_len: usize, 264 mem_len: usize,
254 incr_mem: bool, 265 incr_mem: bool,
255 data_size: WordSize, 266 data_size: WordSize,
256 _options: TransferOptions, 267 options: TransferOptions,
257 ) -> Self { 268 ) -> Self {
258 let ch = channel.regs().ch(channel.num()); 269 let ch = channel.regs().ch(channel.num());
259 270
@@ -283,7 +294,15 @@ impl<'a, C: Channel> Transfer<'a, C> {
283 } 294 }
284 w.set_dir(dir.into()); 295 w.set_dir(dir.into());
285 w.set_teie(true); 296 w.set_teie(true);
286 w.set_tcie(true); 297 w.set_tcie(options.complete_transfer_ir);
298 w.set_htie(options.half_transfer_ir);
299 if options.circular {
300 w.set_circ(vals::Circ::ENABLED);
301 debug!("Setting circular mode");
302 } else {
303 w.set_circ(vals::Circ::DISABLED);
304 }
305 w.set_pl(vals::Pl::VERYHIGH);
287 w.set_en(true); 306 w.set_en(true);
288 }); 307 });
289 308
@@ -291,42 +310,40 @@ impl<'a, C: Channel> Transfer<'a, C> {
291 } 310 }
292 311
293 fn clear_irqs(&mut self) { 312 fn clear_irqs(&mut self) {
294 unsafe { 313 self.channel.regs().ifcr().write(|w| {
295 self.channel.regs().ifcr().write(|w| { 314 w.set_tcif(self.channel.num(), true);
296 w.set_tcif(self.channel.num(), true); 315 w.set_teif(self.channel.num(), true);
297 w.set_teif(self.channel.num(), true); 316 });
298 })
299 }
300 } 317 }
301 318
302 pub fn request_stop(&mut self) { 319 pub fn request_stop(&mut self) {
303 let ch = self.channel.regs().ch(self.channel.num()); 320 let ch = self.channel.regs().ch(self.channel.num());
304 321
305 // Disable the channel. Keep the IEs enabled so the irqs still fire. 322 // Disable the channel. Keep the IEs enabled so the irqs still fire.
306 unsafe { 323 ch.cr().write(|w| {
307 ch.cr().write(|w| { 324 w.set_teie(true);
308 w.set_teie(true); 325 w.set_tcie(true);
309 w.set_tcie(true); 326 });
310 })
311 }
312 } 327 }
313 328
314 pub fn is_running(&mut self) -> bool { 329 pub fn is_running(&mut self) -> bool {
315 let ch = self.channel.regs().ch(self.channel.num()); 330 let ch = self.channel.regs().ch(self.channel.num());
316 let en = unsafe { ch.cr().read() }.en(); 331 let en = ch.cr().read().en();
332 let circular = ch.cr().read().circ() == vals::Circ::ENABLED;
317 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; 333 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
318 en && !tcif 334 en && (circular || !tcif)
319 } 335 }
320 336
321 /// Gets the total remaining transfers for the channel 337 /// Gets the total remaining transfers for the channel
322 /// Note: this will be zero for transfers that completed without cancellation. 338 /// Note: this will be zero for transfers that completed without cancellation.
323 pub fn get_remaining_transfers(&self) -> u16 { 339 pub fn get_remaining_transfers(&self) -> u16 {
324 let ch = self.channel.regs().ch(self.channel.num()); 340 let ch = self.channel.regs().ch(self.channel.num());
325 unsafe { ch.ndtr().read() }.ndt() 341 ch.ndtr().read().ndt()
326 } 342 }
327 343
328 pub fn blocking_wait(mut self) { 344 pub fn blocking_wait(mut self) {
329 while self.is_running() {} 345 while self.is_running() {}
346 self.request_stop();
330 347
331 // "Subsequent reads and writes cannot be moved ahead of preceding reads." 348 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
332 fence(Ordering::SeqCst); 349 fence(Ordering::SeqCst);
@@ -366,7 +383,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
366impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { 383impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
367 fn get_remaining_transfers(&self) -> usize { 384 fn get_remaining_transfers(&self) -> usize {
368 let ch = self.0.regs().ch(self.0.num()); 385 let ch = self.0.regs().ch(self.0.num());
369 unsafe { ch.ndtr().read() }.ndt() as usize 386 ch.ndtr().read().ndt() as usize
370 } 387 }
371 388
372 fn get_complete_count(&self) -> usize { 389 fn get_complete_count(&self) -> usize {
@@ -442,7 +459,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
442 459
443 pub fn start(&mut self) { 460 pub fn start(&mut self) {
444 let ch = self.channel.regs().ch(self.channel.num()); 461 let ch = self.channel.regs().ch(self.channel.num());
445 unsafe { ch.cr().write_value(self.cr) } 462 ch.cr().write_value(self.cr)
446 } 463 }
447 464
448 pub fn clear(&mut self) { 465 pub fn clear(&mut self) {
@@ -469,31 +486,29 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
469 486
470 fn clear_irqs(&mut self) { 487 fn clear_irqs(&mut self) {
471 let dma = self.channel.regs(); 488 let dma = self.channel.regs();
472 unsafe { 489 dma.ifcr().write(|w| {
473 dma.ifcr().write(|w| { 490 w.set_htif(self.channel.num(), true);
474 w.set_htif(self.channel.num(), true); 491 w.set_tcif(self.channel.num(), true);
475 w.set_tcif(self.channel.num(), true); 492 w.set_teif(self.channel.num(), true);
476 w.set_teif(self.channel.num(), true); 493 });
477 })
478 }
479 } 494 }
480 495
481 pub fn request_stop(&mut self) { 496 pub fn request_stop(&mut self) {
482 let ch = self.channel.regs().ch(self.channel.num()); 497 let ch = self.channel.regs().ch(self.channel.num());
483 498
484 // Disable the channel. Keep the IEs enabled so the irqs still fire. 499 // Disable the channel. Keep the IEs enabled so the irqs still fire.
485 unsafe { 500 // If the channel is enabled and transfer is not completed, we need to perform
486 ch.cr().write(|w| { 501 // two separate write access to the CR register to disable the channel.
487 w.set_teie(true); 502 ch.cr().write(|w| {
488 w.set_htie(true); 503 w.set_teie(true);
489 w.set_tcie(true); 504 w.set_htie(true);
490 }) 505 w.set_tcie(true);
491 } 506 });
492 } 507 }
493 508
494 pub fn is_running(&mut self) -> bool { 509 pub fn is_running(&mut self) -> bool {
495 let ch = self.channel.regs().ch(self.channel.num()); 510 let ch = self.channel.regs().ch(self.channel.num());
496 unsafe { ch.cr().read() }.en() 511 ch.cr().read().en()
497 } 512 }
498} 513}
499 514
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 3b602b991..8abe541d3 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -5,7 +5,6 @@ use core::sync::atomic::{fence, Ordering};
5use core::task::{Context, Poll, Waker}; 5use core::task::{Context, Poll, Waker};
6 6
7use atomic_polyfill::AtomicUsize; 7use atomic_polyfill::AtomicUsize;
8use embassy_cortex_m::interrupt::Priority;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
11 10
@@ -13,7 +12,8 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
13use super::word::{Word, WordSize}; 12use super::word::{Word, WordSize};
14use super::Dir; 13use super::Dir;
15use crate::_generated::DMA_CHANNEL_COUNT; 14use crate::_generated::DMA_CHANNEL_COUNT;
16use crate::interrupt::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
16use crate::interrupt::Priority;
17use crate::pac::dma::{regs, vals}; 17use crate::pac::dma::{regs, vals};
18use crate::{interrupt, pac}; 18use crate::{interrupt, pac};
19 19
@@ -149,8 +149,8 @@ static STATE: State = State::new();
149pub(crate) unsafe fn init(irq_priority: Priority) { 149pub(crate) unsafe fn init(irq_priority: Priority) {
150 foreach_interrupt! { 150 foreach_interrupt! {
151 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { 151 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
152 interrupt::$irq::set_priority(irq_priority); 152 interrupt::typelevel::$irq::set_priority(irq_priority);
153 interrupt::$irq::enable(); 153 interrupt::typelevel::$irq::enable();
154 }; 154 };
155 } 155 }
156 crate::_generated::init_dma(); 156 crate::_generated::init_dma();
@@ -183,7 +183,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
183 let isr = dma.isr(channel_num / 4).read(); 183 let isr = dma.isr(channel_num / 4).read();
184 184
185 if isr.teif(channel_num % 4) { 185 if isr.teif(channel_num % 4) {
186 panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num); 186 panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
187 } 187 }
188 188
189 if isr.htif(channel_num % 4) && cr.read().htie() { 189 if isr.htif(channel_num % 4) && cr.read().htie() {
@@ -387,36 +387,32 @@ impl<'a, C: Channel> Transfer<'a, C> {
387 let isrn = self.channel.num() / 4; 387 let isrn = self.channel.num() / 4;
388 let isrbit = self.channel.num() % 4; 388 let isrbit = self.channel.num() % 4;
389 389
390 unsafe { 390 self.channel.regs().ifcr(isrn).write(|w| {
391 self.channel.regs().ifcr(isrn).write(|w| { 391 w.set_tcif(isrbit, true);
392 w.set_tcif(isrbit, true); 392 w.set_teif(isrbit, true);
393 w.set_teif(isrbit, true); 393 });
394 })
395 }
396 } 394 }
397 395
398 pub fn request_stop(&mut self) { 396 pub fn request_stop(&mut self) {
399 let ch = self.channel.regs().st(self.channel.num()); 397 let ch = self.channel.regs().st(self.channel.num());
400 398
401 // Disable the channel. Keep the IEs enabled so the irqs still fire. 399 // Disable the channel. Keep the IEs enabled so the irqs still fire.
402 unsafe { 400 ch.cr().write(|w| {
403 ch.cr().write(|w| { 401 w.set_teie(true);
404 w.set_teie(true); 402 w.set_tcie(true);
405 w.set_tcie(true); 403 });
406 })
407 }
408 } 404 }
409 405
410 pub fn is_running(&mut self) -> bool { 406 pub fn is_running(&mut self) -> bool {
411 let ch = self.channel.regs().st(self.channel.num()); 407 let ch = self.channel.regs().st(self.channel.num());
412 unsafe { ch.cr().read() }.en() 408 ch.cr().read().en()
413 } 409 }
414 410
415 /// Gets the total remaining transfers for the channel 411 /// Gets the total remaining transfers for the channel
416 /// Note: this will be zero for transfers that completed without cancellation. 412 /// Note: this will be zero for transfers that completed without cancellation.
417 pub fn get_remaining_transfers(&self) -> u16 { 413 pub fn get_remaining_transfers(&self) -> u16 {
418 let ch = self.channel.regs().st(self.channel.num()); 414 let ch = self.channel.regs().st(self.channel.num());
419 unsafe { ch.ndtr().read() }.ndt() 415 ch.ndtr().read().ndt()
420 } 416 }
421 417
422 pub fn blocking_wait(mut self) { 418 pub fn blocking_wait(mut self) {
@@ -537,13 +533,11 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
537 let isrn = channel_number / 4; 533 let isrn = channel_number / 4;
538 let isrbit = channel_number % 4; 534 let isrbit = channel_number % 4;
539 535
540 unsafe { 536 dma.ifcr(isrn).write(|w| {
541 dma.ifcr(isrn).write(|w| { 537 w.set_htif(isrbit, true);
542 w.set_htif(isrbit, true); 538 w.set_tcif(isrbit, true);
543 w.set_tcif(isrbit, true); 539 w.set_teif(isrbit, true);
544 w.set_teif(isrbit, true); 540 });
545 })
546 }
547 } 541 }
548 542
549 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { 543 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
@@ -558,7 +552,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
558 552
559 pub fn is_buffer0_accessible(&mut self) -> bool { 553 pub fn is_buffer0_accessible(&mut self) -> bool {
560 let ch = self.channel.regs().st(self.channel.num()); 554 let ch = self.channel.regs().st(self.channel.num());
561 unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1 555 ch.cr().read().ct() == vals::Ct::MEMORY1
562 } 556 }
563 557
564 pub fn set_waker(&mut self, waker: &Waker) { 558 pub fn set_waker(&mut self, waker: &Waker) {
@@ -569,24 +563,22 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
569 let ch = self.channel.regs().st(self.channel.num()); 563 let ch = self.channel.regs().st(self.channel.num());
570 564
571 // Disable the channel. Keep the IEs enabled so the irqs still fire. 565 // Disable the channel. Keep the IEs enabled so the irqs still fire.
572 unsafe { 566 ch.cr().write(|w| {
573 ch.cr().write(|w| { 567 w.set_teie(true);
574 w.set_teie(true); 568 w.set_tcie(true);
575 w.set_tcie(true); 569 });
576 })
577 }
578 } 570 }
579 571
580 pub fn is_running(&mut self) -> bool { 572 pub fn is_running(&mut self) -> bool {
581 let ch = self.channel.regs().st(self.channel.num()); 573 let ch = self.channel.regs().st(self.channel.num());
582 unsafe { ch.cr().read() }.en() 574 ch.cr().read().en()
583 } 575 }
584 576
585 /// Gets the total remaining transfers for the channel 577 /// Gets the total remaining transfers for the channel
586 /// Note: this will be zero for transfers that completed without cancellation. 578 /// Note: this will be zero for transfers that completed without cancellation.
587 pub fn get_remaining_transfers(&self) -> u16 { 579 pub fn get_remaining_transfers(&self) -> u16 {
588 let ch = self.channel.regs().st(self.channel.num()); 580 let ch = self.channel.regs().st(self.channel.num());
589 unsafe { ch.ndtr().read() }.ndt() 581 ch.ndtr().read().ndt()
590 } 582 }
591} 583}
592 584
@@ -607,7 +599,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
607impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { 599impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
608 fn get_remaining_transfers(&self) -> usize { 600 fn get_remaining_transfers(&self) -> usize {
609 let ch = self.0.regs().st(self.0.num()); 601 let ch = self.0.regs().st(self.0.num());
610 unsafe { ch.ndtr().read() }.ndt() as usize 602 ch.ndtr().read().ndt() as usize
611 } 603 }
612 604
613 fn get_complete_count(&self) -> usize { 605 fn get_complete_count(&self) -> usize {
@@ -698,7 +690,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
698 690
699 pub fn start(&mut self) { 691 pub fn start(&mut self) {
700 let ch = self.channel.regs().st(self.channel.num()); 692 let ch = self.channel.regs().st(self.channel.num());
701 unsafe { ch.cr().write_value(self.cr) } 693 ch.cr().write_value(self.cr);
702 } 694 }
703 695
704 pub fn clear(&mut self) { 696 pub fn clear(&mut self) {
@@ -729,31 +721,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
729 let isrn = channel_number / 4; 721 let isrn = channel_number / 4;
730 let isrbit = channel_number % 4; 722 let isrbit = channel_number % 4;
731 723
732 unsafe { 724 dma.ifcr(isrn).write(|w| {
733 dma.ifcr(isrn).write(|w| { 725 w.set_htif(isrbit, true);
734 w.set_htif(isrbit, true); 726 w.set_tcif(isrbit, true);
735 w.set_tcif(isrbit, true); 727 w.set_teif(isrbit, true);
736 w.set_teif(isrbit, true); 728 });
737 })
738 }
739 } 729 }
740 730
741 pub fn request_stop(&mut self) { 731 pub fn request_stop(&mut self) {
742 let ch = self.channel.regs().st(self.channel.num()); 732 let ch = self.channel.regs().st(self.channel.num());
743 733
744 // Disable the channel. Keep the IEs enabled so the irqs still fire. 734 // Disable the channel. Keep the IEs enabled so the irqs still fire.
745 unsafe { 735 ch.cr().write(|w| {
746 ch.cr().write(|w| { 736 w.set_teie(true);
747 w.set_teie(true); 737 w.set_htie(true);
748 w.set_htie(true); 738 w.set_tcie(true);
749 w.set_tcie(true); 739 });
750 })
751 }
752 } 740 }
753 741
754 pub fn is_running(&mut self) -> bool { 742 pub fn is_running(&mut self) -> bool {
755 let ch = self.channel.regs().st(self.channel.num()); 743 let ch = self.channel.regs().st(self.channel.num());
756 unsafe { ch.cr().read() }.en() 744 ch.cr().read().en()
757 } 745 }
758} 746}
759 747
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
index a8c4c5827..36fc03403 100644
--- a/embassy-stm32/src/dma/dmamux.rs
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -2,7 +2,7 @@
2 2
3use crate::{pac, peripherals}; 3use crate::{pac, peripherals};
4 4
5pub(crate) unsafe fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { 5pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) {
6 let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); 6 let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num());
7 ch_mux_regs.write(|reg| { 7 ch_mux_regs.write(|reg| {
8 reg.set_nbreq(0); 8 reg.set_nbreq(0);
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index 7f8b82b46..b7bcf7795 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -5,14 +5,14 @@ use core::pin::Pin;
5use core::sync::atomic::{fence, Ordering}; 5use core::sync::atomic::{fence, Ordering};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_cortex_m::interrupt::Priority;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
11 10
12use super::word::{Word, WordSize}; 11use super::word::{Word, WordSize};
13use super::Dir; 12use super::Dir;
14use crate::_generated::GPDMA_CHANNEL_COUNT; 13use crate::_generated::GPDMA_CHANNEL_COUNT;
15use crate::interrupt::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::interrupt::Priority;
16use crate::pac; 16use crate::pac;
17use crate::pac::gpdma::vals; 17use crate::pac::gpdma::vals;
18 18
@@ -56,8 +56,8 @@ static STATE: State = State::new();
56pub(crate) unsafe fn init(irq_priority: Priority) { 56pub(crate) unsafe fn init(irq_priority: Priority) {
57 foreach_interrupt! { 57 foreach_interrupt! {
58 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { 58 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
59 crate::interrupt::$irq::set_priority(irq_priority); 59 crate::interrupt::typelevel::$irq::set_priority(irq_priority);
60 crate::interrupt::$irq::enable(); 60 crate::interrupt::typelevel::$irq::enable();
61 }; 61 };
62 } 62 }
63 crate::_generated::init_gpdma(); 63 crate::_generated::init_gpdma();
@@ -92,13 +92,15 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
92 if sr.dtef() { 92 if sr.dtef() {
93 panic!( 93 panic!(
94 "DMA: data transfer error on DMA@{:08x} channel {}", 94 "DMA: data transfer error on DMA@{:08x} channel {}",
95 dma.0 as u32, channel_num 95 dma.as_ptr() as u32,
96 channel_num
96 ); 97 );
97 } 98 }
98 if sr.usef() { 99 if sr.usef() {
99 panic!( 100 panic!(
100 "DMA: user settings error on DMA@{:08x} channel {}", 101 "DMA: user settings error on DMA@{:08x} channel {}",
101 dma.0 as u32, channel_num 102 dma.as_ptr() as u32,
103 channel_num
102 ); 104 );
103 } 105 }
104 106
@@ -250,6 +252,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
250 super::dmamux::configure_dmamux(&mut *this.channel, request); 252 super::dmamux::configure_dmamux(&mut *this.channel, request);
251 253
252 ch.cr().write(|w| w.set_reset(true)); 254 ch.cr().write(|w| w.set_reset(true));
255 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs
253 ch.llr().write(|_| {}); // no linked list 256 ch.llr().write(|_| {}); // no linked list
254 ch.tr1().write(|w| { 257 ch.tr1().write(|w| {
255 w.set_sdw(data_size.into()); 258 w.set_sdw(data_size.into());
@@ -298,26 +301,24 @@ impl<'a, C: Channel> Transfer<'a, C> {
298 let ch = self.channel.regs().ch(self.channel.num()); 301 let ch = self.channel.regs().ch(self.channel.num());
299 302
300 // Disable the channel. Keep the IEs enabled so the irqs still fire. 303 // Disable the channel. Keep the IEs enabled so the irqs still fire.
301 unsafe { 304 ch.cr().write(|w| {
302 ch.cr().write(|w| { 305 w.set_tcie(true);
303 w.set_tcie(true); 306 w.set_useie(true);
304 w.set_useie(true); 307 w.set_dteie(true);
305 w.set_dteie(true); 308 w.set_suspie(true);
306 w.set_suspie(true); 309 })
307 })
308 }
309 } 310 }
310 311
311 pub fn is_running(&mut self) -> bool { 312 pub fn is_running(&mut self) -> bool {
312 let ch = self.channel.regs().ch(self.channel.num()); 313 let ch = self.channel.regs().ch(self.channel.num());
313 !unsafe { ch.sr().read() }.tcf() 314 !ch.sr().read().tcf()
314 } 315 }
315 316
316 /// Gets the total remaining transfers for the channel 317 /// Gets the total remaining transfers for the channel
317 /// Note: this will be zero for transfers that completed without cancellation. 318 /// Note: this will be zero for transfers that completed without cancellation.
318 pub fn get_remaining_transfers(&self) -> u16 { 319 pub fn get_remaining_transfers(&self) -> u16 {
319 let ch = self.channel.regs().ch(self.channel.num()); 320 let ch = self.channel.regs().ch(self.channel.num());
320 unsafe { ch.br1().read() }.bndt() 321 ch.br1().read().bndt()
321 } 322 }
322 323
323 pub fn blocking_wait(mut self) { 324 pub fn blocking_wait(mut self) {
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 3ac0d1b3d..0858587bd 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -26,11 +26,11 @@ pub mod word;
26 26
27use core::mem; 27use core::mem;
28 28
29use embassy_cortex_m::interrupt::Priority;
30use embassy_hal_common::impl_peripheral; 29use embassy_hal_common::impl_peripheral;
31 30
32#[cfg(dmamux)] 31#[cfg(dmamux)]
33pub use self::dmamux::*; 32pub use self::dmamux::*;
33use crate::interrupt::Priority;
34 34
35#[derive(Debug, Copy, Clone, PartialEq, Eq)] 35#[derive(Debug, Copy, Clone, PartialEq, Eq)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))] 36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index a5f1a268d..b53c2d0fa 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -5,7 +5,6 @@ mod tx_desc;
5 5
6use core::sync::atomic::{fence, Ordering}; 6use core::sync::atomic::{fence, Ordering};
7 7
8use embassy_cortex_m::interrupt::Interrupt;
9use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; 9use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
11 10
@@ -14,6 +13,7 @@ pub(crate) use self::tx_desc::{TDes, TDesRing};
14use super::*; 13use super::*;
15use crate::gpio::sealed::{AFType, Pin as __GpioPin}; 14use crate::gpio::sealed::{AFType, Pin as __GpioPin};
16use crate::gpio::AnyPin; 15use crate::gpio::AnyPin;
16use crate::interrupt::InterruptExt;
17#[cfg(eth_v1a)] 17#[cfg(eth_v1a)]
18use crate::pac::AFIO; 18use crate::pac::AFIO;
19#[cfg(any(eth_v1b, eth_v1c))] 19#[cfg(any(eth_v1b, eth_v1c))]
@@ -24,23 +24,21 @@ use crate::{interrupt, Peripheral};
24/// Interrupt handler. 24/// Interrupt handler.
25pub struct InterruptHandler {} 25pub struct InterruptHandler {}
26 26
27impl interrupt::Handler<interrupt::ETH> for InterruptHandler { 27impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler {
28 unsafe fn on_interrupt() { 28 unsafe fn on_interrupt() {
29 WAKER.wake(); 29 WAKER.wake();
30 30
31 // TODO: Check and clear more flags 31 // TODO: Check and clear more flags
32 unsafe { 32 let dma = ETH.ethernet_dma();
33 let dma = ETH.ethernet_dma(); 33
34 34 dma.dmasr().modify(|w| {
35 dma.dmasr().modify(|w| { 35 w.set_ts(true);
36 w.set_ts(true); 36 w.set_rs(true);
37 w.set_rs(true); 37 w.set_nis(true);
38 w.set_nis(true); 38 });
39 }); 39 // Delay two peripheral's clock
40 // Delay two peripheral's clock 40 dma.dmasr().read();
41 dma.dmasr().read(); 41 dma.dmasr().read();
42 dma.dmasr().read();
43 }
44 } 42 }
45} 43}
46 44
@@ -59,7 +57,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
59#[cfg(eth_v1a)] 57#[cfg(eth_v1a)]
60macro_rules! config_in_pins { 58macro_rules! config_in_pins {
61 ($($pin:ident),*) => { 59 ($($pin:ident),*) => {
62 // NOTE(unsafe) Exclusive access to the registers
63 critical_section::with(|_| { 60 critical_section::with(|_| {
64 $( 61 $(
65 // TODO properly create a set_as_input function 62 // TODO properly create a set_as_input function
@@ -72,7 +69,6 @@ macro_rules! config_in_pins {
72#[cfg(eth_v1a)] 69#[cfg(eth_v1a)]
73macro_rules! config_af_pins { 70macro_rules! config_af_pins {
74 ($($pin:ident),*) => { 71 ($($pin:ident),*) => {
75 // NOTE(unsafe) Exclusive access to the registers
76 critical_section::with(|_| { 72 critical_section::with(|_| {
77 $( 73 $(
78 // We are lucky here, this configures to max speed (50MHz) 74 // We are lucky here, this configures to max speed (50MHz)
@@ -85,7 +81,6 @@ macro_rules! config_af_pins {
85#[cfg(any(eth_v1b, eth_v1c))] 81#[cfg(any(eth_v1b, eth_v1c))]
86macro_rules! config_pins { 82macro_rules! config_pins {
87 ($($pin:ident),*) => { 83 ($($pin:ident),*) => {
88 // NOTE(unsafe) Exclusive access to the registers
89 critical_section::with(|_| { 84 critical_section::with(|_| {
90 $( 85 $(
91 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); 86 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
@@ -100,7 +95,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
100 pub fn new<const TX: usize, const RX: usize>( 95 pub fn new<const TX: usize, const RX: usize>(
101 queue: &'d mut PacketQueue<TX, RX>, 96 queue: &'d mut PacketQueue<TX, RX>,
102 peri: impl Peripheral<P = T> + 'd, 97 peri: impl Peripheral<P = T> + 'd,
103 _irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd, 98 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
104 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 99 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
105 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 100 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
106 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 101 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@@ -116,222 +111,208 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
116 ) -> Self { 111 ) -> Self {
117 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 112 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
118 113
119 unsafe { 114 // Enable the necessary Clocks
120 // Enable the necessary Clocks 115 #[cfg(eth_v1a)]
121 // NOTE(unsafe) We have exclusive access to the registers 116 critical_section::with(|_| {
122 #[cfg(eth_v1a)] 117 RCC.apb2enr().modify(|w| w.set_afioen(true));
123 critical_section::with(|_| {
124 RCC.apb2enr().modify(|w| w.set_afioen(true));
125
126 // Select RMII (Reduced Media Independent Interface)
127 // Must be done prior to enabling peripheral clock
128 AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true));
129
130 RCC.ahbenr().modify(|w| {
131 w.set_ethen(true);
132 w.set_ethtxen(true);
133 w.set_ethrxen(true);
134 });
135 });
136
137 #[cfg(any(eth_v1b, eth_v1c))]
138 critical_section::with(|_| {
139 RCC.apb2enr().modify(|w| w.set_syscfgen(true));
140 RCC.ahb1enr().modify(|w| {
141 w.set_ethen(true);
142 w.set_ethtxen(true);
143 w.set_ethrxen(true);
144 });
145
146 // RMII (Reduced Media Independent Interface)
147 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
148 });
149
150 #[cfg(eth_v1a)]
151 {
152 config_in_pins!(ref_clk, rx_d0, rx_d1);
153 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
154 }
155
156 #[cfg(any(eth_v1b, eth_v1c))]
157 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
158
159 // NOTE(unsafe) We have exclusive access to the registers
160 let dma = ETH.ethernet_dma();
161 let mac = ETH.ethernet_mac();
162
163 // Reset and wait
164 dma.dmabmr().modify(|w| w.set_sr(true));
165 while dma.dmabmr().read().sr() {}
166
167 mac.maccr().modify(|w| {
168 w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times
169 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
170 w.set_fes(Fes::FES100); // fast ethernet speed
171 w.set_dm(Dm::FULLDUPLEX); // full duplex
172 // TODO: Carrier sense ? ECRSFD
173 });
174
175 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
176 // so the LR write must happen after the HR write.
177 mac.maca0hr()
178 .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
179 mac.maca0lr().write(|w| {
180 w.set_maca0l(
181 u32::from(mac_addr[0])
182 | (u32::from(mac_addr[1]) << 8)
183 | (u32::from(mac_addr[2]) << 16)
184 | (u32::from(mac_addr[3]) << 24),
185 )
186 });
187
188 // pause time
189 mac.macfcr().modify(|w| w.set_pt(0x100));
190
191 // Transfer and Forward, Receive and Forward
192 dma.dmaomr().modify(|w| {
193 w.set_tsf(Tsf::STOREFORWARD);
194 w.set_rsf(Rsf::STOREFORWARD);
195 });
196 118
197 dma.dmabmr().modify(|w| { 119 // Select RMII (Reduced Media Independent Interface)
198 w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? 120 // Must be done prior to enabling peripheral clock
199 }); 121 AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true));
200 122
201 // TODO MTU size setting not found for v1 ethernet, check if correct 123 RCC.ahbenr().modify(|w| {
202 124 w.set_ethen(true);
203 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 125 w.set_ethtxen(true);
204 let hclk = crate::rcc::get_freqs().ahb1; 126 w.set_ethrxen(true);
205 let hclk_mhz = hclk.0 / 1_000_000;
206
207 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
208 let clock_range = match hclk_mhz {
209 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
210 25..=34 => Cr::CR_20_35, // Divide by 16
211 35..=59 => Cr::CR_35_60, // Divide by 26
212 60..=99 => Cr::CR_60_100, // Divide by 42
213 100..=149 => Cr::CR_100_150, // Divide by 62
214 150..=216 => Cr::CR_150_168, // Divide by 102
215 _ => {
216 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
217 }
218 };
219
220 let pins = [
221 ref_clk.map_into(),
222 mdio.map_into(),
223 mdc.map_into(),
224 crs.map_into(),
225 rx_d0.map_into(),
226 rx_d1.map_into(),
227 tx_d0.map_into(),
228 tx_d1.map_into(),
229 tx_en.map_into(),
230 ];
231
232 let mut this = Self {
233 _peri: peri,
234 pins,
235 _phy: phy,
236 clock_range,
237 phy_addr,
238 mac_addr,
239 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
240 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
241 };
242
243 fence(Ordering::SeqCst);
244
245 let mac = ETH.ethernet_mac();
246 let dma = ETH.ethernet_dma();
247
248 mac.maccr().modify(|w| {
249 w.set_re(true);
250 w.set_te(true);
251 });
252 dma.dmaomr().modify(|w| {
253 w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue)
254 w.set_st(St::STARTED); // start transmitting channel
255 w.set_sr(DmaomrSr::STARTED); // start receiving channel
256 }); 127 });
128 });
257 129
258 this.rx.demand_poll(); 130 #[cfg(any(eth_v1b, eth_v1c))]
259 131 critical_section::with(|_| {
260 // Enable interrupts 132 RCC.apb2enr().modify(|w| w.set_syscfgen(true));
261 dma.dmaier().modify(|w| { 133 RCC.ahb1enr().modify(|w| {
262 w.set_nise(true); 134 w.set_ethen(true);
263 w.set_rie(true); 135 w.set_ethtxen(true);
264 w.set_tie(true); 136 w.set_ethrxen(true);
265 }); 137 });
266 138
267 P::phy_reset(&mut this); 139 // RMII (Reduced Media Independent Interface)
268 P::phy_init(&mut this); 140 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
141 });
269 142
270 interrupt::ETH::unpend(); 143 #[cfg(eth_v1a)]
271 interrupt::ETH::enable(); 144 {
272 145 config_in_pins!(ref_clk, rx_d0, rx_d1);
273 this 146 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
274 } 147 }
148
149 #[cfg(any(eth_v1b, eth_v1c))]
150 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
151
152 let dma = ETH.ethernet_dma();
153 let mac = ETH.ethernet_mac();
154
155 // Reset and wait
156 dma.dmabmr().modify(|w| w.set_sr(true));
157 while dma.dmabmr().read().sr() {}
158
159 mac.maccr().modify(|w| {
160 w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times
161 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
162 w.set_fes(Fes::FES100); // fast ethernet speed
163 w.set_dm(Dm::FULLDUPLEX); // full duplex
164 // TODO: Carrier sense ? ECRSFD
165 });
166
167 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
168 // so the LR write must happen after the HR write.
169 mac.maca0hr()
170 .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
171 mac.maca0lr().write(|w| {
172 w.set_maca0l(
173 u32::from(mac_addr[0])
174 | (u32::from(mac_addr[1]) << 8)
175 | (u32::from(mac_addr[2]) << 16)
176 | (u32::from(mac_addr[3]) << 24),
177 )
178 });
179
180 // pause time
181 mac.macfcr().modify(|w| w.set_pt(0x100));
182
183 // Transfer and Forward, Receive and Forward
184 dma.dmaomr().modify(|w| {
185 w.set_tsf(Tsf::STOREFORWARD);
186 w.set_rsf(Rsf::STOREFORWARD);
187 });
188
189 dma.dmabmr().modify(|w| {
190 w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ?
191 });
192
193 // TODO MTU size setting not found for v1 ethernet, check if correct
194
195 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
196 let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
197 let hclk_mhz = hclk.0 / 1_000_000;
198
199 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
200 let clock_range = match hclk_mhz {
201 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
202 25..=34 => Cr::CR_20_35, // Divide by 16
203 35..=59 => Cr::CR_35_60, // Divide by 26
204 60..=99 => Cr::CR_60_100, // Divide by 42
205 100..=149 => Cr::CR_100_150, // Divide by 62
206 150..=216 => Cr::CR_150_168, // Divide by 102
207 _ => {
208 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
209 }
210 };
211
212 let pins = [
213 ref_clk.map_into(),
214 mdio.map_into(),
215 mdc.map_into(),
216 crs.map_into(),
217 rx_d0.map_into(),
218 rx_d1.map_into(),
219 tx_d0.map_into(),
220 tx_d1.map_into(),
221 tx_en.map_into(),
222 ];
223
224 let mut this = Self {
225 _peri: peri,
226 pins,
227 _phy: phy,
228 clock_range,
229 phy_addr,
230 mac_addr,
231 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
232 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
233 };
234
235 fence(Ordering::SeqCst);
236
237 let mac = ETH.ethernet_mac();
238 let dma = ETH.ethernet_dma();
239
240 mac.maccr().modify(|w| {
241 w.set_re(true);
242 w.set_te(true);
243 });
244 dma.dmaomr().modify(|w| {
245 w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue)
246 w.set_st(St::STARTED); // start transmitting channel
247 w.set_sr(DmaomrSr::STARTED); // start receiving channel
248 });
249
250 this.rx.demand_poll();
251
252 // Enable interrupts
253 dma.dmaier().modify(|w| {
254 w.set_nise(true);
255 w.set_rie(true);
256 w.set_tie(true);
257 });
258
259 P::phy_reset(&mut this);
260 P::phy_init(&mut this);
261
262 interrupt::ETH.unpend();
263 unsafe { interrupt::ETH.enable() };
264
265 this
275 } 266 }
276} 267}
277 268
278unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 269unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
279 fn smi_read(&mut self, reg: u8) -> u16 { 270 fn smi_read(&mut self, reg: u8) -> u16 {
280 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 271 let mac = ETH.ethernet_mac();
281 unsafe { 272
282 let mac = ETH.ethernet_mac(); 273 mac.macmiiar().modify(|w| {
283 274 w.set_pa(self.phy_addr);
284 mac.macmiiar().modify(|w| { 275 w.set_mr(reg);
285 w.set_pa(self.phy_addr); 276 w.set_mw(Mw::READ); // read operation
286 w.set_mr(reg); 277 w.set_cr(self.clock_range);
287 w.set_mw(Mw::READ); // read operation 278 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
288 w.set_cr(self.clock_range); 279 });
289 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress 280 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
290 }); 281 mac.macmiidr().read().md()
291 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
292 mac.macmiidr().read().md()
293 }
294 } 282 }
295 283
296 fn smi_write(&mut self, reg: u8, val: u16) { 284 fn smi_write(&mut self, reg: u8, val: u16) {
297 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 285 let mac = ETH.ethernet_mac();
298 unsafe { 286
299 let mac = ETH.ethernet_mac(); 287 mac.macmiidr().write(|w| w.set_md(val));
300 288 mac.macmiiar().modify(|w| {
301 mac.macmiidr().write(|w| w.set_md(val)); 289 w.set_pa(self.phy_addr);
302 mac.macmiiar().modify(|w| { 290 w.set_mr(reg);
303 w.set_pa(self.phy_addr); 291 w.set_mw(Mw::WRITE); // write
304 w.set_mr(reg); 292 w.set_cr(self.clock_range);
305 w.set_mw(Mw::WRITE); // write 293 w.set_mb(MbProgress::BUSY);
306 w.set_cr(self.clock_range); 294 });
307 w.set_mb(MbProgress::BUSY); 295 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
308 });
309 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
310 }
311 } 296 }
312} 297}
313 298
314impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 299impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
315 fn drop(&mut self) { 300 fn drop(&mut self) {
316 // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers 301 let dma = ETH.ethernet_dma();
317 unsafe { 302 let mac = ETH.ethernet_mac();
318 let dma = ETH.ethernet_dma();
319 let mac = ETH.ethernet_mac();
320
321 // Disable the TX DMA and wait for any previous transmissions to be completed
322 dma.dmaomr().modify(|w| w.set_st(St::STOPPED));
323
324 // Disable MAC transmitter and receiver
325 mac.maccr().modify(|w| {
326 w.set_re(false);
327 w.set_te(false);
328 });
329 303
330 dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); 304 // Disable the TX DMA and wait for any previous transmissions to be completed
331 } 305 dma.dmaomr().modify(|w| w.set_st(St::STOPPED));
306
307 // Disable MAC transmitter and receiver
308 mac.maccr().modify(|w| {
309 w.set_re(false);
310 w.set_te(false);
311 });
332 312
333 // NOTE(unsafe) Exclusive access to the regs 313 dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
334 critical_section::with(|_| unsafe { 314
315 critical_section::with(|_| {
335 for pin in self.pins.iter_mut() { 316 for pin in self.pins.iter_mut() {
336 pin.set_as_disconnected(); 317 pin.set_as_disconnected();
337 } 318 }
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 8b8566d92..668378bea 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -146,12 +146,9 @@ impl<'a> RDesRing<'a> {
146 } 146 }
147 147
148 // Register rx descriptor start 148 // Register rx descriptor start
149 // NOTE (unsafe) Used for atomic writes 149 ETH.ethernet_dma()
150 unsafe { 150 .dmardlar()
151 ETH.ethernet_dma() 151 .write(|w| w.0 = descriptors.as_ptr() as u32);
152 .dmardlar()
153 .write(|w| w.0 = descriptors.as_ptr() as u32);
154 };
155 // We already have fences in `set_owned`, which is called in `setup` 152 // We already have fences in `set_owned`, which is called in `setup`
156 153
157 Self { 154 Self {
@@ -162,12 +159,12 @@ impl<'a> RDesRing<'a> {
162 } 159 }
163 160
164 pub(crate) fn demand_poll(&self) { 161 pub(crate) fn demand_poll(&self) {
165 unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) }; 162 ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL));
166 } 163 }
167 164
168 /// Get current `RunningState` 165 /// Get current `RunningState`
169 fn running_state(&self) -> RunningState { 166 fn running_state(&self) -> RunningState {
170 match unsafe { ETH.ethernet_dma().dmasr().read().rps() } { 167 match ETH.ethernet_dma().dmasr().read().rps() {
171 // Reset or Stop Receive Command issued 168 // Reset or Stop Receive Command issued
172 Rps::STOPPED => RunningState::Stopped, 169 Rps::STOPPED => RunningState::Stopped,
173 // Fetching receive transfer descriptor 170 // Fetching receive transfer descriptor
@@ -177,7 +174,7 @@ impl<'a> RDesRing<'a> {
177 // Receive descriptor unavailable 174 // Receive descriptor unavailable
178 Rps::SUSPENDED => RunningState::Stopped, 175 Rps::SUSPENDED => RunningState::Stopped,
179 // Closing receive descriptor 176 // Closing receive descriptor
180 Rps(0b101) => RunningState::Running, 177 Rps::_RESERVED_5 => RunningState::Running,
181 // Transferring the receive packet data from receive buffer to host memory 178 // Transferring the receive packet data from receive buffer to host memory
182 Rps::RUNNINGWRITING => RunningState::Running, 179 Rps::RUNNINGWRITING => RunningState::Running,
183 _ => RunningState::Unknown, 180 _ => RunningState::Unknown,
diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs
index 0e63c5443..1317d20f4 100644
--- a/embassy-stm32/src/eth/v1/tx_desc.rs
+++ b/embassy-stm32/src/eth/v1/tx_desc.rs
@@ -120,12 +120,9 @@ impl<'a> TDesRing<'a> {
120 } 120 }
121 121
122 // Register txdescriptor start 122 // Register txdescriptor start
123 // NOTE (unsafe) Used for atomic writes 123 ETH.ethernet_dma()
124 unsafe { 124 .dmatdlar()
125 ETH.ethernet_dma() 125 .write(|w| w.0 = descriptors.as_ptr() as u32);
126 .dmatdlar()
127 .write(|w| w.0 = descriptors.as_ptr() as u32);
128 }
129 126
130 Self { 127 Self {
131 descriptors, 128 descriptors,
@@ -169,6 +166,6 @@ impl<'a> TDesRing<'a> {
169 self.index = 0 166 self.index = 0
170 } 167 }
171 // Request the DMA engine to poll the latest tx descriptor 168 // Request the DMA engine to poll the latest tx descriptor
172 unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) } 169 ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1)
173 } 170 }
174} 171}
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 2426596fb..e9799adf1 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -73,14 +73,10 @@ impl<'a> TDesRing<'a> {
73 73
74 // Initialize the pointers in the DMA engine. (There will be a memory barrier later 74 // Initialize the pointers in the DMA engine. (There will be a memory barrier later
75 // before the DMA engine is enabled.) 75 // before the DMA engine is enabled.)
76 // NOTE (unsafe) Used for atomic writes 76 let dma = ETH.ethernet_dma();
77 unsafe { 77 dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
78 let dma = ETH.ethernet_dma(); 78 dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
79 79 dma.dmactx_dtpr().write(|w| w.0 = 0);
80 dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
81 dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
82 dma.dmactx_dtpr().write(|w| w.0 = 0);
83 }
84 80
85 Self { 81 Self {
86 descriptors, 82 descriptors,
@@ -129,8 +125,7 @@ impl<'a> TDesRing<'a> {
129 } 125 }
130 126
131 // signal DMA it can try again. 127 // signal DMA it can try again.
132 // NOTE(unsafe) Atomic write 128 ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0)
133 unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) }
134 } 129 }
135} 130}
136 131
@@ -199,13 +194,10 @@ impl<'a> RDesRing<'a> {
199 desc.set_ready(buffers[i].0.as_mut_ptr()); 194 desc.set_ready(buffers[i].0.as_mut_ptr());
200 } 195 }
201 196
202 unsafe { 197 let dma = ETH.ethernet_dma();
203 let dma = ETH.ethernet_dma(); 198 dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
204 199 dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
205 dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); 200 dma.dmacrx_dtpr().write(|w| w.0 = 0);
206 dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
207 dma.dmacrx_dtpr().write(|w| w.0 = 0);
208 }
209 201
210 Self { 202 Self {
211 descriptors, 203 descriptors,
@@ -254,8 +246,7 @@ impl<'a> RDesRing<'a> {
254 fence(Ordering::Release); 246 fence(Ordering::Release);
255 247
256 // signal DMA it can try again. 248 // signal DMA it can try again.
257 // NOTE(unsafe) Atomic write 249 ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0);
258 unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) }
259 250
260 // Increment index. 251 // Increment index.
261 self.index += 1; 252 self.index += 1;
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 9efa436ac..600e1d3bc 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -2,36 +2,34 @@ mod descriptors;
2 2
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4 4
5use embassy_cortex_m::interrupt::Interrupt;
6use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
7 6
8pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; 7pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
9use super::*; 8use super::*;
10use crate::gpio::sealed::{AFType, Pin as _}; 9use crate::gpio::sealed::{AFType, Pin as _};
11use crate::gpio::{AnyPin, Speed}; 10use crate::gpio::{AnyPin, Speed};
11use crate::interrupt::InterruptExt;
12use crate::pac::ETH; 12use crate::pac::ETH;
13use crate::{interrupt, Peripheral}; 13use crate::{interrupt, Peripheral};
14 14
15/// Interrupt handler. 15/// Interrupt handler.
16pub struct InterruptHandler {} 16pub struct InterruptHandler {}
17 17
18impl interrupt::Handler<interrupt::ETH> for InterruptHandler { 18impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler {
19 unsafe fn on_interrupt() { 19 unsafe fn on_interrupt() {
20 WAKER.wake(); 20 WAKER.wake();
21 21
22 // TODO: Check and clear more flags 22 // TODO: Check and clear more flags
23 unsafe { 23 let dma = ETH.ethernet_dma();
24 let dma = ETH.ethernet_dma(); 24
25 25 dma.dmacsr().modify(|w| {
26 dma.dmacsr().modify(|w| { 26 w.set_ti(true);
27 w.set_ti(true); 27 w.set_ri(true);
28 w.set_ri(true); 28 w.set_nis(true);
29 w.set_nis(true); 29 });
30 }); 30 // Delay two peripheral's clock
31 // Delay two peripheral's clock 31 dma.dmacsr().read();
32 dma.dmacsr().read(); 32 dma.dmacsr().read();
33 dma.dmacsr().read();
34 }
35 } 33 }
36} 34}
37 35
@@ -50,7 +48,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
50 48
51macro_rules! config_pins { 49macro_rules! config_pins {
52 ($($pin:ident),*) => { 50 ($($pin:ident),*) => {
53 // NOTE(unsafe) Exclusive access to the registers
54 critical_section::with(|_| { 51 critical_section::with(|_| {
55 $( 52 $(
56 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); 53 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
@@ -64,7 +61,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
64 pub fn new<const TX: usize, const RX: usize>( 61 pub fn new<const TX: usize, const RX: usize>(
65 queue: &'d mut PacketQueue<TX, RX>, 62 queue: &'d mut PacketQueue<TX, RX>,
66 peri: impl Peripheral<P = T> + 'd, 63 peri: impl Peripheral<P = T> + 'd,
67 _irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd, 64 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
68 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 65 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
69 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 66 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
70 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 67 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@@ -80,239 +77,225 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
80 ) -> Self { 77 ) -> Self {
81 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 78 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
82 79
83 unsafe { 80 // Enable the necessary Clocks
84 // Enable the necessary Clocks 81 #[cfg(not(rcc_h5))]
85 // NOTE(unsafe) We have exclusive access to the registers 82 critical_section::with(|_| {
86 #[cfg(not(rcc_h5))] 83 crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
87 critical_section::with(|_| { 84 crate::pac::RCC.ahb1enr().modify(|w| {
88 crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); 85 w.set_eth1macen(true);
89 crate::pac::RCC.ahb1enr().modify(|w| { 86 w.set_eth1txen(true);
90 w.set_eth1macen(true); 87 w.set_eth1rxen(true);
91 w.set_eth1txen(true);
92 w.set_eth1rxen(true);
93 });
94
95 // RMII
96 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
97 });
98
99 #[cfg(rcc_h5)]
100 critical_section::with(|_| {
101 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
102
103 crate::pac::RCC.ahb1enr().modify(|w| {
104 w.set_ethen(true);
105 w.set_ethtxen(true);
106 w.set_ethrxen(true);
107 });
108
109 // RMII
110 crate::pac::SBS
111 .pmcr()
112 .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
113 });
114
115 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
116
117 // NOTE(unsafe) We have exclusive access to the registers
118 let dma = ETH.ethernet_dma();
119 let mac = ETH.ethernet_mac();
120 let mtl = ETH.ethernet_mtl();
121
122 // Reset and wait
123 dma.dmamr().modify(|w| w.set_swr(true));
124 while dma.dmamr().read().swr() {}
125
126 mac.maccr().modify(|w| {
127 w.set_ipg(0b000); // 96 bit times
128 w.set_acs(true);
129 w.set_fes(true);
130 w.set_dm(true);
131 // TODO: Carrier sense ? ECRSFD
132 });
133
134 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
135 // so the LR write must happen after the HR write.
136 mac.maca0hr()
137 .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
138 mac.maca0lr().write(|w| {
139 w.set_addrlo(
140 u32::from(mac_addr[0])
141 | (u32::from(mac_addr[1]) << 8)
142 | (u32::from(mac_addr[2]) << 16)
143 | (u32::from(mac_addr[3]) << 24),
144 )
145 });
146
147 mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
148
149 // disable all MMC RX interrupts
150 mac.mmc_rx_interrupt_mask().write(|w| {
151 w.set_rxcrcerpim(true);
152 w.set_rxalgnerpim(true);
153 w.set_rxucgpim(true);
154 w.set_rxlpiuscim(true);
155 w.set_rxlpitrcim(true)
156 });
157
158 // disable all MMC TX interrupts
159 mac.mmc_tx_interrupt_mask().write(|w| {
160 w.set_txscolgpim(true);
161 w.set_txmcolgpim(true);
162 w.set_txgpktim(true);
163 w.set_txlpiuscim(true);
164 w.set_txlpitrcim(true);
165 });
166
167 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
168 mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
169
170 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
171 dma.dmacrx_cr().modify(|w| {
172 w.set_rxpbl(1); // 32 ?
173 w.set_rbsz(MTU as u16);
174 }); 88 });
175 89
176 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 90 // RMII
177 let hclk = crate::rcc::get_freqs().ahb1; 91 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
178 let hclk_mhz = hclk.0 / 1_000_000; 92 });
179
180 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
181 let clock_range = match hclk_mhz {
182 0..=34 => 2, // Divide by 16
183 35..=59 => 3, // Divide by 26
184 60..=99 => 0, // Divide by 42
185 100..=149 => 1, // Divide by 62
186 150..=249 => 4, // Divide by 102
187 250..=310 => 5, // Divide by 124
188 _ => {
189 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
190 }
191 };
192
193 let pins = [
194 ref_clk.map_into(),
195 mdio.map_into(),
196 mdc.map_into(),
197 crs.map_into(),
198 rx_d0.map_into(),
199 rx_d1.map_into(),
200 tx_d0.map_into(),
201 tx_d1.map_into(),
202 tx_en.map_into(),
203 ];
204
205 let mut this = Self {
206 _peri: peri,
207 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
208 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
209 pins,
210 _phy: phy,
211 clock_range,
212 phy_addr,
213 mac_addr,
214 };
215
216 fence(Ordering::SeqCst);
217
218 let mac = ETH.ethernet_mac();
219 let mtl = ETH.ethernet_mtl();
220 let dma = ETH.ethernet_dma();
221
222 mac.maccr().modify(|w| {
223 w.set_re(true);
224 w.set_te(true);
225 });
226 mtl.mtltx_qomr().modify(|w| w.set_ftq(true));
227 93
228 dma.dmactx_cr().modify(|w| w.set_st(true)); 94 #[cfg(rcc_h5)]
229 dma.dmacrx_cr().modify(|w| w.set_sr(true)); 95 critical_section::with(|_| {
96 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
230 97
231 // Enable interrupts 98 crate::pac::RCC.ahb1enr().modify(|w| {
232 dma.dmacier().modify(|w| { 99 w.set_ethen(true);
233 w.set_nie(true); 100 w.set_ethtxen(true);
234 w.set_rie(true); 101 w.set_ethrxen(true);
235 w.set_tie(true);
236 }); 102 });
237 103
238 P::phy_reset(&mut this); 104 // RMII
239 P::phy_init(&mut this); 105 crate::pac::SBS
240 106 .pmcr()
241 interrupt::ETH::unpend(); 107 .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
242 interrupt::ETH::enable(); 108 });
243 109
244 this 110 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
245 } 111
112 let dma = ETH.ethernet_dma();
113 let mac = ETH.ethernet_mac();
114 let mtl = ETH.ethernet_mtl();
115
116 // Reset and wait
117 dma.dmamr().modify(|w| w.set_swr(true));
118 while dma.dmamr().read().swr() {}
119
120 mac.maccr().modify(|w| {
121 w.set_ipg(0b000); // 96 bit times
122 w.set_acs(true);
123 w.set_fes(true);
124 w.set_dm(true);
125 // TODO: Carrier sense ? ECRSFD
126 });
127
128 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
129 // so the LR write must happen after the HR write.
130 mac.maca0hr()
131 .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
132 mac.maca0lr().write(|w| {
133 w.set_addrlo(
134 u32::from(mac_addr[0])
135 | (u32::from(mac_addr[1]) << 8)
136 | (u32::from(mac_addr[2]) << 16)
137 | (u32::from(mac_addr[3]) << 24),
138 )
139 });
140
141 mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
142
143 // disable all MMC RX interrupts
144 mac.mmc_rx_interrupt_mask().write(|w| {
145 w.set_rxcrcerpim(true);
146 w.set_rxalgnerpim(true);
147 w.set_rxucgpim(true);
148 w.set_rxlpiuscim(true);
149 w.set_rxlpitrcim(true)
150 });
151
152 // disable all MMC TX interrupts
153 mac.mmc_tx_interrupt_mask().write(|w| {
154 w.set_txscolgpim(true);
155 w.set_txmcolgpim(true);
156 w.set_txgpktim(true);
157 w.set_txlpiuscim(true);
158 w.set_txlpitrcim(true);
159 });
160
161 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
162 mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
163
164 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
165 dma.dmacrx_cr().modify(|w| {
166 w.set_rxpbl(1); // 32 ?
167 w.set_rbsz(MTU as u16);
168 });
169
170 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
171 let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
172 let hclk_mhz = hclk.0 / 1_000_000;
173
174 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
175 let clock_range = match hclk_mhz {
176 0..=34 => 2, // Divide by 16
177 35..=59 => 3, // Divide by 26
178 60..=99 => 0, // Divide by 42
179 100..=149 => 1, // Divide by 62
180 150..=249 => 4, // Divide by 102
181 250..=310 => 5, // Divide by 124
182 _ => {
183 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
184 }
185 };
186
187 let pins = [
188 ref_clk.map_into(),
189 mdio.map_into(),
190 mdc.map_into(),
191 crs.map_into(),
192 rx_d0.map_into(),
193 rx_d1.map_into(),
194 tx_d0.map_into(),
195 tx_d1.map_into(),
196 tx_en.map_into(),
197 ];
198
199 let mut this = Self {
200 _peri: peri,
201 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
202 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
203 pins,
204 _phy: phy,
205 clock_range,
206 phy_addr,
207 mac_addr,
208 };
209
210 fence(Ordering::SeqCst);
211
212 let mac = ETH.ethernet_mac();
213 let mtl = ETH.ethernet_mtl();
214 let dma = ETH.ethernet_dma();
215
216 mac.maccr().modify(|w| {
217 w.set_re(true);
218 w.set_te(true);
219 });
220 mtl.mtltx_qomr().modify(|w| w.set_ftq(true));
221
222 dma.dmactx_cr().modify(|w| w.set_st(true));
223 dma.dmacrx_cr().modify(|w| w.set_sr(true));
224
225 // Enable interrupts
226 dma.dmacier().modify(|w| {
227 w.set_nie(true);
228 w.set_rie(true);
229 w.set_tie(true);
230 });
231
232 P::phy_reset(&mut this);
233 P::phy_init(&mut this);
234
235 interrupt::ETH.unpend();
236 unsafe { interrupt::ETH.enable() };
237
238 this
246 } 239 }
247} 240}
248 241
249unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 242unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
250 fn smi_read(&mut self, reg: u8) -> u16 { 243 fn smi_read(&mut self, reg: u8) -> u16 {
251 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 244 let mac = ETH.ethernet_mac();
252 unsafe { 245
253 let mac = ETH.ethernet_mac(); 246 mac.macmdioar().modify(|w| {
254 247 w.set_pa(self.phy_addr);
255 mac.macmdioar().modify(|w| { 248 w.set_rda(reg);
256 w.set_pa(self.phy_addr); 249 w.set_goc(0b11); // read
257 w.set_rda(reg); 250 w.set_cr(self.clock_range);
258 w.set_goc(0b11); // read 251 w.set_mb(true);
259 w.set_cr(self.clock_range); 252 });
260 w.set_mb(true); 253 while mac.macmdioar().read().mb() {}
261 }); 254 mac.macmdiodr().read().md()
262 while mac.macmdioar().read().mb() {}
263 mac.macmdiodr().read().md()
264 }
265 } 255 }
266 256
267 fn smi_write(&mut self, reg: u8, val: u16) { 257 fn smi_write(&mut self, reg: u8, val: u16) {
268 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 258 let mac = ETH.ethernet_mac();
269 unsafe { 259
270 let mac = ETH.ethernet_mac(); 260 mac.macmdiodr().write(|w| w.set_md(val));
271 261 mac.macmdioar().modify(|w| {
272 mac.macmdiodr().write(|w| w.set_md(val)); 262 w.set_pa(self.phy_addr);
273 mac.macmdioar().modify(|w| { 263 w.set_rda(reg);
274 w.set_pa(self.phy_addr); 264 w.set_goc(0b01); // write
275 w.set_rda(reg); 265 w.set_cr(self.clock_range);
276 w.set_goc(0b01); // write 266 w.set_mb(true);
277 w.set_cr(self.clock_range); 267 });
278 w.set_mb(true); 268 while mac.macmdioar().read().mb() {}
279 });
280 while mac.macmdioar().read().mb() {}
281 }
282 } 269 }
283} 270}
284 271
285impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 272impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
286 fn drop(&mut self) { 273 fn drop(&mut self) {
287 // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers 274 let dma = ETH.ethernet_dma();
288 unsafe { 275 let mac = ETH.ethernet_mac();
289 let dma = ETH.ethernet_dma(); 276 let mtl = ETH.ethernet_mtl();
290 let mac = ETH.ethernet_mac(); 277
291 let mtl = ETH.ethernet_mtl(); 278 // Disable the TX DMA and wait for any previous transmissions to be completed
292 279 dma.dmactx_cr().modify(|w| w.set_st(false));
293 // Disable the TX DMA and wait for any previous transmissions to be completed 280 while {
294 dma.dmactx_cr().modify(|w| w.set_st(false)); 281 let txqueue = mtl.mtltx_qdr().read();
295 while { 282 txqueue.trcsts() == 0b01 || txqueue.txqsts()
296 let txqueue = mtl.mtltx_qdr().read(); 283 } {}
297 txqueue.trcsts() == 0b01 || txqueue.txqsts() 284
298 } {} 285 // Disable MAC transmitter and receiver
299 286 mac.maccr().modify(|w| {
300 // Disable MAC transmitter and receiver 287 w.set_re(false);
301 mac.maccr().modify(|w| { 288 w.set_te(false);
302 w.set_re(false); 289 });
303 w.set_te(false); 290
304 }); 291 // Wait for previous receiver transfers to be completed and then disable the RX DMA
292 while {
293 let rxqueue = mtl.mtlrx_qdr().read();
294 rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
295 } {}
296 dma.dmacrx_cr().modify(|w| w.set_sr(false));
305 297
306 // Wait for previous receiver transfers to be completed and then disable the RX DMA 298 critical_section::with(|_| {
307 while {
308 let rxqueue = mtl.mtlrx_qdr().read();
309 rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
310 } {}
311 dma.dmacrx_cr().modify(|w| w.set_sr(false));
312 }
313
314 // NOTE(unsafe) Exclusive access to the regs
315 critical_section::with(|_| unsafe {
316 for pin in self.pins.iter_mut() { 299 for pin in self.pins.iter_mut() {
317 pin.set_as_disconnected(); 300 pin.set_as_disconnected();
318 } 301 }
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index c2fa31b20..3ff92c9e6 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -206,7 +206,7 @@ struct ExtiInputFuture<'a> {
206 206
207impl<'a> ExtiInputFuture<'a> { 207impl<'a> ExtiInputFuture<'a> {
208 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { 208 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
209 critical_section::with(|_| unsafe { 209 critical_section::with(|_| {
210 let pin = pin as usize; 210 let pin = pin as usize;
211 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); 211 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
212 EXTI.rtsr(0).modify(|w| w.set_line(pin, rising)); 212 EXTI.rtsr(0).modify(|w| w.set_line(pin, rising));
@@ -233,7 +233,7 @@ impl<'a> ExtiInputFuture<'a> {
233 233
234impl<'a> Drop for ExtiInputFuture<'a> { 234impl<'a> Drop for ExtiInputFuture<'a> {
235 fn drop(&mut self) { 235 fn drop(&mut self) {
236 critical_section::with(|_| unsafe { 236 critical_section::with(|_| {
237 let pin = self.pin as _; 237 let pin = self.pin as _;
238 cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); 238 cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
239 }); 239 });
@@ -246,7 +246,7 @@ impl<'a> Future for ExtiInputFuture<'a> {
246 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 246 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
247 EXTI_WAKERS[self.pin as usize].register(cx.waker()); 247 EXTI_WAKERS[self.pin as usize].register(cx.waker());
248 248
249 let imr = unsafe { cpu_regs().imr(0).read() }; 249 let imr = cpu_regs().imr(0).read();
250 if !imr.line(self.pin as _) { 250 if !imr.line(self.pin as _) {
251 Poll::Ready(()) 251 Poll::Ready(())
252 } else { 252 } else {
@@ -291,6 +291,7 @@ macro_rules! foreach_exti_irq {
291 291
292macro_rules! impl_irq { 292macro_rules! impl_irq {
293 ($e:ident) => { 293 ($e:ident) => {
294 #[cfg(feature = "rt")]
294 #[interrupt] 295 #[interrupt]
295 unsafe fn $e() { 296 unsafe fn $e() {
296 on_irq() 297 on_irq()
@@ -354,13 +355,13 @@ impl_exti!(EXTI15, 15);
354 355
355macro_rules! enable_irq { 356macro_rules! enable_irq {
356 ($e:ident) => { 357 ($e:ident) => {
357 crate::interrupt::$e::enable(); 358 crate::interrupt::typelevel::$e::enable();
358 }; 359 };
359} 360}
360 361
361/// safety: must be called only once 362/// safety: must be called only once
362pub(crate) unsafe fn init() { 363pub(crate) unsafe fn init() {
363 use crate::interrupt::Interrupt; 364 use crate::interrupt::typelevel::Interrupt;
364 365
365 foreach_exti_irq!(enable_irq); 366 foreach_exti_irq!(enable_irq);
366 367
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 872614d4e..70a5ded62 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -1,7 +1,6 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use atomic_polyfill::{fence, Ordering}; 3use atomic_polyfill::{fence, Ordering};
4use embassy_cortex_m::interrupt::Interrupt;
5use embassy_hal_common::drop::OnDrop; 4use embassy_hal_common::drop::OnDrop;
6use embassy_hal_common::into_ref; 5use embassy_hal_common::into_ref;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
@@ -11,6 +10,7 @@ use super::{
11 blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, 10 blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE,
12 WRITE_SIZE, 11 WRITE_SIZE,
13}; 12};
13use crate::interrupt::InterruptExt;
14use crate::peripherals::FLASH; 14use crate::peripherals::FLASH;
15use crate::{interrupt, Peripheral}; 15use crate::{interrupt, Peripheral};
16 16
@@ -19,12 +19,12 @@ pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new
19impl<'d> Flash<'d, Async> { 19impl<'d> Flash<'d, Async> {
20 pub fn new( 20 pub fn new(
21 p: impl Peripheral<P = FLASH> + 'd, 21 p: impl Peripheral<P = FLASH> + 'd,
22 _irq: impl interrupt::Binding<crate::interrupt::FLASH, InterruptHandler> + 'd, 22 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd,
23 ) -> Self { 23 ) -> Self {
24 into_ref!(p); 24 into_ref!(p);
25 25
26 crate::interrupt::FLASH::unpend(); 26 crate::interrupt::FLASH.unpend();
27 unsafe { crate::interrupt::FLASH::enable() }; 27 unsafe { crate::interrupt::FLASH.enable() };
28 28
29 Self { 29 Self {
30 inner: p, 30 inner: p,
@@ -49,7 +49,7 @@ impl<'d> Flash<'d, Async> {
49/// Interrupt handler 49/// Interrupt handler
50pub struct InterruptHandler; 50pub struct InterruptHandler;
51 51
52impl interrupt::Handler<crate::interrupt::FLASH> for InterruptHandler { 52impl interrupt::typelevel::Handler<crate::interrupt::typelevel::FLASH> for InterruptHandler {
53 unsafe fn on_interrupt() { 53 unsafe fn on_interrupt() {
54 family::on_interrupt(); 54 family::on_interrupt();
55 } 55 }
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 5e1fc696f..242d99278 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -192,7 +192,7 @@ impl FlashSector {
192 192
193#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] 193#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
194pub(crate) fn is_default_layout() -> bool { 194pub(crate) fn is_default_layout() -> bool {
195 unsafe { !pac::FLASH.optcr().read().db1m() } 195 !pac::FLASH.optcr().read().db1m()
196} 196}
197 197
198#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] 198#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
@@ -336,7 +336,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
336 ret 336 ret
337} 337}
338 338
339pub(crate) unsafe fn clear_all_err() { 339pub(crate) fn clear_all_err() {
340 pac::FLASH.sr().write(|w| { 340 pac::FLASH.sr().write(|w| {
341 w.set_pgserr(true); 341 w.set_pgserr(true);
342 w.set_pgperr(true); 342 w.set_pgperr(true);
@@ -345,7 +345,7 @@ pub(crate) unsafe fn clear_all_err() {
345 }); 345 });
346} 346}
347 347
348pub(crate) async unsafe fn wait_ready() -> Result<(), Error> { 348pub(crate) async fn wait_ready() -> Result<(), Error> {
349 use core::task::Poll; 349 use core::task::Poll;
350 350
351 use futures::future::poll_fn; 351 use futures::future::poll_fn;
@@ -391,10 +391,10 @@ fn save_data_cache_state() {
391 let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; 391 let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2;
392 if dual_bank { 392 if dual_bank {
393 // Disable data cache during write/erase if there are two banks, see errata 2.2.12 393 // Disable data cache during write/erase if there are two banks, see errata 2.2.12
394 let dcen = unsafe { pac::FLASH.acr().read().dcen() }; 394 let dcen = pac::FLASH.acr().read().dcen();
395 DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); 395 DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed);
396 if dcen { 396 if dcen {
397 unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) }; 397 pac::FLASH.acr().modify(|w| w.set_dcen(false));
398 } 398 }
399 } 399 }
400} 400}
@@ -405,12 +405,10 @@ fn restore_data_cache_state() {
405 // Restore data cache if it was enabled 405 // Restore data cache if it was enabled
406 let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); 406 let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed);
407 if dcen { 407 if dcen {
408 unsafe { 408 // Reset data cache before we enable it again
409 // Reset data cache before we enable it again 409 pac::FLASH.acr().modify(|w| w.set_dcrst(true));
410 pac::FLASH.acr().modify(|w| w.set_dcrst(true)); 410 pac::FLASH.acr().modify(|w| w.set_dcrst(false));
411 pac::FLASH.acr().modify(|w| w.set_dcrst(false)); 411 pac::FLASH.acr().modify(|w| w.set_dcen(true))
412 pac::FLASH.acr().modify(|w| w.set_dcen(true))
413 };
414 } 412 }
415 } 413 }
416} 414}
@@ -445,7 +443,7 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
445 feature = "stm32f439vi", 443 feature = "stm32f439vi",
446 feature = "stm32f439zi", 444 feature = "stm32f439zi",
447 ))] 445 ))]
448 if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } { 446 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
449 panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); 447 panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11");
450 } 448 }
451 449
@@ -479,11 +477,9 @@ fn pa12_is_output_pull_low() -> bool {
479 use pac::gpio::vals; 477 use pac::gpio::vals;
480 use pac::GPIOA; 478 use pac::GPIOA;
481 const PIN: usize = 12; 479 const PIN: usize = 12;
482 unsafe { 480 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
483 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT 481 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN
484 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN 482 && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
485 && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
486 }
487} 483}
488 484
489#[cfg(test)] 485#[cfg(test)]
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index b9129cb51..a4f3b9686 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -16,7 +16,7 @@ unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T>
16where 16where
17 T: Instance, 17 T: Instance,
18{ 18{
19 const REGISTERS: *const () = T::REGS.0 as *const _; 19 const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
20 20
21 fn enable(&mut self) { 21 fn enable(&mut self) {
22 <T as crate::rcc::sealed::RccPeripheral>::enable(); 22 <T as crate::rcc::sealed::RccPeripheral>::enable();
@@ -28,9 +28,7 @@ where
28 // fsmc v1, v2 and v3 does not have the fmcen bit 28 // fsmc v1, v2 and v3 does not have the fmcen bit
29 // This is a "not" because it is expected that all future versions have this bit 29 // This is a "not" because it is expected that all future versions have this bit
30 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] 30 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
31 unsafe { 31 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
32 T::REGS.bcr1().modify(|r| r.set_fmcen(true))
33 };
34 } 32 }
35 33
36 fn source_clock_hz(&self) -> u32 { 34 fn source_clock_hz(&self) -> u32 {
@@ -67,7 +65,7 @@ macro_rules! fmc_sdram_constructor {
67 chip: CHIP 65 chip: CHIP
68 ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> { 66 ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> {
69 67
70 critical_section::with(|_| unsafe { 68 critical_section::with(|_| {
71 config_pins!( 69 config_pins!(
72 $($addr_pin_name),*, 70 $($addr_pin_name),*,
73 $($ba_pin_name),*, 71 $($ba_pin_name),*,
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 7a066a4ca..af3a8eaca 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -46,7 +46,7 @@ impl<'d, T: Pin> Flex<'d, T> {
46 /// Put the pin into input mode. 46 /// Put the pin into input mode.
47 #[inline] 47 #[inline]
48 pub fn set_as_input(&mut self, pull: Pull) { 48 pub fn set_as_input(&mut self, pull: Pull) {
49 critical_section::with(|_| unsafe { 49 critical_section::with(|_| {
50 let r = self.pin.block(); 50 let r = self.pin.block();
51 let n = self.pin.pin() as usize; 51 let n = self.pin.pin() as usize;
52 #[cfg(gpio_v1)] 52 #[cfg(gpio_v1)]
@@ -84,7 +84,7 @@ impl<'d, T: Pin> Flex<'d, T> {
84 /// at a specific level, call `set_high`/`set_low` on the pin first. 84 /// at a specific level, call `set_high`/`set_low` on the pin first.
85 #[inline] 85 #[inline]
86 pub fn set_as_output(&mut self, speed: Speed) { 86 pub fn set_as_output(&mut self, speed: Speed) {
87 critical_section::with(|_| unsafe { 87 critical_section::with(|_| {
88 let r = self.pin.block(); 88 let r = self.pin.block();
89 let n = self.pin.pin() as usize; 89 let n = self.pin.pin() as usize;
90 #[cfg(gpio_v1)] 90 #[cfg(gpio_v1)]
@@ -116,7 +116,7 @@ impl<'d, T: Pin> Flex<'d, T> {
116 /// at a specific level, call `set_high`/`set_low` on the pin first. 116 /// at a specific level, call `set_high`/`set_low` on the pin first.
117 #[inline] 117 #[inline]
118 pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) { 118 pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) {
119 critical_section::with(|_| unsafe { 119 critical_section::with(|_| {
120 let r = self.pin.block(); 120 let r = self.pin.block();
121 let n = self.pin.pin() as usize; 121 let n = self.pin.pin() as usize;
122 #[cfg(gpio_v1)] 122 #[cfg(gpio_v1)]
@@ -147,7 +147,7 @@ impl<'d, T: Pin> Flex<'d, T> {
147 147
148 #[inline] 148 #[inline]
149 pub fn is_low(&self) -> bool { 149 pub fn is_low(&self) -> bool {
150 let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) }; 150 let state = self.pin.block().idr().read().idr(self.pin.pin() as _);
151 state == vals::Idr::LOW 151 state == vals::Idr::LOW
152 } 152 }
153 153
@@ -164,7 +164,7 @@ impl<'d, T: Pin> Flex<'d, T> {
164 /// Is the output pin set as low? 164 /// Is the output pin set as low?
165 #[inline] 165 #[inline]
166 pub fn is_set_low(&self) -> bool { 166 pub fn is_set_low(&self) -> bool {
167 let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) }; 167 let state = self.pin.block().odr().read().odr(self.pin.pin() as _);
168 state == vals::Odr::LOW 168 state == vals::Odr::LOW
169 } 169 }
170 170
@@ -207,7 +207,7 @@ impl<'d, T: Pin> Flex<'d, T> {
207impl<'d, T: Pin> Drop for Flex<'d, T> { 207impl<'d, T: Pin> Drop for Flex<'d, T> {
208 #[inline] 208 #[inline]
209 fn drop(&mut self) { 209 fn drop(&mut self) {
210 critical_section::with(|_| unsafe { 210 critical_section::with(|_| {
211 let r = self.pin.block(); 211 let r = self.pin.block();
212 let n = self.pin.pin() as usize; 212 let n = self.pin.pin() as usize;
213 #[cfg(gpio_v1)] 213 #[cfg(gpio_v1)]
@@ -534,29 +534,25 @@ pub(crate) mod sealed {
534 /// Set the output as high. 534 /// Set the output as high.
535 #[inline] 535 #[inline]
536 fn set_high(&self) { 536 fn set_high(&self) {
537 unsafe { 537 let n = self._pin() as _;
538 let n = self._pin() as _; 538 self.block().bsrr().write(|w| w.set_bs(n, true));
539 self.block().bsrr().write(|w| w.set_bs(n, true));
540 }
541 } 539 }
542 540
543 /// Set the output as low. 541 /// Set the output as low.
544 #[inline] 542 #[inline]
545 fn set_low(&self) { 543 fn set_low(&self) {
546 unsafe { 544 let n = self._pin() as _;
547 let n = self._pin() as _; 545 self.block().bsrr().write(|w| w.set_br(n, true));
548 self.block().bsrr().write(|w| w.set_br(n, true));
549 }
550 } 546 }
551 547
552 #[inline] 548 #[inline]
553 unsafe fn set_as_af(&self, af_num: u8, af_type: AFType) { 549 fn set_as_af(&self, af_num: u8, af_type: AFType) {
554 self.set_as_af_pull(af_num, af_type, Pull::None); 550 self.set_as_af_pull(af_num, af_type, Pull::None);
555 } 551 }
556 552
557 #[cfg(gpio_v1)] 553 #[cfg(gpio_v1)]
558 #[inline] 554 #[inline]
559 unsafe fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { 555 fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) {
560 // F1 uses the AFIO register for remapping. 556 // F1 uses the AFIO register for remapping.
561 // For now, this is not implemented, so af_num is ignored 557 // For now, this is not implemented, so af_num is ignored
562 // _af_num should be zero here, since it is not set by stm32-data 558 // _af_num should be zero here, since it is not set by stm32-data
@@ -599,7 +595,7 @@ pub(crate) mod sealed {
599 595
600 #[cfg(gpio_v2)] 596 #[cfg(gpio_v2)]
601 #[inline] 597 #[inline]
602 unsafe fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { 598 fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) {
603 let pin = self._pin() as usize; 599 let pin = self._pin() as usize;
604 let block = self.block(); 600 let block = self.block();
605 block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); 601 block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num));
@@ -614,7 +610,7 @@ pub(crate) mod sealed {
614 } 610 }
615 611
616 #[inline] 612 #[inline]
617 unsafe fn set_as_analog(&self) { 613 fn set_as_analog(&self) {
618 let pin = self._pin() as usize; 614 let pin = self._pin() as usize;
619 let block = self.block(); 615 let block = self.block();
620 #[cfg(gpio_v1)] 616 #[cfg(gpio_v1)]
@@ -635,12 +631,12 @@ pub(crate) mod sealed {
635 /// This is currently the same as set_as_analog but is semantically different really. 631 /// This is currently the same as set_as_analog but is semantically different really.
636 /// Drivers should set_as_disconnected pins when dropped. 632 /// Drivers should set_as_disconnected pins when dropped.
637 #[inline] 633 #[inline]
638 unsafe fn set_as_disconnected(&self) { 634 fn set_as_disconnected(&self) {
639 self.set_as_analog(); 635 self.set_as_analog();
640 } 636 }
641 637
642 #[inline] 638 #[inline]
643 unsafe fn set_speed(&self, speed: Speed) { 639 fn set_speed(&self, speed: Speed) {
644 let pin = self._pin() as usize; 640 let pin = self._pin() as usize;
645 641
646 #[cfg(gpio_v1)] 642 #[cfg(gpio_v1)]
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index f898fcc8b..b35678ed9 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -1,6 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3use crate::interrupt::Interrupt; 3use crate::interrupt;
4 4
5#[cfg_attr(i2c_v1, path = "v1.rs")] 5#[cfg_attr(i2c_v1, path = "v1.rs")]
6#[cfg_attr(i2c_v2, path = "v2.rs")] 6#[cfg_attr(i2c_v2, path = "v2.rs")]
@@ -35,7 +35,7 @@ pub(crate) mod sealed {
35} 35}
36 36
37pub trait Instance: sealed::Instance + 'static { 37pub trait Instance: sealed::Instance + 'static {
38 type Interrupt: Interrupt; 38 type Interrupt: interrupt::typelevel::Interrupt;
39} 39}
40 40
41pin_trait!(SclPin, Instance); 41pin_trait!(SclPin, Instance);
@@ -57,7 +57,7 @@ foreach_interrupt!(
57 } 57 }
58 58
59 impl Instance for peripherals::$inst { 59 impl Instance for peripherals::$inst {
60 type Interrupt = crate::interrupt::$irq; 60 type Interrupt = crate::interrupt::typelevel::$irq;
61 } 61 }
62 }; 62 };
63); 63);
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index b9be2e587..aa485cd86 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> {
16 _phantom: PhantomData<T>, 16 _phantom: PhantomData<T>,
17} 17}
18 18
19impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 19impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
20 unsafe fn on_interrupt() {} 20 unsafe fn on_interrupt() {}
21} 21}
22 22
@@ -57,7 +57,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
57 _peri: impl Peripheral<P = T> + 'd, 57 _peri: impl Peripheral<P = T> + 'd,
58 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 58 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
59 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 59 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
60 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 60 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
61 tx_dma: impl Peripheral<P = TXDMA> + 'd, 61 tx_dma: impl Peripheral<P = TXDMA> + 'd,
62 rx_dma: impl Peripheral<P = RXDMA> + 'd, 62 rx_dma: impl Peripheral<P = RXDMA> + 'd,
63 freq: Hertz, 63 freq: Hertz,
@@ -68,53 +68,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
68 T::enable(); 68 T::enable();
69 T::reset(); 69 T::reset();
70 70
71 unsafe { 71 scl.set_as_af_pull(
72 scl.set_as_af_pull( 72 scl.af_num(),
73 scl.af_num(), 73 AFType::OutputOpenDrain,
74 AFType::OutputOpenDrain, 74 match config.scl_pullup {
75 match config.scl_pullup { 75 true => Pull::Up,
76 true => Pull::Up, 76 false => Pull::None,
77 false => Pull::None, 77 },
78 }, 78 );
79 ); 79 sda.set_as_af_pull(
80 sda.set_as_af_pull( 80 sda.af_num(),
81 sda.af_num(), 81 AFType::OutputOpenDrain,
82 AFType::OutputOpenDrain, 82 match config.sda_pullup {
83 match config.sda_pullup { 83 true => Pull::Up,
84 true => Pull::Up, 84 false => Pull::None,
85 false => Pull::None, 85 },
86 }, 86 );
87 );
88 }
89 87
90 unsafe { 88 T::regs().cr1().modify(|reg| {
91 T::regs().cr1().modify(|reg| { 89 reg.set_pe(false);
92 reg.set_pe(false); 90 //reg.set_anfoff(false);
93 //reg.set_anfoff(false); 91 });
94 });
95 }
96 92
97 let timings = Timings::new(T::frequency(), freq.into()); 93 let timings = Timings::new(T::frequency(), freq.into());
98 94
99 unsafe { 95 T::regs().cr2().modify(|reg| {
100 T::regs().cr2().modify(|reg| { 96 reg.set_freq(timings.freq);
101 reg.set_freq(timings.freq); 97 });
102 }); 98 T::regs().ccr().modify(|reg| {
103 T::regs().ccr().modify(|reg| { 99 reg.set_f_s(timings.mode.f_s());
104 reg.set_f_s(timings.mode.f_s()); 100 reg.set_duty(timings.duty.duty());
105 reg.set_duty(timings.duty.duty()); 101 reg.set_ccr(timings.ccr);
106 reg.set_ccr(timings.ccr); 102 });
107 }); 103 T::regs().trise().modify(|reg| {
108 T::regs().trise().modify(|reg| { 104 reg.set_trise(timings.trise);
109 reg.set_trise(timings.trise); 105 });
110 });
111 }
112 106
113 unsafe { 107 T::regs().cr1().modify(|reg| {
114 T::regs().cr1().modify(|reg| { 108 reg.set_pe(true);
115 reg.set_pe(true); 109 });
116 });
117 }
118 110
119 Self { 111 Self {
120 phantom: PhantomData, 112 phantom: PhantomData,
@@ -123,7 +115,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
123 } 115 }
124 } 116 }
125 117
126 unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { 118 fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
127 // Note that flags should only be cleared once they have been registered. If flags are 119 // Note that flags should only be cleared once they have been registered. If flags are
128 // cleared otherwise, there may be an inherent race condition and flags may be missed. 120 // cleared otherwise, there may be an inherent race condition and flags may be missed.
129 let sr1 = T::regs().sr1().read(); 121 let sr1 = T::regs().sr1().read();
@@ -162,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
162 Ok(sr1) 154 Ok(sr1)
163 } 155 }
164 156
165 unsafe fn write_bytes( 157 fn write_bytes(
166 &mut self, 158 &mut self,
167 addr: u8, 159 addr: u8,
168 bytes: &[u8], 160 bytes: &[u8],
@@ -211,7 +203,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
211 Ok(()) 203 Ok(())
212 } 204 }
213 205
214 unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 206 fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
215 // Wait until we're ready for sending 207 // Wait until we're ready for sending
216 while { 208 while {
217 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 209 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
@@ -234,7 +226,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
234 Ok(()) 226 Ok(())
235 } 227 }
236 228
237 unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { 229 fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
238 while { 230 while {
239 // Check for any potential error conditions. 231 // Check for any potential error conditions.
240 self.check_and_clear_error_flags()?; 232 self.check_and_clear_error_flags()?;
@@ -256,56 +248,52 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
256 ) -> Result<(), Error> { 248 ) -> Result<(), Error> {
257 if let Some((last, buffer)) = buffer.split_last_mut() { 249 if let Some((last, buffer)) = buffer.split_last_mut() {
258 // Send a START condition and set ACK bit 250 // Send a START condition and set ACK bit
259 unsafe { 251 T::regs().cr1().modify(|reg| {
260 T::regs().cr1().modify(|reg| { 252 reg.set_start(true);
261 reg.set_start(true); 253 reg.set_ack(true);
262 reg.set_ack(true); 254 });
263 });
264 }
265 255
266 // Wait until START condition was generated 256 // Wait until START condition was generated
267 while unsafe { !self.check_and_clear_error_flags()?.start() } { 257 while !self.check_and_clear_error_flags()?.start() {
268 check_timeout()?; 258 check_timeout()?;
269 } 259 }
270 260
271 // Also wait until signalled we're master and everything is waiting for us 261 // Also wait until signalled we're master and everything is waiting for us
272 while { 262 while {
273 let sr2 = unsafe { T::regs().sr2().read() }; 263 let sr2 = T::regs().sr2().read();
274 !sr2.msl() && !sr2.busy() 264 !sr2.msl() && !sr2.busy()
275 } { 265 } {
276 check_timeout()?; 266 check_timeout()?;
277 } 267 }
278 268
279 // Set up current address, we're trying to talk to 269 // Set up current address, we're trying to talk to
280 unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } 270 T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1));
281 271
282 // Wait until address was sent 272 // Wait until address was sent
283 // Wait for the address to be acknowledged 273 // Wait for the address to be acknowledged
284 while unsafe { !self.check_and_clear_error_flags()?.addr() } { 274 while !self.check_and_clear_error_flags()?.addr() {
285 check_timeout()?; 275 check_timeout()?;
286 } 276 }
287 277
288 // Clear condition by reading SR2 278 // Clear condition by reading SR2
289 let _ = unsafe { T::regs().sr2().read() }; 279 let _ = T::regs().sr2().read();
290 280
291 // Receive bytes into buffer 281 // Receive bytes into buffer
292 for c in buffer { 282 for c in buffer {
293 *c = unsafe { self.recv_byte(&check_timeout)? }; 283 *c = self.recv_byte(&check_timeout)?;
294 } 284 }
295 285
296 // Prepare to send NACK then STOP after next byte 286 // Prepare to send NACK then STOP after next byte
297 unsafe { 287 T::regs().cr1().modify(|reg| {
298 T::regs().cr1().modify(|reg| { 288 reg.set_ack(false);
299 reg.set_ack(false); 289 reg.set_stop(true);
300 reg.set_stop(true); 290 });
301 })
302 }
303 291
304 // Receive last byte 292 // Receive last byte
305 *last = unsafe { self.recv_byte(&check_timeout)? }; 293 *last = self.recv_byte(&check_timeout)?;
306 294
307 // Wait for the STOP to be sent. 295 // Wait for the STOP to be sent.
308 while unsafe { T::regs().cr1().read().stop() } { 296 while T::regs().cr1().read().stop() {
309 check_timeout()?; 297 check_timeout()?;
310 } 298 }
311 299
@@ -326,15 +314,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
326 write: &[u8], 314 write: &[u8],
327 check_timeout: impl Fn() -> Result<(), Error>, 315 check_timeout: impl Fn() -> Result<(), Error>,
328 ) -> Result<(), Error> { 316 ) -> Result<(), Error> {
329 unsafe { 317 self.write_bytes(addr, write, &check_timeout)?;
330 self.write_bytes(addr, write, &check_timeout)?; 318 // Send a STOP condition
331 // Send a STOP condition 319 T::regs().cr1().modify(|reg| reg.set_stop(true));
332 T::regs().cr1().modify(|reg| reg.set_stop(true)); 320 // Wait for STOP condition to transmit.
333 // Wait for STOP condition to transmit. 321 while T::regs().cr1().read().stop() {
334 while T::regs().cr1().read().stop() { 322 check_timeout()?;
335 check_timeout()?; 323 }
336 }
337 };
338 324
339 // Fallthrough is success 325 // Fallthrough is success
340 Ok(()) 326 Ok(())
@@ -351,7 +337,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
351 read: &mut [u8], 337 read: &mut [u8],
352 check_timeout: impl Fn() -> Result<(), Error>, 338 check_timeout: impl Fn() -> Result<(), Error>,
353 ) -> Result<(), Error> { 339 ) -> Result<(), Error> {
354 unsafe { self.write_bytes(addr, write, &check_timeout)? }; 340 self.write_bytes(addr, write, &check_timeout)?;
355 self.blocking_read_timeout(addr, read, &check_timeout)?; 341 self.blocking_read_timeout(addr, read, &check_timeout)?;
356 342
357 Ok(()) 343 Ok(())
@@ -478,8 +464,6 @@ impl Timings {
478 assert!(freq >= 2 && freq <= 50); 464 assert!(freq >= 2 && freq <= 50);
479 465
480 // Configure bus frequency into I2C peripheral 466 // Configure bus frequency into I2C peripheral
481 //self.i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) });
482
483 let trise = if speed <= 100_000 { 467 let trise = if speed <= 100_000 {
484 freq + 1 468 freq + 1
485 } else { 469 } else {
@@ -539,18 +523,16 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
539 type Config = Hertz; 523 type Config = Hertz;
540 fn set_config(&mut self, config: &Self::Config) { 524 fn set_config(&mut self, config: &Self::Config) {
541 let timings = Timings::new(T::frequency(), *config); 525 let timings = Timings::new(T::frequency(), *config);
542 unsafe { 526 T::regs().cr2().modify(|reg| {
543 T::regs().cr2().modify(|reg| { 527 reg.set_freq(timings.freq);
544 reg.set_freq(timings.freq); 528 });
545 }); 529 T::regs().ccr().modify(|reg| {
546 T::regs().ccr().modify(|reg| { 530 reg.set_f_s(timings.mode.f_s());
547 reg.set_f_s(timings.mode.f_s()); 531 reg.set_duty(timings.duty.duty());
548 reg.set_duty(timings.duty.duty()); 532 reg.set_ccr(timings.ccr);
549 reg.set_ccr(timings.ccr); 533 });
550 }); 534 T::regs().trise().modify(|reg| {
551 T::regs().trise().modify(|reg| { 535 reg.set_trise(timings.trise);
552 reg.set_trise(timings.trise); 536 });
553 });
554 }
555 } 537 }
556} 538}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 10f57f700..1f036d55c 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -3,7 +3,6 @@ use core::future::poll_fn;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_cortex_m::interrupt::Interrupt;
7use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
8use embassy_hal_common::drop::OnDrop; 7use embassy_hal_common::drop::OnDrop;
9use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
@@ -13,6 +12,7 @@ use crate::dma::{NoDma, Transfer};
13use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
14use crate::gpio::Pull; 13use crate::gpio::Pull;
15use crate::i2c::{Error, Instance, SclPin, SdaPin}; 14use crate::i2c::{Error, Instance, SclPin, SdaPin};
15use crate::interrupt::typelevel::Interrupt;
16use crate::pac::i2c; 16use crate::pac::i2c;
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{interrupt, Peripheral}; 18use crate::{interrupt, Peripheral};
@@ -22,7 +22,7 @@ pub struct InterruptHandler<T: Instance> {
22 _phantom: PhantomData<T>, 22 _phantom: PhantomData<T>,
23} 23}
24 24
25impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 25impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
26 unsafe fn on_interrupt() { 26 unsafe fn on_interrupt() {
27 let regs = T::regs(); 27 let regs = T::regs();
28 let isr = regs.isr().read(); 28 let isr = regs.isr().read();
@@ -78,7 +78,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
78 peri: impl Peripheral<P = T> + 'd, 78 peri: impl Peripheral<P = T> + 'd,
79 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 79 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
80 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 80 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
81 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 81 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
82 tx_dma: impl Peripheral<P = TXDMA> + 'd, 82 tx_dma: impl Peripheral<P = TXDMA> + 'd,
83 rx_dma: impl Peripheral<P = RXDMA> + 'd, 83 rx_dma: impl Peripheral<P = RXDMA> + 'd,
84 freq: Hertz, 84 freq: Hertz,
@@ -89,49 +89,41 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
89 T::enable(); 89 T::enable();
90 T::reset(); 90 T::reset();
91 91
92 unsafe { 92 scl.set_as_af_pull(
93 scl.set_as_af_pull( 93 scl.af_num(),
94 scl.af_num(), 94 AFType::OutputOpenDrain,
95 AFType::OutputOpenDrain, 95 match config.scl_pullup {
96 match config.scl_pullup { 96 true => Pull::Up,
97 true => Pull::Up, 97 false => Pull::None,
98 false => Pull::None, 98 },
99 }, 99 );
100 ); 100 sda.set_as_af_pull(
101 sda.set_as_af_pull( 101 sda.af_num(),
102 sda.af_num(), 102 AFType::OutputOpenDrain,
103 AFType::OutputOpenDrain, 103 match config.sda_pullup {
104 match config.sda_pullup { 104 true => Pull::Up,
105 true => Pull::Up, 105 false => Pull::None,
106 false => Pull::None, 106 },
107 }, 107 );
108 ); 108
109 } 109 T::regs().cr1().modify(|reg| {
110 110 reg.set_pe(false);
111 unsafe { 111 reg.set_anfoff(false);
112 T::regs().cr1().modify(|reg| { 112 });
113 reg.set_pe(false);
114 reg.set_anfoff(false);
115 });
116 }
117 113
118 let timings = Timings::new(T::frequency(), freq.into()); 114 let timings = Timings::new(T::frequency(), freq.into());
119 115
120 unsafe { 116 T::regs().timingr().write(|reg| {
121 T::regs().timingr().write(|reg| { 117 reg.set_presc(timings.prescale);
122 reg.set_presc(timings.prescale); 118 reg.set_scll(timings.scll);
123 reg.set_scll(timings.scll); 119 reg.set_sclh(timings.sclh);
124 reg.set_sclh(timings.sclh); 120 reg.set_sdadel(timings.sdadel);
125 reg.set_sdadel(timings.sdadel); 121 reg.set_scldel(timings.scldel);
126 reg.set_scldel(timings.scldel); 122 });
127 });
128 }
129 123
130 unsafe { 124 T::regs().cr1().modify(|reg| {
131 T::regs().cr1().modify(|reg| { 125 reg.set_pe(true);
132 reg.set_pe(true); 126 });
133 });
134 }
135 127
136 T::Interrupt::unpend(); 128 T::Interrupt::unpend();
137 unsafe { T::Interrupt::enable() }; 129 unsafe { T::Interrupt::enable() };
@@ -144,12 +136,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
144 } 136 }
145 137
146 fn master_stop(&mut self) { 138 fn master_stop(&mut self) {
147 unsafe { 139 T::regs().cr2().write(|w| w.set_stop(true));
148 T::regs().cr2().write(|w| w.set_stop(true));
149 }
150 } 140 }
151 141
152 unsafe fn master_read( 142 fn master_read(
153 address: u8, 143 address: u8,
154 length: usize, 144 length: usize,
155 stop: Stop, 145 stop: Stop,
@@ -191,7 +181,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
191 Ok(()) 181 Ok(())
192 } 182 }
193 183
194 unsafe fn master_write( 184 fn master_write(
195 address: u8, 185 address: u8,
196 length: usize, 186 length: usize,
197 stop: Stop, 187 stop: Stop,
@@ -229,7 +219,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
229 Ok(()) 219 Ok(())
230 } 220 }
231 221
232 unsafe fn master_continue( 222 fn master_continue(
233 length: usize, 223 length: usize,
234 reload: bool, 224 reload: bool,
235 check_timeout: impl Fn() -> Result<(), Error>, 225 check_timeout: impl Fn() -> Result<(), Error>,
@@ -259,13 +249,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
259 //$i2c.txdr.write(|w| w.txdata().bits(0)); 249 //$i2c.txdr.write(|w| w.txdata().bits(0));
260 //} 250 //}
261 251
262 unsafe { 252 if T::regs().isr().read().txis() {
263 if T::regs().isr().read().txis() { 253 T::regs().txdr().write(|w| w.set_txdata(0));
264 T::regs().txdr().write(|w| w.set_txdata(0)); 254 }
265 } 255 if !T::regs().isr().read().txe() {
266 if !T::regs().isr().read().txe() { 256 T::regs().isr().modify(|w| w.set_txe(true))
267 T::regs().isr().modify(|w| w.set_txe(true))
268 }
269 } 257 }
270 258
271 // If TXDR is not flagged as empty, write 1 to flush it 259 // If TXDR is not flagged as empty, write 1 to flush it
@@ -276,21 +264,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
276 264
277 fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 265 fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
278 loop { 266 loop {
279 unsafe { 267 let isr = T::regs().isr().read();
280 let isr = T::regs().isr().read(); 268 if isr.txe() {
281 if isr.txe() { 269 return Ok(());
282 return Ok(()); 270 } else if isr.berr() {
283 } else if isr.berr() { 271 T::regs().icr().write(|reg| reg.set_berrcf(true));
284 T::regs().icr().write(|reg| reg.set_berrcf(true)); 272 return Err(Error::Bus);
285 return Err(Error::Bus); 273 } else if isr.arlo() {
286 } else if isr.arlo() { 274 T::regs().icr().write(|reg| reg.set_arlocf(true));
287 T::regs().icr().write(|reg| reg.set_arlocf(true)); 275 return Err(Error::Arbitration);
288 return Err(Error::Arbitration); 276 } else if isr.nackf() {
289 } else if isr.nackf() { 277 T::regs().icr().write(|reg| reg.set_nackcf(true));
290 T::regs().icr().write(|reg| reg.set_nackcf(true)); 278 self.flush_txdr();
291 self.flush_txdr(); 279 return Err(Error::Nack);
292 return Err(Error::Nack);
293 }
294 } 280 }
295 281
296 check_timeout()?; 282 check_timeout()?;
@@ -299,21 +285,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
299 285
300 fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 286 fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
301 loop { 287 loop {
302 unsafe { 288 let isr = T::regs().isr().read();
303 let isr = T::regs().isr().read(); 289 if isr.rxne() {
304 if isr.rxne() { 290 return Ok(());
305 return Ok(()); 291 } else if isr.berr() {
306 } else if isr.berr() { 292 T::regs().icr().write(|reg| reg.set_berrcf(true));
307 T::regs().icr().write(|reg| reg.set_berrcf(true)); 293 return Err(Error::Bus);
308 return Err(Error::Bus); 294 } else if isr.arlo() {
309 } else if isr.arlo() { 295 T::regs().icr().write(|reg| reg.set_arlocf(true));
310 T::regs().icr().write(|reg| reg.set_arlocf(true)); 296 return Err(Error::Arbitration);
311 return Err(Error::Arbitration); 297 } else if isr.nackf() {
312 } else if isr.nackf() { 298 T::regs().icr().write(|reg| reg.set_nackcf(true));
313 T::regs().icr().write(|reg| reg.set_nackcf(true)); 299 self.flush_txdr();
314 self.flush_txdr(); 300 return Err(Error::Nack);
315 return Err(Error::Nack);
316 }
317 } 301 }
318 302
319 check_timeout()?; 303 check_timeout()?;
@@ -322,21 +306,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
322 306
323 fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 307 fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
324 loop { 308 loop {
325 unsafe { 309 let isr = T::regs().isr().read();
326 let isr = T::regs().isr().read(); 310 if isr.tc() {
327 if isr.tc() { 311 return Ok(());
328 return Ok(()); 312 } else if isr.berr() {
329 } else if isr.berr() { 313 T::regs().icr().write(|reg| reg.set_berrcf(true));
330 T::regs().icr().write(|reg| reg.set_berrcf(true)); 314 return Err(Error::Bus);
331 return Err(Error::Bus); 315 } else if isr.arlo() {
332 } else if isr.arlo() { 316 T::regs().icr().write(|reg| reg.set_arlocf(true));
333 T::regs().icr().write(|reg| reg.set_arlocf(true)); 317 return Err(Error::Arbitration);
334 return Err(Error::Arbitration); 318 } else if isr.nackf() {
335 } else if isr.nackf() { 319 T::regs().icr().write(|reg| reg.set_nackcf(true));
336 T::regs().icr().write(|reg| reg.set_nackcf(true)); 320 self.flush_txdr();
337 self.flush_txdr(); 321 return Err(Error::Nack);
338 return Err(Error::Nack);
339 }
340 } 322 }
341 323
342 check_timeout()?; 324 check_timeout()?;
@@ -358,32 +340,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
358 }; 340 };
359 let last_chunk_idx = total_chunks.saturating_sub(1); 341 let last_chunk_idx = total_chunks.saturating_sub(1);
360 342
361 unsafe { 343 Self::master_read(
362 Self::master_read( 344 address,
363 address, 345 read.len().min(255),
364 read.len().min(255), 346 Stop::Automatic,
365 Stop::Automatic, 347 last_chunk_idx != 0,
366 last_chunk_idx != 0, 348 restart,
367 restart, 349 &check_timeout,
368 &check_timeout, 350 )?;
369 )?;
370 }
371 351
372 for (number, chunk) in read.chunks_mut(255).enumerate() { 352 for (number, chunk) in read.chunks_mut(255).enumerate() {
373 if number != 0 { 353 if number != 0 {
374 // NOTE(unsafe) We have &mut self 354 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
375 unsafe {
376 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
377 }
378 } 355 }
379 356
380 for byte in chunk { 357 for byte in chunk {
381 // Wait until we have received something 358 // Wait until we have received something
382 self.wait_rxne(&check_timeout)?; 359 self.wait_rxne(&check_timeout)?;
383 360
384 unsafe { 361 *byte = T::regs().rxdr().read().rxdata();
385 *byte = T::regs().rxdr().read().rxdata();
386 }
387 } 362 }
388 } 363 }
389 Ok(()) 364 Ok(())
@@ -407,23 +382,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
407 // I2C start 382 // I2C start
408 // 383 //
409 // ST SAD+W 384 // ST SAD+W
410 // NOTE(unsafe) We have &mut self 385 Self::master_write(
411 unsafe { 386 address,
412 Self::master_write( 387 write.len().min(255),
413 address, 388 Stop::Software,
414 write.len().min(255), 389 last_chunk_idx != 0,
415 Stop::Software, 390 &check_timeout,
416 last_chunk_idx != 0, 391 )?;
417 &check_timeout,
418 )?;
419 }
420 392
421 for (number, chunk) in write.chunks(255).enumerate() { 393 for (number, chunk) in write.chunks(255).enumerate() {
422 if number != 0 { 394 if number != 0 {
423 // NOTE(unsafe) We have &mut self 395 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
424 unsafe {
425 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
426 }
427 } 396 }
428 397
429 for byte in chunk { 398 for byte in chunk {
@@ -432,9 +401,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
432 // through) 401 // through)
433 self.wait_txe(&check_timeout)?; 402 self.wait_txe(&check_timeout)?;
434 403
435 unsafe { 404 T::regs().txdr().write(|w| w.set_txdata(*byte));
436 T::regs().txdr().write(|w| w.set_txdata(*byte));
437 }
438 } 405 }
439 } 406 }
440 // Wait until the write finishes 407 // Wait until the write finishes
@@ -467,7 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
467 w.set_tcie(true); 434 w.set_tcie(true);
468 } 435 }
469 }); 436 });
470 let dst = regs.txdr().ptr() as *mut u8; 437 let dst = regs.txdr().as_ptr() as *mut u8;
471 438
472 let ch = &mut self.tx_dma; 439 let ch = &mut self.tx_dma;
473 let request = ch.request(); 440 let request = ch.request();
@@ -479,37 +446,30 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
479 446
480 let on_drop = OnDrop::new(|| { 447 let on_drop = OnDrop::new(|| {
481 let regs = T::regs(); 448 let regs = T::regs();
482 unsafe { 449 regs.cr1().modify(|w| {
483 regs.cr1().modify(|w| { 450 if last_slice {
484 if last_slice { 451 w.set_txdmaen(false);
485 w.set_txdmaen(false); 452 }
486 } 453 w.set_tcie(false);
487 w.set_tcie(false); 454 })
488 })
489 }
490 }); 455 });
491 456
492 poll_fn(|cx| { 457 poll_fn(|cx| {
493 state.waker.register(cx.waker()); 458 state.waker.register(cx.waker());
494 459
495 let isr = unsafe { T::regs().isr().read() }; 460 let isr = T::regs().isr().read();
496 if remaining_len == total_len { 461 if remaining_len == total_len {
497 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
498 if first_slice { 462 if first_slice {
499 unsafe { 463 Self::master_write(
500 Self::master_write( 464 address,
501 address, 465 total_len.min(255),
502 total_len.min(255), 466 Stop::Software,
503 Stop::Software, 467 (total_len > 255) || !last_slice,
504 (total_len > 255) || !last_slice, 468 &check_timeout,
505 &check_timeout, 469 )?;
506 )?;
507 }
508 } else { 470 } else {
509 unsafe { 471 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?;
510 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; 472 T::regs().cr1().modify(|w| w.set_tcie(true));
511 T::regs().cr1().modify(|w| w.set_tcie(true));
512 }
513 } 473 }
514 } else if !(isr.tcr() || isr.tc()) { 474 } else if !(isr.tcr() || isr.tc()) {
515 // poll_fn was woken without an interrupt present 475 // poll_fn was woken without an interrupt present
@@ -519,13 +479,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
519 } else { 479 } else {
520 let last_piece = (remaining_len <= 255) && last_slice; 480 let last_piece = (remaining_len <= 255) && last_slice;
521 481
522 // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers 482 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
523 unsafe { 483 return Poll::Ready(Err(e));
524 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
525 return Poll::Ready(Err(e));
526 }
527 T::regs().cr1().modify(|w| w.set_tcie(true));
528 } 484 }
485 T::regs().cr1().modify(|w| w.set_tcie(true));
529 } 486 }
530 487
531 remaining_len = remaining_len.saturating_sub(255); 488 remaining_len = remaining_len.saturating_sub(255);
@@ -564,7 +521,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
564 w.set_rxdmaen(true); 521 w.set_rxdmaen(true);
565 w.set_tcie(true); 522 w.set_tcie(true);
566 }); 523 });
567 let src = regs.rxdr().ptr() as *mut u8; 524 let src = regs.rxdr().as_ptr() as *mut u8;
568 525
569 let ch = &mut self.rx_dma; 526 let ch = &mut self.rx_dma;
570 let request = ch.request(); 527 let request = ch.request();
@@ -576,30 +533,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
576 533
577 let on_drop = OnDrop::new(|| { 534 let on_drop = OnDrop::new(|| {
578 let regs = T::regs(); 535 let regs = T::regs();
579 unsafe { 536 regs.cr1().modify(|w| {
580 regs.cr1().modify(|w| { 537 w.set_rxdmaen(false);
581 w.set_rxdmaen(false); 538 w.set_tcie(false);
582 w.set_tcie(false); 539 })
583 })
584 }
585 }); 540 });
586 541
587 poll_fn(|cx| { 542 poll_fn(|cx| {
588 state.waker.register(cx.waker()); 543 state.waker.register(cx.waker());
589 544
590 let isr = unsafe { T::regs().isr().read() }; 545 let isr = T::regs().isr().read();
591 if remaining_len == total_len { 546 if remaining_len == total_len {
592 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers 547 Self::master_read(
593 unsafe { 548 address,
594 Self::master_read( 549 total_len.min(255),
595 address, 550 Stop::Software,
596 total_len.min(255), 551 total_len > 255,
597 Stop::Software, 552 restart,
598 total_len > 255, 553 &check_timeout,
599 restart, 554 )?;
600 &check_timeout,
601 )?;
602 }
603 } else if !(isr.tcr() || isr.tc()) { 555 } else if !(isr.tcr() || isr.tc()) {
604 // poll_fn was woken without an interrupt present 556 // poll_fn was woken without an interrupt present
605 return Poll::Pending; 557 return Poll::Pending;
@@ -608,13 +560,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
608 } else { 560 } else {
609 let last_piece = remaining_len <= 255; 561 let last_piece = remaining_len <= 255;
610 562
611 // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers 563 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
612 unsafe { 564 return Poll::Ready(Err(e));
613 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
614 return Poll::Ready(Err(e));
615 }
616 T::regs().cr1().modify(|w| w.set_tcie(true));
617 } 565 }
566 T::regs().cr1().modify(|w| w.set_tcie(true));
618 } 567 }
619 568
620 remaining_len = remaining_len.saturating_sub(255); 569 remaining_len = remaining_len.saturating_sub(255);
@@ -758,16 +707,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
758 let first_length = write[0].len(); 707 let first_length = write[0].len();
759 let last_slice_index = write.len() - 1; 708 let last_slice_index = write.len() - 1;
760 709
761 // NOTE(unsafe) We have &mut self 710 Self::master_write(
762 unsafe { 711 address,
763 Self::master_write( 712 first_length.min(255),
764 address, 713 Stop::Software,
765 first_length.min(255), 714 (first_length > 255) || (last_slice_index != 0),
766 Stop::Software, 715 &check_timeout,
767 (first_length > 255) || (last_slice_index != 0), 716 )?;
768 &check_timeout,
769 )?;
770 }
771 717
772 for (idx, slice) in write.iter().enumerate() { 718 for (idx, slice) in write.iter().enumerate() {
773 let slice_len = slice.len(); 719 let slice_len = slice.len();
@@ -780,26 +726,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
780 let last_chunk_idx = total_chunks.saturating_sub(1); 726 let last_chunk_idx = total_chunks.saturating_sub(1);
781 727
782 if idx != 0 { 728 if idx != 0 {
783 // NOTE(unsafe) We have &mut self 729 Self::master_continue(
784 unsafe { 730 slice_len.min(255),
785 Self::master_continue( 731 (idx != last_slice_index) || (slice_len > 255),
786 slice_len.min(255), 732 &check_timeout,
787 (idx != last_slice_index) || (slice_len > 255), 733 )?;
788 &check_timeout,
789 )?;
790 }
791 } 734 }
792 735
793 for (number, chunk) in slice.chunks(255).enumerate() { 736 for (number, chunk) in slice.chunks(255).enumerate() {
794 if number != 0 { 737 if number != 0 {
795 // NOTE(unsafe) We have &mut self 738 Self::master_continue(
796 unsafe { 739 chunk.len(),
797 Self::master_continue( 740 (number != last_chunk_idx) || (idx != last_slice_index),
798 chunk.len(), 741 &check_timeout,
799 (number != last_chunk_idx) || (idx != last_slice_index), 742 )?;
800 &check_timeout,
801 )?;
802 }
803 } 743 }
804 744
805 for byte in chunk { 745 for byte in chunk {
@@ -810,9 +750,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
810 750
811 // Put byte on the wire 751 // Put byte on the wire
812 //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); 752 //self.i2c.txdr.write(|w| w.txdata().bits(*byte));
813 unsafe { 753 T::regs().txdr().write(|w| w.set_txdata(*byte));
814 T::regs().txdr().write(|w| w.set_txdata(*byte));
815 }
816 } 754 }
817 } 755 }
818 } 756 }
@@ -1061,14 +999,12 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
1061 type Config = Hertz; 999 type Config = Hertz;
1062 fn set_config(&mut self, config: &Self::Config) { 1000 fn set_config(&mut self, config: &Self::Config) {
1063 let timings = Timings::new(T::frequency(), *config); 1001 let timings = Timings::new(T::frequency(), *config);
1064 unsafe { 1002 T::regs().timingr().write(|reg| {
1065 T::regs().timingr().write(|reg| { 1003 reg.set_presc(timings.prescale);
1066 reg.set_presc(timings.prescale); 1004 reg.set_scll(timings.scll);
1067 reg.set_scll(timings.scll); 1005 reg.set_sclh(timings.sclh);
1068 reg.set_sclh(timings.sclh); 1006 reg.set_sdadel(timings.sdadel);
1069 reg.set_sdadel(timings.sdadel); 1007 reg.set_scldel(timings.scldel);
1070 reg.set_scldel(timings.scldel); 1008 });
1071 });
1072 }
1073 } 1009 }
1074} 1010}
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 2bb199f68..62dda69b4 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -153,19 +153,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
153 ) -> Self { 153 ) -> Self {
154 into_ref!(sd, ws, ck, mck); 154 into_ref!(sd, ws, ck, mck);
155 155
156 unsafe { 156 sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
157 sd.set_as_af(sd.af_num(), AFType::OutputPushPull); 157 sd.set_speed(crate::gpio::Speed::VeryHigh);
158 sd.set_speed(crate::gpio::Speed::VeryHigh);
159 158
160 ws.set_as_af(ws.af_num(), AFType::OutputPushPull); 159 ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
161 ws.set_speed(crate::gpio::Speed::VeryHigh); 160 ws.set_speed(crate::gpio::Speed::VeryHigh);
162 161
163 ck.set_as_af(ck.af_num(), AFType::OutputPushPull); 162 ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
164 ck.set_speed(crate::gpio::Speed::VeryHigh); 163 ck.set_speed(crate::gpio::Speed::VeryHigh);
165 164
166 mck.set_as_af(mck.af_num(), AFType::OutputPushPull); 165 mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
167 mck.set_speed(crate::gpio::Speed::VeryHigh); 166 mck.set_speed(crate::gpio::Speed::VeryHigh);
168 }
169 167
170 let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default()); 168 let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default());
171 169
@@ -178,7 +176,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
178 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); 176 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
179 177
180 #[cfg(any(spi_v1, spi_f1))] 178 #[cfg(any(spi_v1, spi_f1))]
181 unsafe { 179 {
182 use stm32_metapac::spi::vals::{I2scfg, Odd}; 180 use stm32_metapac::spi::vals::{I2scfg, Odd};
183 181
184 // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud 182 // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
@@ -232,10 +230,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
232 w.set_i2se(true) 230 w.set_i2se(true)
233 }); 231 });
234 } 232 }
235 #[cfg(spi_v2)]
236 unsafe {}
237 #[cfg(any(spi_v3, spi_v4))]
238 unsafe {}
239 233
240 Self { 234 Self {
241 _peri: spi, 235 _peri: spi,
@@ -264,12 +258,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
264 258
265impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { 259impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> {
266 fn drop(&mut self) { 260 fn drop(&mut self) {
267 unsafe { 261 self.sd.as_ref().map(|x| x.set_as_disconnected());
268 self.sd.as_ref().map(|x| x.set_as_disconnected()); 262 self.ws.as_ref().map(|x| x.set_as_disconnected());
269 self.ws.as_ref().map(|x| x.set_as_disconnected()); 263 self.ck.as_ref().map(|x| x.set_as_disconnected());
270 self.ck.as_ref().map(|x| x.set_as_disconnected()); 264 self.mck.as_ref().map(|x| x.set_as_disconnected());
271 self.mck.as_ref().map(|x| x.set_as_disconnected());
272 }
273 } 265 }
274} 266}
275 267
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
new file mode 100644
index 000000000..37f840c73
--- /dev/null
+++ b/embassy-stm32/src/ipcc.rs
@@ -0,0 +1,335 @@
1use core::future::poll_fn;
2use core::task::Poll;
3
4use atomic_polyfill::{compiler_fence, Ordering};
5
6use self::sealed::Instance;
7use crate::interrupt;
8use crate::interrupt::typelevel::Interrupt;
9use crate::peripherals::IPCC;
10use crate::rcc::sealed::RccPeripheral;
11
12/// Interrupt handler.
13pub struct ReceiveInterruptHandler {}
14
15impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
16 unsafe fn on_interrupt() {
17 let regs = IPCC::regs();
18
19 let channels = [
20 IpccChannel::Channel1,
21 IpccChannel::Channel2,
22 IpccChannel::Channel3,
23 IpccChannel::Channel4,
24 IpccChannel::Channel5,
25 IpccChannel::Channel6,
26 ];
27
28 // Status register gives channel occupied status. For rx, use cpu1.
29 let sr = regs.cpu(1).sr().read();
30 regs.cpu(0).mr().modify(|w| {
31 for channel in channels {
32 if sr.chf(channel as usize) {
33 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
34 w.set_chom(channel as usize, true);
35
36 // There shouldn't be a race because the channel is masked only if the interrupt has fired
37 IPCC::state().rx_waker_for(channel).wake();
38 }
39 }
40 })
41 }
42}
43
44pub struct TransmitInterruptHandler {}
45
46impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
47 unsafe fn on_interrupt() {
48 let regs = IPCC::regs();
49
50 let channels = [
51 IpccChannel::Channel1,
52 IpccChannel::Channel2,
53 IpccChannel::Channel3,
54 IpccChannel::Channel4,
55 IpccChannel::Channel5,
56 IpccChannel::Channel6,
57 ];
58
59 // Status register gives channel occupied status. For tx, use cpu0.
60 let sr = regs.cpu(0).sr().read();
61 regs.cpu(0).mr().modify(|w| {
62 for channel in channels {
63 if !sr.chf(channel as usize) {
64 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
65 w.set_chfm(channel as usize, true);
66
67 // There shouldn't be a race because the channel is masked only if the interrupt has fired
68 IPCC::state().tx_waker_for(channel).wake();
69 }
70 }
71 });
72 }
73}
74
75#[non_exhaustive]
76#[derive(Clone, Copy, Default)]
77pub struct Config {
78 // TODO: add IPCC peripheral configuration, if any, here
79 // reserved for future use
80}
81
82#[derive(Debug, Clone, Copy)]
83#[repr(C)]
84pub enum IpccChannel {
85 Channel1 = 0,
86 Channel2 = 1,
87 Channel3 = 2,
88 Channel4 = 3,
89 Channel5 = 4,
90 Channel6 = 5,
91}
92
93pub struct Ipcc;
94
95impl Ipcc {
96 pub fn enable(_config: Config) {
97 IPCC::enable();
98 IPCC::reset();
99 IPCC::set_cpu2(true);
100
101 _configure_pwr();
102
103 let regs = IPCC::regs();
104
105 regs.cpu(0).cr().modify(|w| {
106 w.set_rxoie(true);
107 w.set_txfie(true);
108 });
109
110 // enable interrupts
111 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
112 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
113
114 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
115 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
116 }
117
118 /// Send data to an IPCC channel. The closure is called to write the data when appropriate.
119 pub async fn send(channel: IpccChannel, f: impl FnOnce()) {
120 let regs = IPCC::regs();
121
122 Self::flush(channel).await;
123
124 f();
125
126 compiler_fence(Ordering::SeqCst);
127
128 trace!("ipcc: ch {}: send data", channel as u8);
129 regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true));
130 }
131
132 /// Wait for the tx channel to become clear
133 pub async fn flush(channel: IpccChannel) {
134 let regs = IPCC::regs();
135
136 // This is a race, but is nice for debugging
137 if regs.cpu(0).sr().read().chf(channel as usize) {
138 trace!("ipcc: ch {}: wait for tx free", channel as u8);
139 }
140
141 poll_fn(|cx| {
142 IPCC::state().tx_waker_for(channel).register(cx.waker());
143 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
144 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false));
145
146 compiler_fence(Ordering::SeqCst);
147
148 if !regs.cpu(0).sr().read().chf(channel as usize) {
149 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
150 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
151
152 Poll::Ready(())
153 } else {
154 Poll::Pending
155 }
156 })
157 .await;
158 }
159
160 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
161 pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R {
162 let regs = IPCC::regs();
163
164 loop {
165 // This is a race, but is nice for debugging
166 if !regs.cpu(1).sr().read().chf(channel as usize) {
167 trace!("ipcc: ch {}: wait for rx occupied", channel as u8);
168 }
169
170 poll_fn(|cx| {
171 IPCC::state().rx_waker_for(channel).register(cx.waker());
172 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
173 regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false));
174
175 compiler_fence(Ordering::SeqCst);
176
177 if regs.cpu(1).sr().read().chf(channel as usize) {
178 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
179 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
180
181 Poll::Ready(())
182 } else {
183 Poll::Pending
184 }
185 })
186 .await;
187
188 trace!("ipcc: ch {}: read data", channel as u8);
189
190 match f() {
191 Some(ret) => return ret,
192 None => {}
193 }
194
195 trace!("ipcc: ch {}: clear rx", channel as u8);
196 compiler_fence(Ordering::SeqCst);
197 // If the channel is clear and the read function returns none, fetch more data
198 regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true));
199 }
200 }
201}
202
203impl sealed::Instance for crate::peripherals::IPCC {
204 fn regs() -> crate::pac::ipcc::Ipcc {
205 crate::pac::IPCC
206 }
207
208 fn set_cpu2(enabled: bool) {
209 crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled));
210 }
211
212 fn state() -> &'static self::sealed::State {
213 static STATE: self::sealed::State = self::sealed::State::new();
214 &STATE
215 }
216}
217
218pub(crate) mod sealed {
219 use embassy_sync::waitqueue::AtomicWaker;
220
221 use super::*;
222
223 pub struct State {
224 rx_wakers: [AtomicWaker; 6],
225 tx_wakers: [AtomicWaker; 6],
226 }
227
228 impl State {
229 pub const fn new() -> Self {
230 const WAKER: AtomicWaker = AtomicWaker::new();
231
232 Self {
233 rx_wakers: [WAKER; 6],
234 tx_wakers: [WAKER; 6],
235 }
236 }
237
238 pub const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
239 match channel {
240 IpccChannel::Channel1 => &self.rx_wakers[0],
241 IpccChannel::Channel2 => &self.rx_wakers[1],
242 IpccChannel::Channel3 => &self.rx_wakers[2],
243 IpccChannel::Channel4 => &self.rx_wakers[3],
244 IpccChannel::Channel5 => &self.rx_wakers[4],
245 IpccChannel::Channel6 => &self.rx_wakers[5],
246 }
247 }
248
249 pub const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
250 match channel {
251 IpccChannel::Channel1 => &self.tx_wakers[0],
252 IpccChannel::Channel2 => &self.tx_wakers[1],
253 IpccChannel::Channel3 => &self.tx_wakers[2],
254 IpccChannel::Channel4 => &self.tx_wakers[3],
255 IpccChannel::Channel5 => &self.tx_wakers[4],
256 IpccChannel::Channel6 => &self.tx_wakers[5],
257 }
258 }
259 }
260
261 pub trait Instance: crate::rcc::RccPeripheral {
262 fn regs() -> crate::pac::ipcc::Ipcc;
263 fn set_cpu2(enabled: bool);
264 fn state() -> &'static State;
265 }
266}
267
268fn _configure_pwr() {
269 // TODO: move this to RCC
270
271 let pwr = crate::pac::PWR;
272 let rcc = crate::pac::RCC;
273
274 rcc.cfgr().modify(|w| w.set_stopwuck(true));
275
276 pwr.cr1().modify(|w| w.set_dbp(true));
277 pwr.cr1().modify(|w| w.set_dbp(true));
278
279 // configure LSE
280 rcc.bdcr().modify(|w| w.set_lseon(true));
281
282 // select system clock source = PLL
283 // set PLL coefficients
284 // m: 2,
285 // n: 12,
286 // r: 3,
287 // q: 4,
288 // p: 3,
289 let src_bits = 0b11;
290 let pllp = (3 - 1) & 0b11111;
291 let pllq = (4 - 1) & 0b111;
292 let pllr = (3 - 1) & 0b111;
293 let plln = 12 & 0b1111111;
294 let pllm = (2 - 1) & 0b111;
295 rcc.pllcfgr().modify(|w| {
296 w.set_pllsrc(src_bits);
297 w.set_pllm(pllm);
298 w.set_plln(plln);
299 w.set_pllr(pllr);
300 w.set_pllp(pllp);
301 w.set_pllpen(true);
302 w.set_pllq(pllq);
303 w.set_pllqen(true);
304 });
305 // enable PLL
306 rcc.cr().modify(|w| w.set_pllon(true));
307 rcc.cr().write(|w| w.set_hsion(false));
308 // while !rcc.cr().read().pllrdy() {}
309
310 // configure SYSCLK mux to use PLL clocl
311 rcc.cfgr().modify(|w| w.set_sw(0b11));
312
313 // configure CPU1 & CPU2 dividers
314 rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided
315 rcc.extcfgr().modify(|w| {
316 w.set_c2hpre(0b1000); // div2
317 w.set_shdhpre(0); // not divided
318 });
319
320 // apply APB1 / APB2 values
321 rcc.cfgr().modify(|w| {
322 w.set_ppre1(0b000); // not divided
323 w.set_ppre2(0b000); // not divided
324 });
325
326 // TODO: required
327 // set RF wake-up clock = LSE
328 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
329
330 // set LPTIM1 & LPTIM2 clock source
331 rcc.ccipr().modify(|w| {
332 w.set_lptim1sel(0b00); // PCLK
333 w.set_lptim2sel(0b00); // PCLK
334 });
335}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 75d8af3dd..45a7b5476 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -41,6 +41,8 @@ pub mod crc;
41pub mod flash; 41pub mod flash;
42#[cfg(all(spi_v1, rcc_f4))] 42#[cfg(all(spi_v1, rcc_f4))]
43pub mod i2s; 43pub mod i2s;
44#[cfg(stm32wb)]
45pub mod ipcc;
44pub mod pwm; 46pub mod pwm;
45#[cfg(quadspi)] 47#[cfg(quadspi)]
46pub mod qspi; 48pub mod qspi;
@@ -52,8 +54,6 @@ pub mod rtc;
52pub mod sdmmc; 54pub mod sdmmc;
53#[cfg(spi)] 55#[cfg(spi)]
54pub mod spi; 56pub mod spi;
55#[cfg(stm32wb)]
56pub mod tl_mbox;
57#[cfg(usart)] 57#[cfg(usart)]
58pub mod usart; 58pub mod usart;
59#[cfg(usb)] 59#[cfg(usb)]
@@ -72,52 +72,47 @@ pub(crate) mod _generated {
72 include!(concat!(env!("OUT_DIR"), "/_generated.rs")); 72 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
73} 73}
74 74
75pub mod interrupt { 75pub use crate::_generated::interrupt;
76 //! Interrupt definitions and macros to bind them. 76
77 pub use cortex_m::interrupt::{CriticalSection, Mutex}; 77/// Macro to bind interrupts to handlers.
78 pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, Priority}; 78///
79 79/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
80 pub use crate::_generated::interrupt::*; 80/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
81 81/// prove at compile-time that the right interrupts have been bound.
82 /// Macro to bind interrupts to handlers. 82// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
83 /// 83#[macro_export]
84 /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) 84macro_rules! bind_interrupts {
85 /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to 85 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
86 /// prove at compile-time that the right interrupts have been bound. 86 $vis struct $name;
87 // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. 87
88 #[macro_export] 88 $(
89 macro_rules! bind_interrupts { 89 #[allow(non_snake_case)]
90 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 90 #[no_mangle]
91 $vis struct $name; 91 unsafe extern "C" fn $irq() {
92
93 $(
94 #[allow(non_snake_case)]
95 #[no_mangle]
96 unsafe extern "C" fn $irq() {
97 $(
98 <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
99 )*
100 }
101
102 $( 92 $(
103 unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} 93 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
104 )* 94 )*
95 }
96
97 $(
98 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
105 )* 99 )*
106 }; 100 )*
107 } 101 };
108} 102}
109 103
110// Reexports 104// Reexports
111pub use _generated::{peripherals, Peripherals}; 105pub use _generated::{peripherals, Peripherals};
112pub use embassy_cortex_m::executor;
113use embassy_cortex_m::interrupt::Priority;
114pub use embassy_cortex_m::interrupt::_export::interrupt;
115pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 106pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
116#[cfg(feature = "unstable-pac")] 107#[cfg(feature = "unstable-pac")]
117pub use stm32_metapac as pac; 108pub use stm32_metapac as pac;
118#[cfg(not(feature = "unstable-pac"))] 109#[cfg(not(feature = "unstable-pac"))]
119pub(crate) use stm32_metapac as pac; 110pub(crate) use stm32_metapac as pac;
120 111
112use crate::interrupt::Priority;
113#[cfg(feature = "rt")]
114pub use crate::pac::NVIC_PRIO_BITS;
115
121#[non_exhaustive] 116#[non_exhaustive]
122pub struct Config { 117pub struct Config {
123 pub rcc: rcc::Config, 118 pub rcc: rcc::Config,
@@ -151,35 +146,35 @@ impl Default for Config {
151pub fn init(config: Config) -> Peripherals { 146pub fn init(config: Config) -> Peripherals {
152 let p = Peripherals::take(); 147 let p = Peripherals::take();
153 148
154 unsafe { 149 #[cfg(dbgmcu)]
155 #[cfg(dbgmcu)] 150 if config.enable_debug_during_sleep {
156 if config.enable_debug_during_sleep { 151 crate::pac::DBGMCU.cr().modify(|cr| {
157 crate::pac::DBGMCU.cr().modify(|cr| { 152 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))]
158 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] 153 {
159 { 154 cr.set_dbg_stop(true);
160 cr.set_dbg_stop(true); 155 cr.set_dbg_standby(true);
161 cr.set_dbg_standby(true); 156 }
162 } 157 #[cfg(any(
163 #[cfg(any( 158 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
164 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, 159 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
165 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl 160 ))]
166 ))] 161 {
167 { 162 cr.set_dbg_sleep(true);
168 cr.set_dbg_sleep(true); 163 cr.set_dbg_stop(true);
169 cr.set_dbg_stop(true); 164 cr.set_dbg_standby(true);
170 cr.set_dbg_standby(true); 165 }
171 } 166 #[cfg(dbgmcu_h7)]
172 #[cfg(dbgmcu_h7)] 167 {
173 { 168 cr.set_d1dbgcken(true);
174 cr.set_d1dbgcken(true); 169 cr.set_d3dbgcken(true);
175 cr.set_d3dbgcken(true); 170 cr.set_dbgsleep_d1(true);
176 cr.set_dbgsleep_d1(true); 171 cr.set_dbgstby_d1(true);
177 cr.set_dbgstby_d1(true); 172 cr.set_dbgstop_d1(true);
178 cr.set_dbgstop_d1(true); 173 }
179 } 174 });
180 }); 175 }
181 }
182 176
177 unsafe {
183 gpio::init(); 178 gpio::init();
184 dma::init( 179 dma::init(
185 #[cfg(bdma)] 180 #[cfg(bdma)]
diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs
index cfb79947c..4d64d005c 100644
--- a/embassy-stm32/src/pwm/complementary_pwm.rs
+++ b/embassy-stm32/src/pwm/complementary_pwm.rs
@@ -21,7 +21,7 @@ macro_rules! complementary_channel_impl {
21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { 21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
22 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { 22 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
23 into_ref!(pin); 23 into_ref!(pin);
24 critical_section::with(|_| unsafe { 24 critical_section::with(|_| {
25 pin.set_low(); 25 pin.set_low();
26 pin.set_as_af(pin.af_num(), AFType::OutputPushPull); 26 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
27 #[cfg(gpio_v2)] 27 #[cfg(gpio_v2)]
@@ -72,33 +72,27 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
72 this.inner.set_frequency(freq); 72 this.inner.set_frequency(freq);
73 this.inner.start(); 73 this.inner.start();
74 74
75 unsafe { 75 this.inner.enable_outputs(true);
76 this.inner.enable_outputs(true); 76
77 77 this.inner
78 this.inner 78 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
79 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); 79 this.inner
80 this.inner 80 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
81 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); 81 this.inner
82 this.inner 82 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
83 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); 83 this.inner
84 this.inner 84 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
85 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
86 }
87 this 85 this
88 } 86 }
89 87
90 pub fn enable(&mut self, channel: Channel) { 88 pub fn enable(&mut self, channel: Channel) {
91 unsafe { 89 self.inner.enable_channel(channel, true);
92 self.inner.enable_channel(channel, true); 90 self.inner.enable_complementary_channel(channel, true);
93 self.inner.enable_complementary_channel(channel, true);
94 }
95 } 91 }
96 92
97 pub fn disable(&mut self, channel: Channel) { 93 pub fn disable(&mut self, channel: Channel) {
98 unsafe { 94 self.inner.enable_complementary_channel(channel, false);
99 self.inner.enable_complementary_channel(channel, false); 95 self.inner.enable_channel(channel, false);
100 self.inner.enable_channel(channel, false);
101 }
102 } 96 }
103 97
104 pub fn set_freq(&mut self, freq: Hertz) { 98 pub fn set_freq(&mut self, freq: Hertz) {
@@ -106,22 +100,20 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
106 } 100 }
107 101
108 pub fn get_max_duty(&self) -> u16 { 102 pub fn get_max_duty(&self) -> u16 {
109 unsafe { self.inner.get_max_compare_value() } 103 self.inner.get_max_compare_value()
110 } 104 }
111 105
112 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 106 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
113 assert!(duty < self.get_max_duty()); 107 assert!(duty < self.get_max_duty());
114 unsafe { self.inner.set_compare_value(channel, duty) } 108 self.inner.set_compare_value(channel, duty)
115 } 109 }
116 110
117 /// Set the dead time as a proportion of max_duty 111 /// Set the dead time as a proportion of max_duty
118 pub fn set_dead_time(&mut self, value: u16) { 112 pub fn set_dead_time(&mut self, value: u16) {
119 let (ckd, value) = compute_dead_time_value(value); 113 let (ckd, value) = compute_dead_time_value(value);
120 114
121 unsafe { 115 self.inner.set_dead_time_clock_division(ckd);
122 self.inner.set_dead_time_clock_division(ckd); 116 self.inner.set_dead_time_value(value);
123 self.inner.set_dead_time_value(value);
124 }
125 } 117 }
126} 118}
127 119
@@ -251,7 +243,7 @@ mod tests {
251 for test_run in fn_results { 243 for test_run in fn_results {
252 let (ckd, bits) = compute_dead_time_value(test_run.value); 244 let (ckd, bits) = compute_dead_time_value(test_run.value);
253 245
254 assert_eq!(ckd.0, test_run.ckd.0); 246 assert_eq!(ckd.to_bits(), test_run.ckd.to_bits());
255 assert_eq!(bits, test_run.bits); 247 assert_eq!(bits, test_run.bits);
256 } 248 }
257 } 249 }
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs
index 0bef07089..5aba2663e 100644
--- a/embassy-stm32/src/pwm/mod.rs
+++ b/embassy-stm32/src/pwm/mod.rs
@@ -59,33 +59,33 @@ pub(crate) mod sealed {
59 59
60 pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance { 60 pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance {
61 /// Global output enable. Does not do anything on non-advanced timers. 61 /// Global output enable. Does not do anything on non-advanced timers.
62 unsafe fn enable_outputs(&mut self, enable: bool); 62 fn enable_outputs(&mut self, enable: bool);
63 63
64 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 64 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
65 65
66 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); 66 fn enable_channel(&mut self, channel: Channel, enable: bool);
67 67
68 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16); 68 fn set_compare_value(&mut self, channel: Channel, value: u16);
69 69
70 unsafe fn get_max_compare_value(&self) -> u16; 70 fn get_max_compare_value(&self) -> u16;
71 } 71 }
72 72
73 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { 73 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
74 unsafe fn set_dead_time_clock_division(&mut self, value: Ckd); 74 fn set_dead_time_clock_division(&mut self, value: Ckd);
75 75
76 unsafe fn set_dead_time_value(&mut self, value: u8); 76 fn set_dead_time_value(&mut self, value: u8);
77 77
78 unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); 78 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
79 } 79 }
80 80
81 pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { 81 pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
82 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 82 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
83 83
84 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); 84 fn enable_channel(&mut self, channel: Channel, enable: bool);
85 85
86 unsafe fn set_compare_value(&mut self, channel: Channel, value: u32); 86 fn set_compare_value(&mut self, channel: Channel, value: u32);
87 87
88 unsafe fn get_max_compare_value(&self) -> u32; 88 fn get_max_compare_value(&self) -> u32;
89 } 89 }
90} 90}
91 91
@@ -108,9 +108,9 @@ pub trait CaptureCompare32bitInstance:
108macro_rules! impl_compare_capable_16bit { 108macro_rules! impl_compare_capable_16bit {
109 ($inst:ident) => { 109 ($inst:ident) => {
110 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 110 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
111 unsafe fn enable_outputs(&mut self, _enable: bool) {} 111 fn enable_outputs(&mut self, _enable: bool) {}
112 112
113 unsafe fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) { 113 fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) {
114 use crate::timer::sealed::GeneralPurpose16bitInstance; 114 use crate::timer::sealed::GeneralPurpose16bitInstance;
115 let r = Self::regs_gp16(); 115 let r = Self::regs_gp16();
116 let raw_channel: usize = channel.raw(); 116 let raw_channel: usize = channel.raw();
@@ -118,19 +118,19 @@ macro_rules! impl_compare_capable_16bit {
118 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 118 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
119 } 119 }
120 120
121 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { 121 fn enable_channel(&mut self, channel: Channel, enable: bool) {
122 use crate::timer::sealed::GeneralPurpose16bitInstance; 122 use crate::timer::sealed::GeneralPurpose16bitInstance;
123 Self::regs_gp16() 123 Self::regs_gp16()
124 .ccer() 124 .ccer()
125 .modify(|w| w.set_cce(channel.raw(), enable)); 125 .modify(|w| w.set_cce(channel.raw(), enable));
126 } 126 }
127 127
128 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { 128 fn set_compare_value(&mut self, channel: Channel, value: u16) {
129 use crate::timer::sealed::GeneralPurpose16bitInstance; 129 use crate::timer::sealed::GeneralPurpose16bitInstance;
130 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 130 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
131 } 131 }
132 132
133 unsafe fn get_max_compare_value(&self) -> u16 { 133 fn get_max_compare_value(&self) -> u16 {
134 use crate::timer::sealed::GeneralPurpose16bitInstance; 134 use crate::timer::sealed::GeneralPurpose16bitInstance;
135 Self::regs_gp16().arr().read().arr() 135 Self::regs_gp16().arr().read().arr()
136 } 136 }
@@ -150,7 +150,7 @@ foreach_interrupt! {
150 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 150 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
151 impl_compare_capable_16bit!($inst); 151 impl_compare_capable_16bit!($inst);
152 impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { 152 impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
153 unsafe fn set_output_compare_mode( 153 fn set_output_compare_mode(
154 &mut self, 154 &mut self,
155 channel: crate::pwm::Channel, 155 channel: crate::pwm::Channel,
156 mode: OutputCompareMode, 156 mode: OutputCompareMode,
@@ -160,17 +160,17 @@ foreach_interrupt! {
160 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 160 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
161 } 161 }
162 162
163 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { 163 fn enable_channel(&mut self, channel: Channel, enable: bool) {
164 use crate::timer::sealed::GeneralPurpose32bitInstance; 164 use crate::timer::sealed::GeneralPurpose32bitInstance;
165 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); 165 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
166 } 166 }
167 167
168 unsafe fn set_compare_value(&mut self, channel: Channel, value: u32) { 168 fn set_compare_value(&mut self, channel: Channel, value: u32) {
169 use crate::timer::sealed::GeneralPurpose32bitInstance; 169 use crate::timer::sealed::GeneralPurpose32bitInstance;
170 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 170 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
171 } 171 }
172 172
173 unsafe fn get_max_compare_value(&self) -> u32 { 173 fn get_max_compare_value(&self) -> u32 {
174 use crate::timer::sealed::GeneralPurpose32bitInstance; 174 use crate::timer::sealed::GeneralPurpose32bitInstance;
175 Self::regs_gp32().arr().read().arr() as u32 175 Self::regs_gp32().arr().read().arr() as u32
176 } 176 }
@@ -185,13 +185,13 @@ foreach_interrupt! {
185 185
186 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 186 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
187 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 187 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
188 unsafe fn enable_outputs(&mut self, enable: bool) { 188 fn enable_outputs(&mut self, enable: bool) {
189 use crate::timer::sealed::AdvancedControlInstance; 189 use crate::timer::sealed::AdvancedControlInstance;
190 let r = Self::regs_advanced(); 190 let r = Self::regs_advanced();
191 r.bdtr().modify(|w| w.set_moe(enable)); 191 r.bdtr().modify(|w| w.set_moe(enable));
192 } 192 }
193 193
194 unsafe fn set_output_compare_mode( 194 fn set_output_compare_mode(
195 &mut self, 195 &mut self,
196 channel: crate::pwm::Channel, 196 channel: crate::pwm::Channel,
197 mode: OutputCompareMode, 197 mode: OutputCompareMode,
@@ -203,21 +203,21 @@ foreach_interrupt! {
203 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 203 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
204 } 204 }
205 205
206 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { 206 fn enable_channel(&mut self, channel: Channel, enable: bool) {
207 use crate::timer::sealed::AdvancedControlInstance; 207 use crate::timer::sealed::AdvancedControlInstance;
208 Self::regs_advanced() 208 Self::regs_advanced()
209 .ccer() 209 .ccer()
210 .modify(|w| w.set_cce(channel.raw(), enable)); 210 .modify(|w| w.set_cce(channel.raw(), enable));
211 } 211 }
212 212
213 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { 213 fn set_compare_value(&mut self, channel: Channel, value: u16) {
214 use crate::timer::sealed::AdvancedControlInstance; 214 use crate::timer::sealed::AdvancedControlInstance;
215 Self::regs_advanced() 215 Self::regs_advanced()
216 .ccr(channel.raw()) 216 .ccr(channel.raw())
217 .modify(|w| w.set_ccr(value)); 217 .modify(|w| w.set_ccr(value));
218 } 218 }
219 219
220 unsafe fn get_max_compare_value(&self) -> u16 { 220 fn get_max_compare_value(&self) -> u16 {
221 use crate::timer::sealed::AdvancedControlInstance; 221 use crate::timer::sealed::AdvancedControlInstance;
222 Self::regs_advanced().arr().read().arr() 222 Self::regs_advanced().arr().read().arr()
223 } 223 }
@@ -228,17 +228,17 @@ foreach_interrupt! {
228 } 228 }
229 229
230 impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { 230 impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
231 unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) { 231 fn set_dead_time_clock_division(&mut self, value: Ckd) {
232 use crate::timer::sealed::AdvancedControlInstance; 232 use crate::timer::sealed::AdvancedControlInstance;
233 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 233 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
234 } 234 }
235 235
236 unsafe fn set_dead_time_value(&mut self, value: u8) { 236 fn set_dead_time_value(&mut self, value: u8) {
237 use crate::timer::sealed::AdvancedControlInstance; 237 use crate::timer::sealed::AdvancedControlInstance;
238 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 238 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
239 } 239 }
240 240
241 unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 241 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
242 use crate::timer::sealed::AdvancedControlInstance; 242 use crate::timer::sealed::AdvancedControlInstance;
243 Self::regs_advanced() 243 Self::regs_advanced()
244 .ccer() 244 .ccer()
diff --git a/embassy-stm32/src/pwm/simple_pwm.rs b/embassy-stm32/src/pwm/simple_pwm.rs
index b045a2d78..995f59c23 100644
--- a/embassy-stm32/src/pwm/simple_pwm.rs
+++ b/embassy-stm32/src/pwm/simple_pwm.rs
@@ -24,7 +24,7 @@ macro_rules! channel_impl {
24 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { 24 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
25 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 25 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
26 into_ref!(pin); 26 into_ref!(pin);
27 critical_section::with(|_| unsafe { 27 critical_section::with(|_| {
28 pin.set_low(); 28 pin.set_low();
29 pin.set_as_af(pin.af_num(), AFType::OutputPushPull); 29 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
30 #[cfg(gpio_v2)] 30 #[cfg(gpio_v2)]
@@ -71,31 +71,25 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
71 this.inner.set_frequency(freq); 71 this.inner.set_frequency(freq);
72 this.inner.start(); 72 this.inner.start();
73 73
74 unsafe { 74 this.inner.enable_outputs(true);
75 this.inner.enable_outputs(true); 75
76 76 this.inner
77 this.inner 77 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
78 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); 78 this.inner
79 this.inner 79 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
80 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); 80 this.inner
81 this.inner 81 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
82 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); 82 this.inner
83 this.inner 83 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
84 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
85 }
86 this 84 this
87 } 85 }
88 86
89 pub fn enable(&mut self, channel: Channel) { 87 pub fn enable(&mut self, channel: Channel) {
90 unsafe { 88 self.inner.enable_channel(channel, true);
91 self.inner.enable_channel(channel, true);
92 }
93 } 89 }
94 90
95 pub fn disable(&mut self, channel: Channel) { 91 pub fn disable(&mut self, channel: Channel) {
96 unsafe { 92 self.inner.enable_channel(channel, false);
97 self.inner.enable_channel(channel, false);
98 }
99 } 93 }
100 94
101 pub fn set_freq(&mut self, freq: Hertz) { 95 pub fn set_freq(&mut self, freq: Hertz) {
@@ -103,11 +97,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
103 } 97 }
104 98
105 pub fn get_max_duty(&self) -> u16 { 99 pub fn get_max_duty(&self) -> u16 {
106 unsafe { self.inner.get_max_compare_value() } 100 self.inner.get_max_compare_value()
107 } 101 }
108 102
109 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 103 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
110 assert!(duty < self.get_max_duty()); 104 assert!(duty < self.get_max_duty());
111 unsafe { self.inner.set_compare_value(channel, duty) } 105 self.inner.set_compare_value(channel, duty)
112 } 106 }
113} 107}
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index c3126b37f..e9db934bf 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -96,20 +96,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
96 ) -> Self { 96 ) -> Self {
97 into_ref!(peri, d0, d1, d2, d3, sck, nss); 97 into_ref!(peri, d0, d1, d2, d3, sck, nss);
98 98
99 unsafe { 99 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
100 sck.set_as_af(sck.af_num(), AFType::OutputPushPull); 100 sck.set_speed(crate::gpio::Speed::VeryHigh);
101 sck.set_speed(crate::gpio::Speed::VeryHigh); 101 nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
102 nss.set_as_af(nss.af_num(), AFType::OutputPushPull); 102 nss.set_speed(crate::gpio::Speed::VeryHigh);
103 nss.set_speed(crate::gpio::Speed::VeryHigh); 103 d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
104 d0.set_as_af(d0.af_num(), AFType::OutputPushPull); 104 d0.set_speed(crate::gpio::Speed::VeryHigh);
105 d0.set_speed(crate::gpio::Speed::VeryHigh); 105 d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
106 d1.set_as_af(d1.af_num(), AFType::OutputPushPull); 106 d1.set_speed(crate::gpio::Speed::VeryHigh);
107 d1.set_speed(crate::gpio::Speed::VeryHigh); 107 d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
108 d2.set_as_af(d2.af_num(), AFType::OutputPushPull); 108 d2.set_speed(crate::gpio::Speed::VeryHigh);
109 d2.set_speed(crate::gpio::Speed::VeryHigh); 109 d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
110 d3.set_as_af(d3.af_num(), AFType::OutputPushPull); 110 d3.set_speed(crate::gpio::Speed::VeryHigh);
111 d3.set_speed(crate::gpio::Speed::VeryHigh);
112 }
113 111
114 Self::new_inner( 112 Self::new_inner(
115 peri, 113 peri,
@@ -138,21 +136,19 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
138 into_ref!(peri, dma); 136 into_ref!(peri, dma);
139 137
140 T::enable(); 138 T::enable();
141 unsafe { 139 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
142 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
143 140
144 while T::REGS.sr().read().busy() {} 141 while T::REGS.sr().read().busy() {}
145 142
146 T::REGS.cr().write(|w| { 143 T::REGS.cr().write(|w| {
147 w.set_prescaler(config.prescaler); 144 w.set_prescaler(config.prescaler);
148 w.set_en(true); 145 w.set_en(true);
149 }); 146 });
150 T::REGS.dcr().write(|w| { 147 T::REGS.dcr().write(|w| {
151 w.set_fsize(config.memory_size.into()); 148 w.set_fsize(config.memory_size.into());
152 w.set_csht(config.cs_high_time.into()); 149 w.set_csht(config.cs_high_time.into());
153 w.set_ckmode(false); 150 w.set_ckmode(false);
154 }); 151 });
155 }
156 152
157 Self { 153 Self {
158 _peri: peri, 154 _peri: peri,
@@ -168,148 +164,140 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
168 } 164 }
169 165
170 pub fn command(&mut self, transaction: TransferConfig) { 166 pub fn command(&mut self, transaction: TransferConfig) {
171 unsafe { 167 T::REGS.cr().modify(|v| v.set_dmaen(false));
172 T::REGS.cr().modify(|v| v.set_dmaen(false)); 168 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
173 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
174 169
175 while !T::REGS.sr().read().tcf() {} 170 while !T::REGS.sr().read().tcf() {}
176 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 171 T::REGS.fcr().modify(|v| v.set_ctcf(true));
177 }
178 } 172 }
179 173
180 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { 174 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
181 unsafe { 175 T::REGS.cr().modify(|v| v.set_dmaen(false));
182 T::REGS.cr().modify(|v| v.set_dmaen(false)); 176 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
183 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 177
184 178 if let Some(len) = transaction.data_len {
185 if let Some(len) = transaction.data_len { 179 let current_ar = T::REGS.ar().read().address();
186 let current_ar = T::REGS.ar().read().address(); 180 T::REGS.ccr().modify(|v| {
187 T::REGS.ccr().modify(|v| { 181 v.set_fmode(QspiMode::IndirectRead.into());
188 v.set_fmode(QspiMode::IndirectRead.into()); 182 });
189 }); 183 T::REGS.ar().write(|v| {
190 T::REGS.ar().write(|v| { 184 v.set_address(current_ar);
191 v.set_address(current_ar); 185 });
192 });
193
194 for idx in 0..len {
195 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
196 buf[idx] = *(T::REGS.dr().ptr() as *mut u8);
197 }
198 }
199 186
200 while !T::REGS.sr().read().tcf() {} 187 for idx in 0..len {
201 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 188 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
189 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
190 }
202 } 191 }
192
193 while !T::REGS.sr().read().tcf() {}
194 T::REGS.fcr().modify(|v| v.set_ctcf(true));
203 } 195 }
204 196
205 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { 197 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
206 unsafe { 198 T::REGS.cr().modify(|v| v.set_dmaen(false));
207 T::REGS.cr().modify(|v| v.set_dmaen(false)); 199 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
208 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
209
210 if let Some(len) = transaction.data_len {
211 T::REGS.ccr().modify(|v| {
212 v.set_fmode(QspiMode::IndirectWrite.into());
213 });
214
215 for idx in 0..len {
216 while !T::REGS.sr().read().ftf() {}
217 *(T::REGS.dr().ptr() as *mut u8) = buf[idx];
218 }
219 }
220 200
221 while !T::REGS.sr().read().tcf() {} 201 if let Some(len) = transaction.data_len {
222 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 202 T::REGS.ccr().modify(|v| {
203 v.set_fmode(QspiMode::IndirectWrite.into());
204 });
205
206 for idx in 0..len {
207 while !T::REGS.sr().read().ftf() {}
208 unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) };
209 }
223 } 210 }
211
212 while !T::REGS.sr().read().tcf() {}
213 T::REGS.fcr().modify(|v| v.set_ctcf(true));
224 } 214 }
225 215
226 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) 216 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
227 where 217 where
228 Dma: QuadDma<T>, 218 Dma: QuadDma<T>,
229 { 219 {
230 unsafe { 220 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
231 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 221
232 222 T::REGS.ccr().modify(|v| {
233 T::REGS.ccr().modify(|v| { 223 v.set_fmode(QspiMode::IndirectRead.into());
234 v.set_fmode(QspiMode::IndirectRead.into()); 224 });
235 }); 225 let current_ar = T::REGS.ar().read().address();
236 let current_ar = T::REGS.ar().read().address(); 226 T::REGS.ar().write(|v| {
237 T::REGS.ar().write(|v| { 227 v.set_address(current_ar);
238 v.set_address(current_ar); 228 });
239 }); 229
240 230 let request = self.dma.request();
241 let request = self.dma.request(); 231 let transfer = unsafe {
242 let transfer = Transfer::new_read( 232 Transfer::new_read(
243 &mut self.dma, 233 &mut self.dma,
244 request, 234 request,
245 T::REGS.dr().ptr() as *mut u8, 235 T::REGS.dr().as_ptr() as *mut u8,
246 buf, 236 buf,
247 Default::default(), 237 Default::default(),
248 ); 238 )
239 };
249 240
250 T::REGS.cr().modify(|v| v.set_dmaen(true)); 241 T::REGS.cr().modify(|v| v.set_dmaen(true));
251 242
252 transfer.blocking_wait(); 243 transfer.blocking_wait();
253 }
254 } 244 }
255 245
256 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) 246 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
257 where 247 where
258 Dma: QuadDma<T>, 248 Dma: QuadDma<T>,
259 { 249 {
260 unsafe { 250 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
261 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
262 251
263 T::REGS.ccr().modify(|v| { 252 T::REGS.ccr().modify(|v| {
264 v.set_fmode(QspiMode::IndirectWrite.into()); 253 v.set_fmode(QspiMode::IndirectWrite.into());
265 }); 254 });
266 255
267 let request = self.dma.request(); 256 let request = self.dma.request();
268 let transfer = Transfer::new_write( 257 let transfer = unsafe {
258 Transfer::new_write(
269 &mut self.dma, 259 &mut self.dma,
270 request, 260 request,
271 buf, 261 buf,
272 T::REGS.dr().ptr() as *mut u8, 262 T::REGS.dr().as_ptr() as *mut u8,
273 Default::default(), 263 Default::default(),
274 ); 264 )
265 };
275 266
276 T::REGS.cr().modify(|v| v.set_dmaen(true)); 267 T::REGS.cr().modify(|v| v.set_dmaen(true));
277 268
278 transfer.blocking_wait(); 269 transfer.blocking_wait();
279 }
280 } 270 }
281 271
282 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { 272 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
283 unsafe { 273 T::REGS.fcr().modify(|v| {
284 T::REGS.fcr().modify(|v| { 274 v.set_csmf(true);
285 v.set_csmf(true); 275 v.set_ctcf(true);
286 v.set_ctcf(true); 276 v.set_ctef(true);
287 v.set_ctef(true); 277 v.set_ctof(true);
288 v.set_ctof(true); 278 });
289 });
290 279
291 while T::REGS.sr().read().busy() {} 280 while T::REGS.sr().read().busy() {}
292 281
293 if let Some(len) = transaction.data_len { 282 if let Some(len) = transaction.data_len {
294 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); 283 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
295 } 284 }
296 285
297 T::REGS.ccr().write(|v| { 286 T::REGS.ccr().write(|v| {
298 v.set_fmode(fmode.into()); 287 v.set_fmode(fmode.into());
299 v.set_imode(transaction.iwidth.into()); 288 v.set_imode(transaction.iwidth.into());
300 v.set_instruction(transaction.instruction); 289 v.set_instruction(transaction.instruction);
301 v.set_admode(transaction.awidth.into()); 290 v.set_admode(transaction.awidth.into());
302 v.set_adsize(self.config.address_size.into()); 291 v.set_adsize(self.config.address_size.into());
303 v.set_dmode(transaction.dwidth.into()); 292 v.set_dmode(transaction.dwidth.into());
304 v.set_abmode(QspiWidth::NONE.into()); 293 v.set_abmode(QspiWidth::NONE.into());
305 v.set_dcyc(transaction.dummy.into()); 294 v.set_dcyc(transaction.dummy.into());
295 });
296
297 if let Some(addr) = transaction.address {
298 T::REGS.ar().write(|v| {
299 v.set_address(addr);
306 }); 300 });
307
308 if let Some(addr) = transaction.address {
309 T::REGS.ar().write(|v| {
310 v.set_address(addr);
311 });
312 }
313 } 301 }
314 } 302 }
315} 303}
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 6c7b36647..df6e9047c 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -126,7 +126,7 @@ pub(crate) unsafe fn init(config: Config) {
126 }); 126 });
127 while !RCC.cr().read().hsirdy() {} 127 while !RCC.cr().read().hsirdy() {}
128 128
129 (HSI_FREQ.0 >> div.0, Sw::HSI) 129 (HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
130 } 130 }
131 ClockSrc::HSE(freq) => { 131 ClockSrc::HSE(freq) => {
132 // Enable HSE 132 // Enable HSE
@@ -157,7 +157,7 @@ pub(crate) unsafe fn init(config: Config) {
157 let mut set_flash_latency_after = false; 157 let mut set_flash_latency_after = false;
158 FLASH.acr().modify(|w| { 158 FLASH.acr().modify(|w| {
159 // Is the current flash latency less than what we need at the new SYSCLK? 159 // Is the current flash latency less than what we need at the new SYSCLK?
160 if w.latency().0 <= target_flash_latency.0 { 160 if w.latency().to_bits() <= target_flash_latency.to_bits() {
161 // We must increase the number of wait states now 161 // We must increase the number of wait states now
162 w.set_latency(target_flash_latency) 162 w.set_latency(target_flash_latency)
163 } else { 163 } else {
@@ -171,12 +171,12 @@ pub(crate) unsafe fn init(config: Config) {
171 // > Flash memory. 171 // > Flash memory.
172 // 172 //
173 // Enable flash prefetching if we have at least one wait state, and disable it otherwise. 173 // Enable flash prefetching if we have at least one wait state, and disable it otherwise.
174 w.set_prften(target_flash_latency.0 > 0); 174 w.set_prften(target_flash_latency.to_bits() > 0);
175 }); 175 });
176 176
177 if !set_flash_latency_after { 177 if !set_flash_latency_after {
178 // Spin until the effective flash latency is compatible with the clock change 178 // Spin until the effective flash latency is compatible with the clock change
179 while FLASH.acr().read().latency().0 < target_flash_latency.0 {} 179 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
180 } 180 }
181 181
182 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 182 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@@ -218,7 +218,7 @@ pub(crate) unsafe fn init(config: Config) {
218 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 218 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
219 pre => { 219 pre => {
220 let pre: Ppre = pre.into(); 220 let pre: Ppre = pre.into();
221 let pre: u8 = 1 << (pre.0 - 3); 221 let pre: u8 = 1 << (pre.to_bits() - 3);
222 let freq = ahb_freq / pre as u32; 222 let freq = ahb_freq / pre as u32;
223 (freq, freq * 2) 223 (freq, freq * 2)
224 } 224 }
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs
index eb62ab661..ca6eed284 100644
--- a/embassy-stm32/src/rcc/f0.rs
+++ b/embassy-stm32/src/rcc/f0.rs
@@ -1,3 +1,5 @@
1use stm32_metapac::flash::vals::Latency;
2
1use super::{set_freqs, Clocks}; 3use super::{set_freqs, Clocks};
2use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; 4use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
3use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
@@ -85,14 +87,11 @@ pub(crate) unsafe fn init(config: Config) {
85 let timer_mul = if ppre == 1 { 1 } else { 2 }; 87 let timer_mul = if ppre == 1 { 1 } else { 2 };
86 88
87 FLASH.acr().write(|w| { 89 FLASH.acr().write(|w| {
88 let latency = if real_sysclk <= 24_000_000 { 90 w.set_latency(if real_sysclk <= 24_000_000 {
89 0 91 Latency::WS0
90 } else if real_sysclk <= 48_000_000 {
91 1
92 } else { 92 } else {
93 2 93 Latency::WS1
94 }; 94 });
95 w.latency().0 = latency;
96 }); 95 });
97 96
98 match (config.hse.is_some(), use_hsi48) { 97 match (config.hse.is_some(), use_hsi48) {
@@ -134,20 +133,20 @@ pub(crate) unsafe fn init(config: Config) {
134 // TODO: Option to use CRS (Clock Recovery) 133 // TODO: Option to use CRS (Clock Recovery)
135 134
136 if let Some(pllmul_bits) = pllmul_bits { 135 if let Some(pllmul_bits) = pllmul_bits {
137 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); 136 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul::from_bits(pllmul_bits)));
138 137
139 RCC.cr().modify(|w| w.set_pllon(true)); 138 RCC.cr().modify(|w| w.set_pllon(true));
140 while !RCC.cr().read().pllrdy() {} 139 while !RCC.cr().read().pllrdy() {}
141 140
142 RCC.cfgr().modify(|w| { 141 RCC.cfgr().modify(|w| {
143 w.set_ppre(Ppre(ppre_bits)); 142 w.set_ppre(Ppre::from_bits(ppre_bits));
144 w.set_hpre(Hpre(hpre_bits)); 143 w.set_hpre(Hpre::from_bits(hpre_bits));
145 w.set_sw(Sw::PLL) 144 w.set_sw(Sw::PLL)
146 }); 145 });
147 } else { 146 } else {
148 RCC.cfgr().modify(|w| { 147 RCC.cfgr().modify(|w| {
149 w.set_ppre(Ppre(ppre_bits)); 148 w.set_ppre(Ppre::from_bits(ppre_bits));
150 w.set_hpre(Hpre(hpre_bits)); 149 w.set_hpre(Hpre::from_bits(hpre_bits));
151 150
152 if config.hse.is_some() { 151 if config.hse.is_some() {
153 w.set_sw(Sw::HSE); 152 w.set_sw(Sw::HSE);
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
index 4769b7059..b6200231e 100644
--- a/embassy-stm32/src/rcc/f1.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -106,11 +106,11 @@ pub(crate) unsafe fn init(config: Config) {
106 // Only needed for stm32f103? 106 // Only needed for stm32f103?
107 FLASH.acr().write(|w| { 107 FLASH.acr().write(|w| {
108 w.set_latency(if real_sysclk <= 24_000_000 { 108 w.set_latency(if real_sysclk <= 24_000_000 {
109 Latency(0b000) 109 Latency::WS0
110 } else if real_sysclk <= 48_000_000 { 110 } else if real_sysclk <= 48_000_000 {
111 Latency(0b001) 111 Latency::WS1
112 } else { 112 } else {
113 Latency(0b010) 113 Latency::WS2
114 }); 114 });
115 }); 115 });
116 116
@@ -147,12 +147,13 @@ pub(crate) unsafe fn init(config: Config) {
147 147
148 if let Some(pllmul_bits) = pllmul_bits { 148 if let Some(pllmul_bits) = pllmul_bits {
149 let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 }; 149 let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 };
150 RCC.cfgr().modify(|w| w.set_pllxtpre(Pllxtpre(pllctpre_flag))); 150 RCC.cfgr()
151 .modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag)));
151 152
152 // enable PLL and wait for it to be ready 153 // enable PLL and wait for it to be ready
153 RCC.cfgr().modify(|w| { 154 RCC.cfgr().modify(|w| {
154 w.set_pllmul(Pllmul(pllmul_bits)); 155 w.set_pllmul(Pllmul::from_bits(pllmul_bits));
155 w.set_pllsrc(Pllsrc(config.hse.is_some() as u8)); 156 w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8));
156 }); 157 });
157 158
158 RCC.cr().modify(|w| w.set_pllon(true)); 159 RCC.cr().modify(|w| w.set_pllon(true));
@@ -161,22 +162,19 @@ pub(crate) unsafe fn init(config: Config) {
161 162
162 // Only needed for stm32f103? 163 // Only needed for stm32f103?
163 RCC.cfgr().modify(|w| { 164 RCC.cfgr().modify(|w| {
164 w.set_adcpre(Adcpre(apre_bits)); 165 w.set_adcpre(Adcpre::from_bits(apre_bits));
165 w.set_ppre2(Ppre1(ppre2_bits)); 166 w.set_ppre2(Ppre1::from_bits(ppre2_bits));
166 w.set_ppre1(Ppre1(ppre1_bits)); 167 w.set_ppre1(Ppre1::from_bits(ppre1_bits));
167 w.set_hpre(Hpre(hpre_bits)); 168 w.set_hpre(Hpre::from_bits(hpre_bits));
168 #[cfg(not(rcc_f100))] 169 #[cfg(not(rcc_f100))]
169 w.set_usbpre(Usbpre(usbpre as u8)); 170 w.set_usbpre(Usbpre::from_bits(usbpre as u8));
170 w.set_sw(Sw(if pllmul_bits.is_some() { 171 w.set_sw(if pllmul_bits.is_some() {
171 // PLL 172 Sw::PLL
172 0b10
173 } else if config.hse.is_some() { 173 } else if config.hse.is_some() {
174 // HSE 174 Sw::HSE
175 0b1
176 } else { 175 } else {
177 // HSI 176 Sw::HSI
178 0b0 177 });
179 }));
180 }); 178 });
181 179
182 set_freqs(Clocks { 180 set_freqs(Clocks {
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs
index bcae64d0f..1525cc3c3 100644
--- a/embassy-stm32/src/rcc/f2.rs
+++ b/embassy-stm32/src/rcc/f2.rs
@@ -485,7 +485,7 @@ pub(crate) unsafe fn init(config: Config) {
485 w.set_ppre1(config.apb1_pre.into()); 485 w.set_ppre1(config.apb1_pre.into());
486 w.set_ppre2(config.apb2_pre.into()); 486 w.set_ppre2(config.apb2_pre.into());
487 }); 487 });
488 while RCC.cfgr().read().sws() != sw.0 {} 488 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
489 489
490 // Turn off HSI to save power if we don't need it 490 // Turn off HSI to save power if we don't need it
491 if !config.hsi { 491 if !config.hsi {
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index e0929ca49..b84470440 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -36,18 +36,18 @@ pub struct Config {
36} 36}
37 37
38#[cfg(stm32f410)] 38#[cfg(stm32f410)]
39unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { 39fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
40 None 40 None
41} 41}
42 42
43// Not currently implemented, but will be in the future 43// Not currently implemented, but will be in the future
44#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] 44#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
45unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { 45fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
46 None 46 None
47} 47}
48 48
49#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] 49#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
50unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { 50fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
51 let min_div = 2; 51 let min_div = 2;
52 let max_div = 7; 52 let max_div = 7;
53 let target = match plli2s { 53 let target = match plli2s {
@@ -82,18 +82,12 @@ unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
82 Some(output) 82 Some(output)
83} 83}
84 84
85unsafe fn setup_pll( 85fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults {
86 pllsrcclk: u32,
87 use_hse: bool,
88 pllsysclk: Option<u32>,
89 plli2s: Option<u32>,
90 pll48clk: bool,
91) -> PllResults {
92 use crate::pac::rcc::vals::{Pllp, Pllsrc}; 86 use crate::pac::rcc::vals::{Pllp, Pllsrc};
93 87
94 let sysclk = pllsysclk.unwrap_or(pllsrcclk); 88 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
95 if pllsysclk.is_none() && !pll48clk { 89 if pllsysclk.is_none() && !pll48clk {
96 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); 90 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
97 91
98 return PllResults { 92 return PllResults {
99 use_pll: false, 93 use_pll: false,
@@ -147,9 +141,9 @@ unsafe fn setup_pll(
147 RCC.pllcfgr().modify(|w| { 141 RCC.pllcfgr().modify(|w| {
148 w.set_pllm(pllm as u8); 142 w.set_pllm(pllm as u8);
149 w.set_plln(plln as u16); 143 w.set_plln(plln as u16);
150 w.set_pllp(Pllp(pllp as u8)); 144 w.set_pllp(Pllp::from_bits(pllp as u8));
151 w.set_pllq(pllq as u8); 145 w.set_pllq(pllq as u8);
152 w.set_pllsrc(Pllsrc(use_hse as u8)); 146 w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
153 }); 147 });
154 148
155 let real_pllsysclk = vco_in * plln / sysclk_div; 149 let real_pllsysclk = vco_in * plln / sysclk_div;
@@ -320,7 +314,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
320 } 314 }
321} 315}
322 316
323unsafe fn flash_setup(sysclk: u32) { 317fn flash_setup(sysclk: u32) {
324 use crate::pac::flash::vals::Latency; 318 use crate::pac::flash::vals::Latency;
325 319
326 // Be conservative with voltage ranges 320 // Be conservative with voltage ranges
@@ -329,7 +323,7 @@ unsafe fn flash_setup(sysclk: u32) {
329 critical_section::with(|_| { 323 critical_section::with(|_| {
330 FLASH 324 FLASH
331 .acr() 325 .acr()
332 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); 326 .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
333 }); 327 });
334} 328}
335 329
@@ -446,8 +440,8 @@ pub(crate) unsafe fn init(config: Config) {
446 } 440 }
447 441
448 RCC.cfgr().modify(|w| { 442 RCC.cfgr().modify(|w| {
449 w.set_ppre2(Ppre(ppre2_bits)); 443 w.set_ppre2(Ppre::from_bits(ppre2_bits));
450 w.set_ppre1(Ppre(ppre1_bits)); 444 w.set_ppre1(Ppre::from_bits(ppre1_bits));
451 w.set_hpre(hpre_bits); 445 w.set_hpre(hpre_bits);
452 }); 446 });
453 447
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index 2d21326a3..85cb9c661 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -25,12 +25,12 @@ pub struct Config {
25 pub pll48: bool, 25 pub pll48: bool,
26} 26}
27 27
28unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { 28fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
29 use crate::pac::rcc::vals::{Pllp, Pllsrc}; 29 use crate::pac::rcc::vals::{Pllp, Pllsrc};
30 30
31 let sysclk = pllsysclk.unwrap_or(pllsrcclk); 31 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
32 if pllsysclk.is_none() && !pll48clk { 32 if pllsysclk.is_none() && !pll48clk {
33 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); 33 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
34 34
35 return PllResults { 35 return PllResults {
36 use_pll: false, 36 use_pll: false,
@@ -83,9 +83,9 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48
83 RCC.pllcfgr().modify(|w| { 83 RCC.pllcfgr().modify(|w| {
84 w.set_pllm(pllm as u8); 84 w.set_pllm(pllm as u8);
85 w.set_plln(plln as u16); 85 w.set_plln(plln as u16);
86 w.set_pllp(Pllp(pllp as u8)); 86 w.set_pllp(Pllp::from_bits(pllp as u8));
87 w.set_pllq(pllq as u8); 87 w.set_pllq(pllq as u8);
88 w.set_pllsrc(Pllsrc(use_hse as u8)); 88 w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
89 }); 89 });
90 90
91 let real_pllsysclk = vco_in * plln / sysclk_div; 91 let real_pllsysclk = vco_in * plln / sysclk_div;
@@ -97,7 +97,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48
97 } 97 }
98} 98}
99 99
100unsafe fn flash_setup(sysclk: u32) { 100fn flash_setup(sysclk: u32) {
101 use crate::pac::flash::vals::Latency; 101 use crate::pac::flash::vals::Latency;
102 102
103 // Be conservative with voltage ranges 103 // Be conservative with voltage ranges
@@ -106,7 +106,7 @@ unsafe fn flash_setup(sysclk: u32) {
106 critical_section::with(|_| { 106 critical_section::with(|_| {
107 FLASH 107 FLASH
108 .acr() 108 .acr()
109 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); 109 .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
110 }); 110 });
111} 111}
112 112
@@ -246,8 +246,8 @@ pub(crate) unsafe fn init(config: Config) {
246 } 246 }
247 247
248 RCC.cfgr().modify(|w| { 248 RCC.cfgr().modify(|w| {
249 w.set_ppre2(Ppre(ppre2_bits)); 249 w.set_ppre2(Ppre::from_bits(ppre2_bits));
250 w.set_ppre1(Ppre(ppre1_bits)); 250 w.set_ppre1(Ppre::from_bits(ppre1_bits));
251 w.set_hpre(hpre_bits); 251 w.set_hpre(hpre_bits);
252 }); 252 });
253 253
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index 3e138c7ab..5e3a7911a 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -245,7 +245,7 @@ impl Default for Config {
245} 245}
246 246
247impl PllConfig { 247impl PllConfig {
248 pub(crate) unsafe fn init(self) -> u32 { 248 pub(crate) fn init(self) -> u32 {
249 assert!(self.n >= 8 && self.n <= 86); 249 assert!(self.n >= 8 && self.n <= 86);
250 let (src, input_freq) = match self.source { 250 let (src, input_freq) = match self.source {
251 PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), 251 PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0),
@@ -344,7 +344,7 @@ pub(crate) unsafe fn init(config: Config) {
344 }); 344 });
345 while !RCC.cr().read().hsirdy() {} 345 while !RCC.cr().read().hsirdy() {}
346 346
347 (HSI_FREQ.0 >> div.0, Sw::HSI) 347 (HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
348 } 348 }
349 ClockSrc::HSE(freq) => { 349 ClockSrc::HSE(freq) => {
350 // Enable HSE 350 // Enable HSE
@@ -381,7 +381,7 @@ pub(crate) unsafe fn init(config: Config) {
381 let mut set_flash_latency_after = false; 381 let mut set_flash_latency_after = false;
382 FLASH.acr().modify(|w| { 382 FLASH.acr().modify(|w| {
383 // Is the current flash latency less than what we need at the new SYSCLK? 383 // Is the current flash latency less than what we need at the new SYSCLK?
384 if w.latency().0 <= target_flash_latency.0 { 384 if w.latency().to_bits() <= target_flash_latency.to_bits() {
385 // We must increase the number of wait states now 385 // We must increase the number of wait states now
386 w.set_latency(target_flash_latency) 386 w.set_latency(target_flash_latency)
387 } else { 387 } else {
@@ -395,12 +395,12 @@ pub(crate) unsafe fn init(config: Config) {
395 // > Flash memory. 395 // > Flash memory.
396 // 396 //
397 // Enable flash prefetching if we have at least one wait state, and disable it otherwise. 397 // Enable flash prefetching if we have at least one wait state, and disable it otherwise.
398 w.set_prften(target_flash_latency.0 > 0); 398 w.set_prften(target_flash_latency.to_bits() > 0);
399 }); 399 });
400 400
401 if !set_flash_latency_after { 401 if !set_flash_latency_after {
402 // Spin until the effective flash latency is compatible with the clock change 402 // Spin until the effective flash latency is compatible with the clock change
403 while FLASH.acr().read().latency().0 < target_flash_latency.0 {} 403 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
404 } 404 }
405 405
406 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 406 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: Config) {
442 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 442 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
443 pre => { 443 pre => {
444 let pre: Ppre = pre.into(); 444 let pre: Ppre = pre.into();
445 let pre: u8 = 1 << (pre.0 - 3); 445 let pre: u8 = 1 << (pre.to_bits() - 3);
446 let freq = ahb_freq / pre as u32; 446 let freq = ahb_freq / pre as u32;
447 (freq, freq * 2) 447 (freq, freq * 2)
448 } 448 }
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 7e748c7b5..ff8f97541 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,6 +1,9 @@
1use stm32_metapac::rcc::vals::{Hpre, Ppre, Sw}; 1use stm32_metapac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
3use stm32_metapac::FLASH;
2 4
3use crate::pac::{PWR, RCC}; 5use crate::pac::{PWR, RCC};
6use crate::rcc::sealed::RccPeripheral;
4use crate::rcc::{set_freqs, Clocks}; 7use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 8use crate::time::Hertz;
6 9
@@ -15,6 +18,7 @@ pub const LSI_FREQ: Hertz = Hertz(32_000);
15pub enum ClockSrc { 18pub enum ClockSrc {
16 HSE(Hertz), 19 HSE(Hertz),
17 HSI16, 20 HSI16,
21 PLL,
18} 22}
19 23
20/// AHB prescaler 24/// AHB prescaler
@@ -41,6 +45,222 @@ pub enum APBPrescaler {
41 Div16, 45 Div16,
42} 46}
43 47
48/// PLL clock input source
49#[derive(Clone, Copy, Debug)]
50pub enum PllSrc {
51 HSI16,
52 HSE(Hertz),
53}
54
55impl Into<Pllsrc> for PllSrc {
56 fn into(self) -> Pllsrc {
57 match self {
58 PllSrc::HSE(..) => Pllsrc::HSE,
59 PllSrc::HSI16 => Pllsrc::HSI16,
60 }
61 }
62}
63
64seq_macro::seq!(P in 2..=31 {
65 /// Output divider for the PLL P output.
66 #[derive(Clone, Copy)]
67 pub enum PllP {
68 // Note: If PLL P is set to 0 the PLLP bit controls the output division. There does not seem to
69 // a good reason to do this so the API does not support it.
70 // Div1 is invalid
71 #(
72 Div~P,
73 )*
74 }
75
76 impl From<PllP> for u8 {
77 /// Returns the register value for the P output divider.
78 fn from(val: PllP) -> u8 {
79 match val {
80 #(
81 PllP::Div~P => P,
82 )*
83 }
84 }
85 }
86});
87
88impl PllP {
89 /// Returns the numeric value of the P output divider.
90 pub fn to_div(self) -> u32 {
91 let val: u8 = self.into();
92 val as u32
93 }
94}
95
96/// Output divider for the PLL Q output.
97#[derive(Clone, Copy)]
98pub enum PllQ {
99 Div2,
100 Div4,
101 Div6,
102 Div8,
103}
104
105impl PllQ {
106 /// Returns the numeric value of the Q output divider.
107 pub fn to_div(self) -> u32 {
108 let val: u8 = self.into();
109 (val as u32 + 1) * 2
110 }
111}
112
113impl From<PllQ> for u8 {
114 /// Returns the register value for the Q output divider.
115 fn from(val: PllQ) -> u8 {
116 match val {
117 PllQ::Div2 => 0b00,
118 PllQ::Div4 => 0b01,
119 PllQ::Div6 => 0b10,
120 PllQ::Div8 => 0b11,
121 }
122 }
123}
124
125/// Output divider for the PLL R output.
126#[derive(Clone, Copy)]
127pub enum PllR {
128 Div2,
129 Div4,
130 Div6,
131 Div8,
132}
133
134impl PllR {
135 /// Returns the numeric value of the R output divider.
136 pub fn to_div(self) -> u32 {
137 let val: u8 = self.into();
138 (val as u32 + 1) * 2
139 }
140}
141
142impl From<PllR> for u8 {
143 /// Returns the register value for the R output divider.
144 fn from(val: PllR) -> u8 {
145 match val {
146 PllR::Div2 => 0b00,
147 PllR::Div4 => 0b01,
148 PllR::Div6 => 0b10,
149 PllR::Div8 => 0b11,
150 }
151 }
152}
153
154seq_macro::seq!(N in 8..=127 {
155 /// Multiplication factor for the PLL VCO input clock.
156 #[derive(Clone, Copy)]
157 pub enum PllN {
158 #(
159 Mul~N,
160 )*
161 }
162
163 impl From<PllN> for u8 {
164 /// Returns the register value for the N multiplication factor.
165 fn from(val: PllN) -> u8 {
166 match val {
167 #(
168 PllN::Mul~N => N,
169 )*
170 }
171 }
172 }
173
174 impl PllN {
175 /// Returns the numeric value of the N multiplication factor.
176 pub fn to_mul(self) -> u32 {
177 match self {
178 #(
179 PllN::Mul~N => N,
180 )*
181 }
182 }
183 }
184});
185
186/// PLL Pre-division. This must be set such that the PLL input is between 2.66 MHz and 16 MHz.
187#[derive(Copy, Clone)]
188pub enum PllM {
189 Div1,
190 Div2,
191 Div3,
192 Div4,
193 Div5,
194 Div6,
195 Div7,
196 Div8,
197 Div9,
198 Div10,
199 Div11,
200 Div12,
201 Div13,
202 Div14,
203 Div15,
204 Div16,
205}
206
207impl PllM {
208 /// Returns the numeric value of the M pre-division.
209 pub fn to_div(self) -> u32 {
210 let val: u8 = self.into();
211 val as u32 + 1
212 }
213}
214
215impl From<PllM> for u8 {
216 /// Returns the register value for the M pre-division.
217 fn from(val: PllM) -> u8 {
218 match val {
219 PllM::Div1 => 0b0000,
220 PllM::Div2 => 0b0001,
221 PllM::Div3 => 0b0010,
222 PllM::Div4 => 0b0011,
223 PllM::Div5 => 0b0100,
224 PllM::Div6 => 0b0101,
225 PllM::Div7 => 0b0110,
226 PllM::Div8 => 0b0111,
227 PllM::Div9 => 0b1000,
228 PllM::Div10 => 0b1001,
229 PllM::Div11 => 0b1010,
230 PllM::Div12 => 0b1011,
231 PllM::Div13 => 0b1100,
232 PllM::Div14 => 0b1101,
233 PllM::Div15 => 0b1110,
234 PllM::Div16 => 0b1111,
235 }
236 }
237}
238
239/// PLL Configuration
240///
241/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
242/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
243/// frequency ranges for each of these settings.
244pub struct Pll {
245 /// PLL Source clock selection.
246 pub source: PllSrc,
247
248 /// PLL pre-divider
249 pub prediv_m: PllM,
250
251 /// PLL multiplication factor for VCO
252 pub mul_n: PllN,
253
254 /// PLL division factor for P clock (ADC Clock)
255 pub div_p: Option<PllP>,
256
257 /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI)
258 pub div_q: Option<PllQ>,
259
260 /// PLL division factor for R clock (SYSCLK)
261 pub div_r: Option<PllR>,
262}
263
44impl AHBPrescaler { 264impl AHBPrescaler {
45 const fn div(self) -> u32 { 265 const fn div(self) -> u32 {
46 match self { 266 match self {
@@ -97,6 +317,27 @@ impl Into<Hpre> for AHBPrescaler {
97 } 317 }
98} 318}
99 319
320/// Sets the source for the 48MHz clock to the USB and RNG peripherals.
321pub enum Clock48MhzSrc {
322 /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
323 /// oscillator to comply with the USB specification for oscillator tolerance.
324 Hsi48(Option<CrsConfig>),
325 /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
326 /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
327 /// tolerance.
328 PllQ,
329}
330
331/// Sets the sync source for the Clock Recovery System (CRS).
332pub enum CrsSyncSource {
333 /// Use an external GPIO to sync the CRS.
334 Gpio,
335 /// Use the Low Speed External oscillator to sync the CRS.
336 Lse,
337 /// Use the USB SOF to sync the CRS.
338 Usb,
339}
340
100/// Clocks configutation 341/// Clocks configutation
101pub struct Config { 342pub struct Config {
102 pub mux: ClockSrc, 343 pub mux: ClockSrc,
@@ -104,6 +345,17 @@ pub struct Config {
104 pub apb1_pre: APBPrescaler, 345 pub apb1_pre: APBPrescaler,
105 pub apb2_pre: APBPrescaler, 346 pub apb2_pre: APBPrescaler,
106 pub low_power_run: bool, 347 pub low_power_run: bool,
348 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
349 /// MUST turn on the PLLR output.
350 pub pll: Option<Pll>,
351 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
352 pub clock_48mhz_src: Option<Clock48MhzSrc>,
353}
354
355/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
356pub struct CrsConfig {
357 /// Sync source for the CRS.
358 pub sync_src: CrsSyncSource,
107} 359}
108 360
109impl Default for Config { 361impl Default for Config {
@@ -115,11 +367,81 @@ impl Default for Config {
115 apb1_pre: APBPrescaler::NotDivided, 367 apb1_pre: APBPrescaler::NotDivided,
116 apb2_pre: APBPrescaler::NotDivided, 368 apb2_pre: APBPrescaler::NotDivided,
117 low_power_run: false, 369 low_power_run: false,
370 pll: None,
371 clock_48mhz_src: None,
118 } 372 }
119 } 373 }
120} 374}
121 375
376pub struct PllFreq {
377 pub pll_p: Option<Hertz>,
378 pub pll_q: Option<Hertz>,
379 pub pll_r: Option<Hertz>,
380}
381
122pub(crate) unsafe fn init(config: Config) { 382pub(crate) unsafe fn init(config: Config) {
383 let pll_freq = config.pll.map(|pll_config| {
384 let src_freq = match pll_config.source {
385 PllSrc::HSI16 => {
386 RCC.cr().write(|w| w.set_hsion(true));
387 while !RCC.cr().read().hsirdy() {}
388
389 HSI_FREQ.0
390 }
391 PllSrc::HSE(freq) => {
392 RCC.cr().write(|w| w.set_hseon(true));
393 while !RCC.cr().read().hserdy() {}
394 freq.0
395 }
396 };
397
398 // Disable PLL before configuration
399 RCC.cr().modify(|w| w.set_pllon(false));
400 while RCC.cr().read().pllrdy() {}
401
402 let internal_freq = src_freq / pll_config.prediv_m.to_div() * pll_config.mul_n.to_mul();
403
404 RCC.pllcfgr().write(|w| {
405 w.set_plln(pll_config.mul_n.into());
406 w.set_pllm(pll_config.prediv_m.into());
407 w.set_pllsrc(pll_config.source.into());
408 });
409
410 let pll_p_freq = pll_config.div_p.map(|div_p| {
411 RCC.pllcfgr().modify(|w| {
412 w.set_pllpdiv(div_p.into());
413 w.set_pllpen(true);
414 });
415 Hertz(internal_freq / div_p.to_div())
416 });
417
418 let pll_q_freq = pll_config.div_q.map(|div_q| {
419 RCC.pllcfgr().modify(|w| {
420 w.set_pllq(div_q.into());
421 w.set_pllqen(true);
422 });
423 Hertz(internal_freq / div_q.to_div())
424 });
425
426 let pll_r_freq = pll_config.div_r.map(|div_r| {
427 RCC.pllcfgr().modify(|w| {
428 w.set_pllr(div_r.into());
429 w.set_pllren(true);
430 });
431 Hertz(internal_freq / div_r.to_div())
432 });
433
434 // Enable the PLL
435 RCC.cr().modify(|w| w.set_pllon(true));
436 while !RCC.cr().read().pllrdy() {}
437
438 PllFreq {
439 pll_p: pll_p_freq,
440 pll_q: pll_q_freq,
441 pll_r: pll_r_freq,
442 }
443 });
444
123 let (sys_clk, sw) = match config.mux { 445 let (sys_clk, sw) = match config.mux {
124 ClockSrc::HSI16 => { 446 ClockSrc::HSI16 => {
125 // Enable HSI16 447 // Enable HSI16
@@ -135,6 +457,47 @@ pub(crate) unsafe fn init(config: Config) {
135 457
136 (freq.0, Sw::HSE) 458 (freq.0, Sw::HSE)
137 } 459 }
460 ClockSrc::PLL => {
461 assert!(pll_freq.is_some());
462 assert!(pll_freq.as_ref().unwrap().pll_r.is_some());
463
464 let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0;
465
466 assert!(freq <= 170_000_000);
467
468 if freq >= 150_000_000 {
469 // Enable Core Boost mode on freq >= 150Mhz ([RM0440] p234)
470 PWR.cr5().modify(|w| w.set_r1mode(false));
471 // Set flash wait state in boost mode based on frequency ([RM0440] p191)
472 if freq <= 36_000_000 {
473 FLASH.acr().modify(|w| w.set_latency(Latency::WS0));
474 } else if freq <= 68_000_000 {
475 FLASH.acr().modify(|w| w.set_latency(Latency::WS1));
476 } else if freq <= 102_000_000 {
477 FLASH.acr().modify(|w| w.set_latency(Latency::WS2));
478 } else if freq <= 136_000_000 {
479 FLASH.acr().modify(|w| w.set_latency(Latency::WS3));
480 } else {
481 FLASH.acr().modify(|w| w.set_latency(Latency::WS4));
482 }
483 } else {
484 PWR.cr5().modify(|w| w.set_r1mode(true));
485 // Set flash wait state in normal mode based on frequency ([RM0440] p191)
486 if freq <= 30_000_000 {
487 FLASH.acr().modify(|w| w.set_latency(Latency::WS0));
488 } else if freq <= 60_000_000 {
489 FLASH.acr().modify(|w| w.set_latency(Latency::WS1));
490 } else if freq <= 80_000_000 {
491 FLASH.acr().modify(|w| w.set_latency(Latency::WS2));
492 } else if freq <= 120_000_000 {
493 FLASH.acr().modify(|w| w.set_latency(Latency::WS3));
494 } else {
495 FLASH.acr().modify(|w| w.set_latency(Latency::WS4));
496 }
497 }
498
499 (freq, Sw::PLLRCLK)
500 }
138 }; 501 };
139 502
140 RCC.cfgr().modify(|w| { 503 RCC.cfgr().modify(|w| {
@@ -165,6 +528,50 @@ pub(crate) unsafe fn init(config: Config) {
165 } 528 }
166 }; 529 };
167 530
531 // Setup the 48 MHz clock if needed
532 if let Some(clock_48mhz_src) = config.clock_48mhz_src {
533 let source = match clock_48mhz_src {
534 Clock48MhzSrc::PllQ => {
535 // Make sure the PLLQ is enabled and running at 48Mhz
536 let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
537 assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
538
539 crate::pac::rcc::vals::Clk48sel::PLLQCLK
540 }
541 Clock48MhzSrc::Hsi48(crs_config) => {
542 // Enable HSI48
543 RCC.crrcr().modify(|w| w.set_hsi48on(true));
544 // Wait for HSI48 to turn on
545 while RCC.crrcr().read().hsi48rdy() == false {}
546
547 // Enable and setup CRS if needed
548 if let Some(crs_config) = crs_config {
549 crate::peripherals::CRS::enable();
550
551 let sync_src = match crs_config.sync_src {
552 CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
553 CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
554 CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
555 };
556
557 crate::pac::CRS.cfgr().modify(|w| {
558 w.set_syncsrc(sync_src);
559 });
560
561 // These are the correct settings for standard USB operation. If other settings
562 // are needed there will need to be additional config options for the CRS.
563 crate::pac::CRS.cr().modify(|w| {
564 w.set_autotrimen(true);
565 w.set_cen(true);
566 });
567 }
568 crate::pac::rcc::vals::Clk48sel::HSI48
569 }
570 };
571
572 RCC.ccipr().modify(|w| w.set_clk48sel(source));
573 }
574
168 if config.low_power_run { 575 if config.low_power_run {
169 assert!(sys_clk <= 2_000_000); 576 assert!(sys_clk <= 2_000_000);
170 PWR.cr1().modify(|w| w.set_lpr(true)); 577 PWR.cr1().modify(|w| w.set_lpr(true));
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs
index 17fbc6056..4025a4e05 100644
--- a/embassy-stm32/src/rcc/h5.rs
+++ b/embassy-stm32/src/rcc/h5.rs
@@ -462,7 +462,7 @@ struct PllOutput {
462 r: Option<Hertz>, 462 r: Option<Hertz>,
463} 463}
464 464
465unsafe fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { 465fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
466 let Some(config) = config else { 466 let Some(config) = config else {
467 // Stop PLL 467 // Stop PLL
468 RCC.cr().modify(|w| w.set_pllon(num, false)); 468 RCC.cr().modify(|w| w.set_pllon(num, false));
@@ -595,12 +595,9 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
595 595
596 defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); 596 defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
597 597
598 // NOTE(unsafe) Atomic write 598 FLASH.acr().write(|w| {
599 unsafe { 599 w.set_wrhighfreq(wrhighfreq);
600 FLASH.acr().write(|w| { 600 w.set_latency(latency);
601 w.set_wrhighfreq(wrhighfreq); 601 });
602 w.set_latency(latency); 602 while FLASH.acr().read().latency() != latency {}
603 });
604 while FLASH.acr().read().latency() != latency {}
605 }
606} 603}
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index 0185f7ae8..f3a98c794 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -253,14 +253,11 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
253 }, 253 },
254 }; 254 };
255 255
256 // NOTE(unsafe) Atomic write 256 FLASH.acr().write(|w| {
257 unsafe { 257 w.set_wrhighfreq(progr_delay);
258 FLASH.acr().write(|w| { 258 w.set_latency(wait_states)
259 w.set_wrhighfreq(progr_delay); 259 });
260 w.set_latency(wait_states) 260 while FLASH.acr().read().latency() != wait_states {}
261 });
262 while FLASH.acr().read().latency() != wait_states {}
263 }
264} 261}
265 262
266pub enum McoClock { 263pub enum McoClock {
@@ -474,7 +471,6 @@ pub(crate) unsafe fn init(mut config: Config) {
474 // Configure traceclk from PLL if needed 471 // Configure traceclk from PLL if needed
475 traceclk_setup(&mut config, sys_use_pll1_p); 472 traceclk_setup(&mut config, sys_use_pll1_p);
476 473
477 // NOTE(unsafe) We have exclusive access to the RCC
478 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); 474 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
479 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); 475 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
480 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); 476 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
@@ -605,22 +601,22 @@ pub(crate) unsafe fn init(mut config: Config) {
605 601
606 // Core Prescaler / AHB Prescaler / APB3 Prescaler 602 // Core Prescaler / AHB Prescaler / APB3 Prescaler
607 RCC.d1cfgr().modify(|w| { 603 RCC.d1cfgr().modify(|w| {
608 w.set_d1cpre(Hpre(d1cpre_bits)); 604 w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
609 w.set_d1ppre(Dppre(ppre3_bits)); 605 w.set_d1ppre(Dppre::from_bits(ppre3_bits));
610 w.set_hpre(hpre_bits) 606 w.set_hpre(hpre_bits)
611 }); 607 });
612 // Ensure core prescaler value is valid before future lower 608 // Ensure core prescaler value is valid before future lower
613 // core voltage 609 // core voltage
614 while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {} 610 while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
615 611
616 // APB1 / APB2 Prescaler 612 // APB1 / APB2 Prescaler
617 RCC.d2cfgr().modify(|w| { 613 RCC.d2cfgr().modify(|w| {
618 w.set_d2ppre1(Dppre(ppre1_bits)); 614 w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
619 w.set_d2ppre2(Dppre(ppre2_bits)); 615 w.set_d2ppre2(Dppre::from_bits(ppre2_bits));
620 }); 616 });
621 617
622 // APB4 Prescaler 618 // APB4 Prescaler
623 RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits))); 619 RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits)));
624 620
625 // Peripheral Clock (per_ck) 621 // Peripheral Clock (per_ck)
626 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); 622 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
@@ -644,7 +640,7 @@ pub(crate) unsafe fn init(mut config: Config) {
644 _ => Sw::HSI, 640 _ => Sw::HSI,
645 }; 641 };
646 RCC.cfgr().modify(|w| w.set_sw(sw)); 642 RCC.cfgr().modify(|w| w.set_sw(sw));
647 while RCC.cfgr().read().sws() != sw.0 {} 643 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
648 644
649 // IO compensation cell - Requires CSI clock and SYSCFG 645 // IO compensation cell - Requires CSI clock and SYSCFG
650 assert!(RCC.cr().read().csirdy()); 646 assert!(RCC.cr().read().csirdy());
@@ -756,7 +752,7 @@ mod pll {
756 /// # Safety 752 /// # Safety
757 /// 753 ///
758 /// Must have exclusive access to the RCC register block 754 /// Must have exclusive access to the RCC register block
759 unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { 755 fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
760 use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; 756 use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
761 757
762 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); 758 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
@@ -785,11 +781,7 @@ mod pll {
785 /// # Safety 781 /// # Safety
786 /// 782 ///
787 /// Must have exclusive access to the RCC register block 783 /// Must have exclusive access to the RCC register block
788 pub(super) unsafe fn pll_setup( 784 pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
789 pll_src: u32,
790 config: &PllConfig,
791 plln: usize,
792 ) -> (Option<u32>, Option<u32>, Option<u32>) {
793 use crate::pac::rcc::vals::Divp; 785 use crate::pac::rcc::vals::Divp;
794 786
795 match config.p_ck { 787 match config.p_ck {
@@ -814,7 +806,8 @@ mod pll {
814 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false)); 806 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
815 let vco_ck = ref_x_ck * pll_x_n; 807 let vco_ck = ref_x_ck * pll_x_n;
816 808
817 RCC.plldivr(plln).modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8))); 809 RCC.plldivr(plln)
810 .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
818 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true)); 811 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
819 812
820 // Calulate additional output dividers 813 // Calulate additional output dividers
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index 42a481a74..46a528e31 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -1,7 +1,7 @@
1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; 1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
2use crate::pac::RCC; 2use crate::pac::RCC;
3#[cfg(crs)] 3#[cfg(crs)]
4use crate::pac::{CRS, SYSCFG}; 4use crate::pac::{crs, CRS, SYSCFG};
5use crate::rcc::{set_freqs, Clocks}; 5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 6use crate::time::Hertz;
7 7
@@ -293,7 +293,7 @@ pub(crate) unsafe fn init(config: Config) {
293 AHBPrescaler::NotDivided => sys_clk, 293 AHBPrescaler::NotDivided => sys_clk,
294 pre => { 294 pre => {
295 let pre: Hpre = pre.into(); 295 let pre: Hpre = pre.into();
296 let pre = 1 << (pre.0 as u32 - 7); 296 let pre = 1 << (pre.to_bits() as u32 - 7);
297 sys_clk / pre 297 sys_clk / pre
298 } 298 }
299 }; 299 };
@@ -302,7 +302,7 @@ pub(crate) unsafe fn init(config: Config) {
302 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 302 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
303 pre => { 303 pre => {
304 let pre: Ppre = pre.into(); 304 let pre: Ppre = pre.into();
305 let pre: u8 = 1 << (pre.0 - 3); 305 let pre: u8 = 1 << (pre.to_bits() - 3);
306 let freq = ahb_freq / pre as u32; 306 let freq = ahb_freq / pre as u32;
307 (freq, freq * 2) 307 (freq, freq * 2)
308 } 308 }
@@ -312,7 +312,7 @@ pub(crate) unsafe fn init(config: Config) {
312 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 312 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
313 pre => { 313 pre => {
314 let pre: Ppre = pre.into(); 314 let pre: Ppre = pre.into();
315 let pre: u8 = 1 << (pre.0 - 3); 315 let pre: u8 = 1 << (pre.to_bits() - 3);
316 let freq = ahb_freq / pre as u32; 316 let freq = ahb_freq / pre as u32;
317 (freq, freq * 2) 317 (freq, freq * 2)
318 } 318 }
@@ -338,7 +338,7 @@ pub(crate) unsafe fn init(config: Config) {
338 CRS.cfgr().write(|w| 338 CRS.cfgr().write(|w|
339 339
340 // Select LSE as synchronization source 340 // Select LSE as synchronization source
341 w.set_syncsrc(0b01)); 341 w.set_syncsrc(crs::vals::Syncsrc::LSE));
342 CRS.cr().modify(|w| { 342 CRS.cr().modify(|w| {
343 w.set_autotrimen(true); 343 w.set_autotrimen(true);
344 w.set_cen(true); 344 w.set_cen(true);
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs
index c907fa88a..59a6eac8f 100644
--- a/embassy-stm32/src/rcc/l1.rs
+++ b/embassy-stm32/src/rcc/l1.rs
@@ -294,7 +294,7 @@ pub(crate) unsafe fn init(config: Config) {
294 AHBPrescaler::NotDivided => sys_clk, 294 AHBPrescaler::NotDivided => sys_clk,
295 pre => { 295 pre => {
296 let pre: Hpre = pre.into(); 296 let pre: Hpre = pre.into();
297 let pre = 1 << (pre.0 as u32 - 7); 297 let pre = 1 << (pre.to_bits() as u32 - 7);
298 sys_clk / pre 298 sys_clk / pre
299 } 299 }
300 }; 300 };
@@ -303,7 +303,7 @@ pub(crate) unsafe fn init(config: Config) {
303 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 303 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
304 pre => { 304 pre => {
305 let pre: Ppre = pre.into(); 305 let pre: Ppre = pre.into();
306 let pre: u8 = 1 << (pre.0 - 3); 306 let pre: u8 = 1 << (pre.to_bits() - 3);
307 let freq = ahb_freq / pre as u32; 307 let freq = ahb_freq / pre as u32;
308 (freq, freq * 2) 308 (freq, freq * 2)
309 } 309 }
@@ -313,7 +313,7 @@ pub(crate) unsafe fn init(config: Config) {
313 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 313 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
314 pre => { 314 pre => {
315 let pre: Ppre = pre.into(); 315 let pre: Ppre = pre.into();
316 let pre: u8 = 1 << (pre.0 - 3); 316 let pre: u8 = 1 << (pre.to_bits() - 3);
317 let freq = ahb_freq / pre as u32; 317 let freq = ahb_freq / pre as u32;
318 (freq, freq * 2) 318 (freq, freq * 2)
319 } 319 }
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index f7f3b9046..8a9b4adbf 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -656,7 +656,7 @@ pub(crate) unsafe fn init(config: Config) {
656 AHBPrescaler::NotDivided => sys_clk, 656 AHBPrescaler::NotDivided => sys_clk,
657 pre => { 657 pre => {
658 let pre: Hpre = pre.into(); 658 let pre: Hpre = pre.into();
659 let pre = 1 << (pre.0 as u32 - 7); 659 let pre = 1 << (pre.to_bits() as u32 - 7);
660 sys_clk / pre 660 sys_clk / pre
661 } 661 }
662 }; 662 };
@@ -665,7 +665,7 @@ pub(crate) unsafe fn init(config: Config) {
665 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 665 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
666 pre => { 666 pre => {
667 let pre: Ppre = pre.into(); 667 let pre: Ppre = pre.into();
668 let pre: u8 = 1 << (pre.0 - 3); 668 let pre: u8 = 1 << (pre.to_bits() - 3);
669 let freq = ahb_freq / pre as u32; 669 let freq = ahb_freq / pre as u32;
670 (freq, freq * 2) 670 (freq, freq * 2)
671 } 671 }
@@ -675,7 +675,7 @@ pub(crate) unsafe fn init(config: Config) {
675 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 675 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
676 pre => { 676 pre => {
677 let pre: Ppre = pre.into(); 677 let pre: Ppre = pre.into();
678 let pre: u8 = 1 << (pre.0 - 3); 678 let pre: u8 = 1 << (pre.to_bits() - 3);
679 let freq = ahb_freq / pre as u32; 679 let freq = ahb_freq / pre as u32;
680 (freq, freq * 2) 680 (freq, freq * 2)
681 } 681 }
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs
index f56fce365..16da65d5e 100644
--- a/embassy-stm32/src/rcc/l5.rs
+++ b/embassy-stm32/src/rcc/l5.rs
@@ -461,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
461 AHBPrescaler::NotDivided => sys_clk, 461 AHBPrescaler::NotDivided => sys_clk,
462 pre => { 462 pre => {
463 let pre: Hpre = pre.into(); 463 let pre: Hpre = pre.into();
464 let pre = 1 << (pre.0 as u32 - 7); 464 let pre = 1 << (pre.to_bits() as u32 - 7);
465 sys_clk / pre 465 sys_clk / pre
466 } 466 }
467 }; 467 };
@@ -470,7 +470,7 @@ pub(crate) unsafe fn init(config: Config) {
470 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 470 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
471 pre => { 471 pre => {
472 let pre: Ppre = pre.into(); 472 let pre: Ppre = pre.into();
473 let pre: u8 = 1 << (pre.0 - 3); 473 let pre: u8 = 1 << (pre.to_bits() - 3);
474 let freq = ahb_freq / pre as u32; 474 let freq = ahb_freq / pre as u32;
475 (freq, freq * 2) 475 (freq, freq * 2)
476 } 476 }
@@ -480,7 +480,7 @@ pub(crate) unsafe fn init(config: Config) {
480 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 480 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
481 pre => { 481 pre => {
482 let pre: Ppre = pre.into(); 482 let pre: Ppre = pre.into();
483 let pre: u8 = 1 << (pre.0 - 3); 483 let pre: u8 = 1 << (pre.to_bits() - 3);
484 let freq = ahb_freq / pre as u32; 484 let freq = ahb_freq / pre as u32;
485 (freq, freq * 2) 485 (freq, freq * 2)
486 } 486 }
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 81507a4d6..cfc07f069 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -126,7 +126,7 @@ pub enum PllM {
126 126
127impl Into<Pllm> for PllM { 127impl Into<Pllm> for PllM {
128 fn into(self) -> Pllm { 128 fn into(self) -> Pllm {
129 Pllm(self as u8) 129 Pllm::from_bits(self as u8)
130 } 130 }
131} 131}
132 132
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 1e16b8478..b2faec53d 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -34,40 +34,34 @@ impl<'d, T: Instance> Rng<'d, T> {
34 pub fn reset(&mut self) { 34 pub fn reset(&mut self) {
35 // rng_v2 locks up on seed error, needs reset 35 // rng_v2 locks up on seed error, needs reset
36 #[cfg(rng_v2)] 36 #[cfg(rng_v2)]
37 if unsafe { T::regs().sr().read().seis() } { 37 if T::regs().sr().read().seis() {
38 T::reset(); 38 T::reset();
39 } 39 }
40 unsafe { 40 T::regs().cr().modify(|reg| {
41 T::regs().cr().modify(|reg| { 41 reg.set_rngen(true);
42 reg.set_rngen(true); 42 reg.set_ie(true);
43 reg.set_ie(true); 43 });
44 }); 44 T::regs().sr().modify(|reg| {
45 T::regs().sr().modify(|reg| { 45 reg.set_seis(false);
46 reg.set_seis(false); 46 reg.set_ceis(false);
47 reg.set_ceis(false); 47 });
48 });
49 }
50 // Reference manual says to discard the first. 48 // Reference manual says to discard the first.
51 let _ = self.next_u32(); 49 let _ = self.next_u32();
52 } 50 }
53 51
54 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { 52 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
55 unsafe { 53 T::regs().cr().modify(|reg| {
56 T::regs().cr().modify(|reg| { 54 reg.set_rngen(true);
57 reg.set_rngen(true); 55 });
58 })
59 }
60 56
61 for chunk in dest.chunks_mut(4) { 57 for chunk in dest.chunks_mut(4) {
62 poll_fn(|cx| { 58 poll_fn(|cx| {
63 RNG_WAKER.register(cx.waker()); 59 RNG_WAKER.register(cx.waker());
64 unsafe { 60 T::regs().cr().modify(|reg| {
65 T::regs().cr().modify(|reg| { 61 reg.set_ie(true);
66 reg.set_ie(true); 62 });
67 });
68 }
69 63
70 let bits = unsafe { T::regs().sr().read() }; 64 let bits = T::regs().sr().read();
71 65
72 if bits.drdy() { 66 if bits.drdy() {
73 Poll::Ready(Ok(())) 67 Poll::Ready(Ok(()))
@@ -82,7 +76,7 @@ impl<'d, T: Instance> Rng<'d, T> {
82 } 76 }
83 }) 77 })
84 .await?; 78 .await?;
85 let random_bytes = unsafe { T::regs().dr().read() }.to_be_bytes(); 79 let random_bytes = T::regs().dr().read().to_be_bytes();
86 for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) { 80 for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) {
87 *dest = *src 81 *dest = *src
88 } 82 }
@@ -95,11 +89,11 @@ impl<'d, T: Instance> Rng<'d, T> {
95impl<'d, T: Instance> RngCore for Rng<'d, T> { 89impl<'d, T: Instance> RngCore for Rng<'d, T> {
96 fn next_u32(&mut self) -> u32 { 90 fn next_u32(&mut self) -> u32 {
97 loop { 91 loop {
98 let sr = unsafe { T::regs().sr().read() }; 92 let sr = T::regs().sr().read();
99 if sr.seis() | sr.ceis() { 93 if sr.seis() | sr.ceis() {
100 self.reset(); 94 self.reset();
101 } else if sr.drdy() { 95 } else if sr.drdy() {
102 return unsafe { T::regs().dr().read() }; 96 return T::regs().dr().read();
103 } 97 }
104 } 98 }
105 } 99 }
@@ -149,6 +143,7 @@ foreach_peripheral!(
149 }; 143 };
150); 144);
151 145
146#[cfg(feature = "rt")]
152macro_rules! irq { 147macro_rules! irq {
153 ($irq:ident) => { 148 ($irq:ident) => {
154 mod rng_irq { 149 mod rng_irq {
@@ -166,6 +161,7 @@ macro_rules! irq {
166 }; 161 };
167} 162}
168 163
164#[cfg(feature = "rt")]
169foreach_interrupt!( 165foreach_interrupt!(
170 (RNG) => { 166 (RNG) => {
171 irq!(RNG); 167 irq!(RNG);
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index 0a590c1bb..a9c48d88d 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -154,29 +154,27 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
154 let yr_offset = (yr - 1970_u16) as u8; 154 let yr_offset = (yr - 1970_u16) as u8;
155 let (yt, yu) = byte_to_bcd2(yr_offset); 155 let (yt, yu) = byte_to_bcd2(yr_offset);
156 156
157 unsafe { 157 use crate::pac::rtc::vals::Ampm;
158 use crate::pac::rtc::vals::Ampm; 158
159 159 rtc.tr().write(|w| {
160 rtc.tr().write(|w| { 160 w.set_ht(ht);
161 w.set_ht(ht); 161 w.set_hu(hu);
162 w.set_hu(hu); 162 w.set_mnt(mnt);
163 w.set_mnt(mnt); 163 w.set_mnu(mnu);
164 w.set_mnu(mnu); 164 w.set_st(st);
165 w.set_st(st); 165 w.set_su(su);
166 w.set_su(su); 166 w.set_pm(Ampm::AM);
167 w.set_pm(Ampm::AM); 167 });
168 }); 168
169 169 rtc.dr().write(|w| {
170 rtc.dr().write(|w| { 170 w.set_dt(dt);
171 w.set_dt(dt); 171 w.set_du(du);
172 w.set_du(du); 172 w.set_mt(mt > 0);
173 w.set_mt(mt > 0); 173 w.set_mu(mu);
174 w.set_mu(mu); 174 w.set_yt(yt);
175 w.set_yt(yt); 175 w.set_yu(yu);
176 w.set_yu(yu); 176 w.set_wdu(day_of_week_to_u8(t.day_of_week));
177 w.set_wdu(day_of_week_to_u8(t.day_of_week)); 177 });
178 });
179 }
180} 178}
181 179
182pub(super) fn datetime( 180pub(super) fn datetime(
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 962927fb1..12a2ac795 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod {
113 113
114impl<'d, T: Instance> Rtc<'d, T> { 114impl<'d, T: Instance> Rtc<'d, T> {
115 pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self { 115 pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self {
116 unsafe { T::enable_peripheral_clk() }; 116 T::enable_peripheral_clk();
117 117
118 let mut rtc_struct = Self { 118 let mut rtc_struct = Self {
119 phantom: PhantomData, 119 phantom: PhantomData,
@@ -144,34 +144,32 @@ impl<'d, T: Instance> Rtc<'d, T> {
144 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. 144 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
145 pub fn now(&self) -> Result<DateTime, RtcError> { 145 pub fn now(&self) -> Result<DateTime, RtcError> {
146 let r = T::regs(); 146 let r = T::regs();
147 unsafe { 147 let tr = r.tr().read();
148 let tr = r.tr().read(); 148 let second = bcd2_to_byte((tr.st(), tr.su()));
149 let second = bcd2_to_byte((tr.st(), tr.su())); 149 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
150 let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); 150 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
151 let hour = bcd2_to_byte((tr.ht(), tr.hu())); 151 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
152 // Reading either RTC_SSR or RTC_TR locks the values in the higher-order 152 // calendar shadow registers until RTC_DR is read.
153 // calendar shadow registers until RTC_DR is read. 153 let dr = r.dr().read();
154 let dr = r.dr().read(); 154
155 155 let weekday = dr.wdu();
156 let weekday = dr.wdu(); 156 let day = bcd2_to_byte((dr.dt(), dr.du()));
157 let day = bcd2_to_byte((dr.dt(), dr.du())); 157 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
158 let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); 158 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
159 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; 159
160 160 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
161 self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
162 }
163 } 161 }
164 162
165 /// Check if daylight savings time is active. 163 /// Check if daylight savings time is active.
166 pub fn get_daylight_savings(&self) -> bool { 164 pub fn get_daylight_savings(&self) -> bool {
167 let cr = unsafe { T::regs().cr().read() }; 165 let cr = T::regs().cr().read();
168 cr.bkp() 166 cr.bkp()
169 } 167 }
170 168
171 /// Enable/disable daylight savings time. 169 /// Enable/disable daylight savings time.
172 pub fn set_daylight_savings(&mut self, daylight_savings: bool) { 170 pub fn set_daylight_savings(&mut self, daylight_savings: bool) {
173 self.write(true, |rtc| { 171 self.write(true, |rtc| {
174 unsafe { rtc.cr().modify(|w| w.set_bkp(daylight_savings)) }; 172 rtc.cr().modify(|w| w.set_bkp(daylight_savings));
175 }) 173 })
176 } 174 }
177 175
@@ -228,7 +226,7 @@ pub(crate) mod sealed {
228 crate::pac::RTC 226 crate::pac::RTC
229 } 227 }
230 228
231 unsafe fn enable_peripheral_clk() {} 229 fn enable_peripheral_clk() {}
232 230
233 /// Read content of the backup register. 231 /// Read content of the backup register.
234 /// 232 ///
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index adaafe67a..a2eace6d3 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -8,74 +8,72 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
8 /// It this changes the RTC clock source the time will be reset 8 /// It this changes the RTC clock source the time will be reset
9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { 9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
10 // Unlock the backup domain 10 // Unlock the backup domain
11 unsafe { 11 let clock_config = rtc_config.clock_config as u8;
12 let clock_config = rtc_config.clock_config as u8;
13 12
14 #[cfg(not(rtc_v2wb))] 13 #[cfg(not(rtc_v2wb))]
15 use stm32_metapac::rcc::vals::Rtcsel; 14 use stm32_metapac::rcc::vals::Rtcsel;
16 15
17 #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] 16 #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))]
18 let cr = crate::pac::PWR.cr(); 17 let cr = crate::pac::PWR.cr();
19 #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] 18 #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
20 let cr = crate::pac::PWR.cr1(); 19 let cr = crate::pac::PWR.cr1();
21 20
22 // TODO: Missing from PAC for l0 and f0? 21 // TODO: Missing from PAC for l0 and f0?
23 #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] 22 #[cfg(not(any(rtc_v2f0, rtc_v2l0)))]
24 { 23 {
25 cr.modify(|w| w.set_dbp(true)); 24 cr.modify(|w| w.set_dbp(true));
26 while !cr.read().dbp() {} 25 while !cr.read().dbp() {}
27 } 26 }
28 27
29 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 28 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
30 let reg = crate::pac::RCC.bdcr().read(); 29 let reg = crate::pac::RCC.bdcr().read();
31 #[cfg(any(rtc_v2l0, rtc_v2l1))] 30 #[cfg(any(rtc_v2l0, rtc_v2l1))]
32 let reg = crate::pac::RCC.csr().read(); 31 let reg = crate::pac::RCC.csr().read();
33 32
34 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] 33 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))]
35 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 34 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
36 35
37 #[cfg(rtc_v2wb)] 36 #[cfg(rtc_v2wb)]
38 let rtcsel = reg.rtcsel(); 37 let rtcsel = reg.rtcsel();
39 #[cfg(not(rtc_v2wb))] 38 #[cfg(not(rtc_v2wb))]
40 let rtcsel = reg.rtcsel().0; 39 let rtcsel = reg.rtcsel().to_bits();
41 40
42 if !reg.rtcen() || rtcsel != clock_config { 41 if !reg.rtcen() || rtcsel != clock_config {
43 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 42 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
44 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); 43 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
45 44
45 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
46 let cr = crate::pac::RCC.bdcr();
47 #[cfg(any(rtc_v2l0, rtc_v2l1))]
48 let cr = crate::pac::RCC.csr();
49
50 cr.modify(|w| {
51 // Reset
46 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 52 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
47 let cr = crate::pac::RCC.bdcr(); 53 w.set_bdrst(false);
48 #[cfg(any(rtc_v2l0, rtc_v2l1))] 54
49 let cr = crate::pac::RCC.csr(); 55 // Select RTC source
50 56 #[cfg(not(rtc_v2wb))]
51 cr.modify(|w| { 57 w.set_rtcsel(Rtcsel::from_bits(clock_config));
52 // Reset 58 #[cfg(rtc_v2wb)]
53 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 59 w.set_rtcsel(clock_config);
54 w.set_bdrst(false); 60 w.set_rtcen(true);
55 61
56 // Select RTC source 62 // Restore bcdr
57 #[cfg(not(rtc_v2wb))] 63 #[cfg(any(rtc_v2l4, rtc_v2wb))]
58 w.set_rtcsel(Rtcsel(clock_config)); 64 w.set_lscosel(reg.lscosel());
59 #[cfg(rtc_v2wb)] 65 #[cfg(any(rtc_v2l4, rtc_v2wb))]
60 w.set_rtcsel(clock_config); 66 w.set_lscoen(reg.lscoen());
61 w.set_rtcen(true); 67
62 68 w.set_lseon(reg.lseon());
63 // Restore bcdr 69
64 #[cfg(any(rtc_v2l4, rtc_v2wb))] 70 #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
65 w.set_lscosel(reg.lscosel()); 71 w.set_lsedrv(reg.lsedrv());
66 #[cfg(any(rtc_v2l4, rtc_v2wb))] 72 w.set_lsebyp(reg.lsebyp());
67 w.set_lscoen(reg.lscoen()); 73 });
68
69 w.set_lseon(reg.lseon());
70
71 #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
72 w.set_lsedrv(reg.lsedrv());
73 w.set_lsebyp(reg.lsebyp());
74 });
75 }
76 } 74 }
77 75
78 self.write(true, |rtc| unsafe { 76 self.write(true, |rtc| {
79 rtc.cr().modify(|w| { 77 rtc.cr().modify(|w| {
80 #[cfg(rtc_v2f2)] 78 #[cfg(rtc_v2f2)]
81 w.set_fmt(false); 79 w.set_fmt(false);
@@ -117,47 +115,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
117 clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; 115 clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM;
118 116
119 self.write(false, |rtc| { 117 self.write(false, |rtc| {
120 unsafe { 118 rtc.calr().write(|w| {
121 rtc.calr().write(|w| { 119 match period {
122 match period { 120 super::RtcCalibrationCyclePeriod::Seconds8 => {
123 super::RtcCalibrationCyclePeriod::Seconds8 => { 121 w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND);
124 w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND);
125 }
126 super::RtcCalibrationCyclePeriod::Seconds16 => {
127 w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND);
128 }
129 super::RtcCalibrationCyclePeriod::Seconds32 => {
130 // Set neither `calw8` nor `calw16` to use 32 seconds
131 }
132 } 122 }
133 123 super::RtcCalibrationCyclePeriod::Seconds16 => {
134 // Extra pulses during calibration cycle period: CALP * 512 - CALM 124 w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND);
135 // 125 }
136 // CALP sets whether pulses are added or omitted. 126 super::RtcCalibrationCyclePeriod::Seconds32 => {
137 // 127 // Set neither `calw8` nor `calw16` to use 32 seconds
138 // CALM contains how many pulses (out of 512) are masked in a
139 // given calibration cycle period.
140 if clock_drift > 0.0 {
141 // Maximum (about 512.2) rounds to 512.
142 clock_drift += 0.5;
143
144 // When the offset is positive (0 to 512), the opposite of
145 // the offset (512 - offset) is masked, i.e. for the
146 // maximum offset (512), 0 pulses are masked.
147 w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ);
148 w.set_calm(512 - clock_drift as u16);
149 } else {
150 // Minimum (about -510.7) rounds to -511.
151 clock_drift -= 0.5;
152
153 // When the offset is negative or zero (-511 to 0),
154 // the absolute offset is masked, i.e. for the minimum
155 // offset (-511), 511 pulses are masked.
156 w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE);
157 w.set_calm((clock_drift * -1.0) as u16);
158 } 128 }
159 }); 129 }
160 } 130
131 // Extra pulses during calibration cycle period: CALP * 512 - CALM
132 //
133 // CALP sets whether pulses are added or omitted.
134 //
135 // CALM contains how many pulses (out of 512) are masked in a
136 // given calibration cycle period.
137 if clock_drift > 0.0 {
138 // Maximum (about 512.2) rounds to 512.
139 clock_drift += 0.5;
140
141 // When the offset is positive (0 to 512), the opposite of
142 // the offset (512 - offset) is masked, i.e. for the
143 // maximum offset (512), 0 pulses are masked.
144 w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ);
145 w.set_calm(512 - clock_drift as u16);
146 } else {
147 // Minimum (about -510.7) rounds to -511.
148 clock_drift -= 0.5;
149
150 // When the offset is negative or zero (-511 to 0),
151 // the absolute offset is masked, i.e. for the minimum
152 // offset (-511), 511 pulses are masked.
153 w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE);
154 w.set_calm((clock_drift * -1.0) as u16);
155 }
156 });
161 }) 157 })
162 } 158 }
163 159
@@ -168,31 +164,27 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
168 let r = T::regs(); 164 let r = T::regs();
169 // Disable write protection. 165 // Disable write protection.
170 // This is safe, as we're only writin the correct and expected values. 166 // This is safe, as we're only writin the correct and expected values.
171 unsafe { 167 r.wpr().write(|w| w.set_key(0xca));
172 r.wpr().write(|w| w.set_key(0xca)); 168 r.wpr().write(|w| w.set_key(0x53));
173 r.wpr().write(|w| w.set_key(0x53)); 169
174 170 // true if initf bit indicates RTC peripheral is in init mode
175 // true if initf bit indicates RTC peripheral is in init mode 171 if init_mode && !r.isr().read().initf() {
176 if init_mode && !r.isr().read().initf() { 172 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
177 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode 173 r.isr().modify(|w| w.set_init(Init::INITMODE));
178 r.isr().modify(|w| w.set_init(Init::INITMODE)); 174 // wait till init state entered
179 // wait till init state entered 175 // ~2 RTCCLK cycles
180 // ~2 RTCCLK cycles 176 while !r.isr().read().initf() {}
181 while !r.isr().read().initf() {}
182 }
183 } 177 }
184 178
185 let result = f(&r); 179 let result = f(&r);
186 180
187 unsafe { 181 if init_mode {
188 if init_mode { 182 r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
189 r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
190 }
191
192 // Re-enable write protection.
193 // This is safe, as the field accepts the full range of 8-bit values.
194 r.wpr().write(|w| w.set_key(0xff));
195 } 183 }
184
185 // Re-enable write protection.
186 // This is safe, as the field accepts the full range of 8-bit values.
187 r.wpr().write(|w| w.set_key(0xff));
196 result 188 result
197 } 189 }
198} 190}
@@ -200,7 +192,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
200impl sealed::Instance for crate::peripherals::RTC { 192impl sealed::Instance for crate::peripherals::RTC {
201 const BACKUP_REGISTER_COUNT: usize = 20; 193 const BACKUP_REGISTER_COUNT: usize = 20;
202 194
203 unsafe fn enable_peripheral_clk() { 195 fn enable_peripheral_clk() {
204 #[cfg(any(rtc_v2l4, rtc_v2wb))] 196 #[cfg(any(rtc_v2l4, rtc_v2wb))]
205 { 197 {
206 // enable peripheral clock for communication 198 // enable peripheral clock for communication
@@ -213,7 +205,7 @@ impl sealed::Instance for crate::peripherals::RTC {
213 205
214 fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { 206 fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
215 if register < Self::BACKUP_REGISTER_COUNT { 207 if register < Self::BACKUP_REGISTER_COUNT {
216 Some(unsafe { rtc.bkpr(register).read().bkp() }) 208 Some(rtc.bkpr(register).read().bkp())
217 } else { 209 } else {
218 None 210 None
219 } 211 }
@@ -221,7 +213,7 @@ impl sealed::Instance for crate::peripherals::RTC {
221 213
222 fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { 214 fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
223 if register < Self::BACKUP_REGISTER_COUNT { 215 if register < Self::BACKUP_REGISTER_COUNT {
224 unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) } 216 rtc.bkpr(register).write(|w| w.set_bkp(value));
225 } 217 }
226 } 218 }
227} 219}
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 24f6496a6..7e5c64d90 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -8,70 +8,66 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
8 /// It this changes the RTC clock source the time will be reset 8 /// It this changes the RTC clock source the time will be reset
9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { 9 pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
10 // Unlock the backup domain 10 // Unlock the backup domain
11 unsafe { 11 #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
12 #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] 12 {
13 { 13 crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
14 crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); 14 while !crate::pac::PWR.cr1().read().dbp() {}
15 while !crate::pac::PWR.cr1().read().dbp() {} 15 }
16 } 16 #[cfg(any(rcc_wl5, rcc_wle))]
17 #[cfg(any(rcc_wl5, rcc_wle))] 17 {
18 { 18 use crate::pac::pwr::vals::Dbp;
19 use crate::pac::pwr::vals::Dbp; 19
20 20 crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
21 crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); 21 while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {}
22 while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} 22 }
23 } 23
24 24 let reg = crate::pac::RCC.bdcr().read();
25 let reg = crate::pac::RCC.bdcr().read(); 25 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
26 assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 26
27 27 let config_rtcsel = rtc_config.clock_config as u8;
28 let config_rtcsel = rtc_config.clock_config as u8; 28 #[cfg(not(any(rcc_wl5, rcc_wle)))]
29 #[cfg(not(any(rcc_wl5, rcc_wle)))] 29 let config_rtcsel = crate::pac::rcc::vals::Rtcsel::from_bits(config_rtcsel);
30 let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel); 30
31 31 if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
32 if !reg.rtcen() || reg.rtcsel() != config_rtcsel { 32 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
33 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); 33
34 34 crate::pac::RCC.bdcr().modify(|w| {
35 crate::pac::RCC.bdcr().modify(|w| { 35 // Reset
36 // Reset 36 w.set_bdrst(false);
37 w.set_bdrst(false); 37
38 38 // Select RTC source
39 // Select RTC source 39 w.set_rtcsel(config_rtcsel);
40 w.set_rtcsel(config_rtcsel); 40
41 41 w.set_rtcen(true);
42 w.set_rtcen(true); 42
43 43 // Restore bcdr
44 // Restore bcdr 44 w.set_lscosel(reg.lscosel());
45 w.set_lscosel(reg.lscosel()); 45 w.set_lscoen(reg.lscoen());
46 w.set_lscoen(reg.lscoen()); 46
47 47 w.set_lseon(reg.lseon());
48 w.set_lseon(reg.lseon()); 48 w.set_lsedrv(reg.lsedrv());
49 w.set_lsedrv(reg.lsedrv()); 49 w.set_lsebyp(reg.lsebyp());
50 w.set_lsebyp(reg.lsebyp()); 50 });
51 });
52 }
53 } 51 }
54 52
55 self.write(true, |rtc| { 53 self.write(true, |rtc| {
56 unsafe { 54 rtc.cr().modify(|w| {
57 rtc.cr().modify(|w| { 55 w.set_fmt(Fmt::TWENTYFOURHOUR);
58 w.set_fmt(Fmt::TWENTYFOURHOUR); 56 w.set_osel(Osel::DISABLED);
59 w.set_osel(Osel::DISABLED); 57 w.set_pol(Pol::HIGH);
60 w.set_pol(Pol::HIGH); 58 });
61 }); 59
62 60 rtc.prer().modify(|w| {
63 rtc.prer().modify(|w| { 61 w.set_prediv_s(rtc_config.sync_prescaler);
64 w.set_prediv_s(rtc_config.sync_prescaler); 62 w.set_prediv_a(rtc_config.async_prescaler);
65 w.set_prediv_a(rtc_config.async_prescaler); 63 });
66 }); 64
67 65 // TODO: configuration for output pins
68 // TODO: configuration for output pins 66 rtc.cr().modify(|w| {
69 rtc.cr().modify(|w| { 67 w.set_out2en(false);
70 w.set_out2en(false); 68 w.set_tampalrm_type(TampalrmType::PUSHPULL);
71 w.set_tampalrm_type(TampalrmType::PUSHPULL); 69 w.set_tampalrm_pu(TampalrmPu::NOPULLUP);
72 w.set_tampalrm_pu(TampalrmPu::NOPULLUP); 70 });
73 });
74 }
75 }); 71 });
76 72
77 self.rtc_config = rtc_config; 73 self.rtc_config = rtc_config;
@@ -99,47 +95,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
99 clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM; 95 clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM;
100 96
101 self.write(false, |rtc| { 97 self.write(false, |rtc| {
102 unsafe { 98 rtc.calr().write(|w| {
103 rtc.calr().write(|w| { 99 match period {
104 match period { 100 RtcCalibrationCyclePeriod::Seconds8 => {
105 RtcCalibrationCyclePeriod::Seconds8 => { 101 w.set_calw8(Calw8::EIGHTSECONDS);
106 w.set_calw8(Calw8::EIGHTSECONDS);
107 }
108 RtcCalibrationCyclePeriod::Seconds16 => {
109 w.set_calw16(Calw16::SIXTEENSECONDS);
110 }
111 RtcCalibrationCyclePeriod::Seconds32 => {
112 // Set neither `calw8` nor `calw16` to use 32 seconds
113 }
114 } 102 }
115 103 RtcCalibrationCyclePeriod::Seconds16 => {
116 // Extra pulses during calibration cycle period: CALP * 512 - CALM 104 w.set_calw16(Calw16::SIXTEENSECONDS);
117 //
118 // CALP sets whether pulses are added or omitted.
119 //
120 // CALM contains how many pulses (out of 512) are masked in a
121 // given calibration cycle period.
122 if clock_drift > 0.0 {
123 // Maximum (about 512.2) rounds to 512.
124 clock_drift += 0.5;
125
126 // When the offset is positive (0 to 512), the opposite of
127 // the offset (512 - offset) is masked, i.e. for the
128 // maximum offset (512), 0 pulses are masked.
129 w.set_calp(Calp::INCREASEFREQ);
130 w.set_calm(512 - clock_drift as u16);
131 } else {
132 // Minimum (about -510.7) rounds to -511.
133 clock_drift -= 0.5;
134
135 // When the offset is negative or zero (-511 to 0),
136 // the absolute offset is masked, i.e. for the minimum
137 // offset (-511), 511 pulses are masked.
138 w.set_calp(Calp::NOCHANGE);
139 w.set_calm((clock_drift * -1.0) as u16);
140 } 105 }
141 }); 106 RtcCalibrationCyclePeriod::Seconds32 => {
142 } 107 // Set neither `calw8` nor `calw16` to use 32 seconds
108 }
109 }
110
111 // Extra pulses during calibration cycle period: CALP * 512 - CALM
112 //
113 // CALP sets whether pulses are added or omitted.
114 //
115 // CALM contains how many pulses (out of 512) are masked in a
116 // given calibration cycle period.
117 if clock_drift > 0.0 {
118 // Maximum (about 512.2) rounds to 512.
119 clock_drift += 0.5;
120
121 // When the offset is positive (0 to 512), the opposite of
122 // the offset (512 - offset) is masked, i.e. for the
123 // maximum offset (512), 0 pulses are masked.
124 w.set_calp(Calp::INCREASEFREQ);
125 w.set_calm(512 - clock_drift as u16);
126 } else {
127 // Minimum (about -510.7) rounds to -511.
128 clock_drift -= 0.5;
129
130 // When the offset is negative or zero (-511 to 0),
131 // the absolute offset is masked, i.e. for the minimum
132 // offset (-511), 511 pulses are masked.
133 w.set_calp(Calp::NOCHANGE);
134 w.set_calm((clock_drift * -1.0) as u16);
135 }
136 });
143 }) 137 })
144 } 138 }
145 139
@@ -150,29 +144,26 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
150 let r = T::regs(); 144 let r = T::regs();
151 // Disable write protection. 145 // Disable write protection.
152 // This is safe, as we're only writin the correct and expected values. 146 // This is safe, as we're only writin the correct and expected values.
153 unsafe { 147 r.wpr().write(|w| w.set_key(Key::DEACTIVATE1));
154 r.wpr().write(|w| w.set_key(Key::DEACTIVATE1)); 148 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
155 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); 149
156 150 if init_mode && !r.icsr().read().initf() {
157 if init_mode && !r.icsr().read().initf() { 151 r.icsr().modify(|w| w.set_init(Init::INITMODE));
158 r.icsr().modify(|w| w.set_init(Init::INITMODE)); 152 // wait till init state entered
159 // wait till init state entered 153 // ~2 RTCCLK cycles
160 // ~2 RTCCLK cycles 154 while !r.icsr().read().initf() {}
161 while !r.icsr().read().initf() {}
162 }
163 } 155 }
164 156
165 let result = f(&r); 157 let result = f(&r);
166 158
167 unsafe { 159 if init_mode {
168 if init_mode { 160 r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
169 r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
170 }
171
172 // Re-enable write protection.
173 // This is safe, as the field accepts the full range of 8-bit values.
174 r.wpr().write(|w| w.set_key(Key::ACTIVATE));
175 } 161 }
162
163 // Re-enable write protection.
164 // This is safe, as the field accepts the full range of 8-bit values.
165 r.wpr().write(|w| w.set_key(Key::ACTIVATE));
166
176 result 167 result
177 } 168 }
178} 169}
@@ -192,7 +183,7 @@ impl sealed::Instance for crate::peripherals::RTC {
192 fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { 183 fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
193 if register < Self::BACKUP_REGISTER_COUNT { 184 if register < Self::BACKUP_REGISTER_COUNT {
194 // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC 185 // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
195 //unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) } 186 //self.rtc.bkpr()[register].write(|w| w.bits(value))
196 } 187 }
197 } 188 }
198} 189}
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 3cc17aa68..698292bff 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -14,7 +14,7 @@ use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID,
14use crate::dma::NoDma; 14use crate::dma::NoDma;
15use crate::gpio::sealed::{AFType, Pin}; 15use crate::gpio::sealed::{AFType, Pin};
16use crate::gpio::{AnyPin, Pull, Speed}; 16use crate::gpio::{AnyPin, Pull, Speed};
17use crate::interrupt::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::sdmmc::Sdmmc as RegBlock; 18use crate::pac::sdmmc::Sdmmc as RegBlock;
19use crate::rcc::RccPeripheral; 19use crate::rcc::RccPeripheral;
20use crate::time::Hertz; 20use crate::time::Hertz;
@@ -28,21 +28,18 @@ pub struct InterruptHandler<T: Instance> {
28impl<T: Instance> InterruptHandler<T> { 28impl<T: Instance> InterruptHandler<T> {
29 fn data_interrupts(enable: bool) { 29 fn data_interrupts(enable: bool) {
30 let regs = T::regs(); 30 let regs = T::regs();
31 // NOTE(unsafe) Atomic write 31 regs.maskr().write(|w| {
32 unsafe { 32 w.set_dcrcfailie(enable);
33 regs.maskr().write(|w| { 33 w.set_dtimeoutie(enable);
34 w.set_dcrcfailie(enable); 34 w.set_dataendie(enable);
35 w.set_dtimeoutie(enable);
36 w.set_dataendie(enable);
37 35
38 #[cfg(sdmmc_v2)] 36 #[cfg(sdmmc_v2)]
39 w.set_dabortie(enable); 37 w.set_dabortie(enable);
40 }); 38 });
41 }
42 } 39 }
43} 40}
44 41
45impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 42impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
46 unsafe fn on_interrupt() { 43 unsafe fn on_interrupt() {
47 Self::data_interrupts(false); 44 Self::data_interrupts(false);
48 T::state().wake(); 45 T::state().wake();
@@ -230,7 +227,11 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp
230 fifo_threshold: Some(crate::dma::FifoThreshold::Full), 227 fifo_threshold: Some(crate::dma::FifoThreshold::Full),
231}; 228};
232#[cfg(all(sdmmc_v1, not(dma)))] 229#[cfg(all(sdmmc_v1, not(dma)))]
233const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {}; 230const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
231 circular: false,
232 half_transfer_ir: false,
233 complete_transfer_ir: true,
234};
234 235
235/// SDMMC configuration 236/// SDMMC configuration
236/// 237///
@@ -276,7 +277,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
276impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { 277impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
277 pub fn new_1bit( 278 pub fn new_1bit(
278 sdmmc: impl Peripheral<P = T> + 'd, 279 sdmmc: impl Peripheral<P = T> + 'd,
279 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 280 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
280 dma: impl Peripheral<P = Dma> + 'd, 281 dma: impl Peripheral<P = Dma> + 'd,
281 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 282 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
282 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 283 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
@@ -285,7 +286,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
285 ) -> Self { 286 ) -> Self {
286 into_ref!(clk, cmd, d0); 287 into_ref!(clk, cmd, d0);
287 288
288 critical_section::with(|_| unsafe { 289 critical_section::with(|_| {
289 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 290 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
290 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 291 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
291 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 292 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -310,7 +311,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
310 311
311 pub fn new_4bit( 312 pub fn new_4bit(
312 sdmmc: impl Peripheral<P = T> + 'd, 313 sdmmc: impl Peripheral<P = T> + 'd,
313 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 314 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
314 dma: impl Peripheral<P = Dma> + 'd, 315 dma: impl Peripheral<P = Dma> + 'd,
315 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 316 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
316 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 317 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
@@ -322,7 +323,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
322 ) -> Self { 323 ) -> Self {
323 into_ref!(clk, cmd, d0, d1, d2, d3); 324 into_ref!(clk, cmd, d0, d1, d2, d3);
324 325
325 critical_section::with(|_| unsafe { 326 critical_section::with(|_| {
326 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 327 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
327 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 328 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
328 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 329 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -356,7 +357,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
356impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { 357impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
357 pub fn new_1bit( 358 pub fn new_1bit(
358 sdmmc: impl Peripheral<P = T> + 'd, 359 sdmmc: impl Peripheral<P = T> + 'd,
359 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 360 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
360 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 361 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
361 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 362 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
362 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 363 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
@@ -364,7 +365,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
364 ) -> Self { 365 ) -> Self {
365 into_ref!(clk, cmd, d0); 366 into_ref!(clk, cmd, d0);
366 367
367 critical_section::with(|_| unsafe { 368 critical_section::with(|_| {
368 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 369 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
369 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 370 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
370 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 371 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -389,7 +390,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
389 390
390 pub fn new_4bit( 391 pub fn new_4bit(
391 sdmmc: impl Peripheral<P = T> + 'd, 392 sdmmc: impl Peripheral<P = T> + 'd,
392 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 393 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
393 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 394 clk: impl Peripheral<P = impl CkPin<T>> + 'd,
394 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 395 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
395 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 396 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
@@ -400,7 +401,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
400 ) -> Self { 401 ) -> Self {
401 into_ref!(clk, cmd, d0, d1, d2, d3); 402 into_ref!(clk, cmd, d0, d1, d2, d3);
402 403
403 critical_section::with(|_| unsafe { 404 critical_section::with(|_| {
404 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); 405 clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
405 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); 406 cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
406 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); 407 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@@ -451,26 +452,24 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
451 unsafe { T::Interrupt::enable() }; 452 unsafe { T::Interrupt::enable() };
452 453
453 let regs = T::regs(); 454 let regs = T::regs();
454 unsafe { 455 regs.clkcr().write(|w| {
455 regs.clkcr().write(|w| { 456 w.set_pwrsav(false);
456 w.set_pwrsav(false); 457 w.set_negedge(false);
457 w.set_negedge(false);
458
459 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
460 // See chip erratas for more details.
461 #[cfg(sdmmc_v1)]
462 w.set_hwfc_en(false);
463 #[cfg(sdmmc_v2)]
464 w.set_hwfc_en(true);
465 458
466 #[cfg(sdmmc_v1)] 459 // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
467 w.set_clken(true); 460 // See chip erratas for more details.
468 }); 461 #[cfg(sdmmc_v1)]
462 w.set_hwfc_en(false);
463 #[cfg(sdmmc_v2)]
464 w.set_hwfc_en(true);
469 465
470 // Power off, writen 00: Clock to the card is stopped; 466 #[cfg(sdmmc_v1)]
471 // D[7:0], CMD, and CK are driven high. 467 w.set_clken(true);
472 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); 468 });
473 } 469
470 // Power off, writen 00: Clock to the card is stopped;
471 // D[7:0], CMD, and CK are driven high.
472 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
474 473
475 Self { 474 Self {
476 _peri: sdmmc, 475 _peri: sdmmc,
@@ -495,14 +494,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
495 fn data_active() -> bool { 494 fn data_active() -> bool {
496 let regs = T::regs(); 495 let regs = T::regs();
497 496
498 // NOTE(unsafe) Atomic read with no side-effects 497 let status = regs.star().read();
499 unsafe { 498 #[cfg(sdmmc_v1)]
500 let status = regs.star().read(); 499 return status.rxact() || status.txact();
501 #[cfg(sdmmc_v1)] 500 #[cfg(sdmmc_v2)]
502 return status.rxact() || status.txact(); 501 return status.dpsmact();
503 #[cfg(sdmmc_v2)]
504 return status.dpsmact();
505 }
506 } 502 }
507 503
508 /// Coammand transfer is in progress 504 /// Coammand transfer is in progress
@@ -510,14 +506,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
510 fn cmd_active() -> bool { 506 fn cmd_active() -> bool {
511 let regs = T::regs(); 507 let regs = T::regs();
512 508
513 // NOTE(unsafe) Atomic read with no side-effects 509 let status = regs.star().read();
514 unsafe { 510 #[cfg(sdmmc_v1)]
515 let status = regs.star().read(); 511 return status.cmdact();
516 #[cfg(sdmmc_v1)] 512 #[cfg(sdmmc_v2)]
517 return status.cmdact(); 513 return status.cpsmact();
518 #[cfg(sdmmc_v2)]
519 return status.cpsmact();
520 }
521 } 514 }
522 515
523 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 516 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
@@ -542,44 +535,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
542 Self::wait_idle(); 535 Self::wait_idle();
543 Self::clear_interrupt_flags(); 536 Self::clear_interrupt_flags();
544 537
545 // NOTE(unsafe) We have exclusive access to the regisers 538 regs.dtimer()
546 unsafe { 539 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
547 regs.dtimer() 540 regs.dlenr().write(|w| w.set_datalength(length_bytes));
548 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
549 regs.dlenr().write(|w| w.set_datalength(length_bytes));
550 541
551 #[cfg(sdmmc_v1)] 542 #[cfg(sdmmc_v1)]
552 let transfer = { 543 let transfer = unsafe {
553 let request = self.dma.request(); 544 let request = self.dma.request();
554 Transfer::new_read( 545 Transfer::new_read(
555 &mut self.dma, 546 &mut self.dma,
556 request, 547 request,
557 regs.fifor().ptr() as *mut u32, 548 regs.fifor().as_ptr() as *mut u32,
558 buffer, 549 buffer,
559 DMA_TRANSFER_OPTIONS, 550 DMA_TRANSFER_OPTIONS,
560 ) 551 )
561 }; 552 };
562 #[cfg(sdmmc_v2)] 553 #[cfg(sdmmc_v2)]
563 let transfer = { 554 let transfer = {
564 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); 555 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
565 regs.idmactrlr().modify(|w| w.set_idmaen(true)); 556 regs.idmactrlr().modify(|w| w.set_idmaen(true));
566 Transfer { 557 Transfer {
567 _dummy: core::marker::PhantomData, 558 _dummy: core::marker::PhantomData,
568 } 559 }
569 }; 560 };
570 561
571 regs.dctrl().modify(|w| { 562 regs.dctrl().modify(|w| {
572 w.set_dblocksize(block_size); 563 w.set_dblocksize(block_size);
573 w.set_dtdir(true); 564 w.set_dtdir(true);
574 #[cfg(sdmmc_v1)] 565 #[cfg(sdmmc_v1)]
575 { 566 {
576 w.set_dmaen(true); 567 w.set_dmaen(true);
577 w.set_dten(true); 568 w.set_dten(true);
578 } 569 }
579 }); 570 });
580 571
581 transfer 572 transfer
582 }
583 } 573 }
584 574
585 /// # Safety 575 /// # Safety
@@ -598,59 +588,54 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
598 Self::wait_idle(); 588 Self::wait_idle();
599 Self::clear_interrupt_flags(); 589 Self::clear_interrupt_flags();
600 590
601 // NOTE(unsafe) We have exclusive access to the regisers 591 regs.dtimer()
602 unsafe { 592 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
603 regs.dtimer() 593 regs.dlenr().write(|w| w.set_datalength(length_bytes));
604 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
605 regs.dlenr().write(|w| w.set_datalength(length_bytes));
606 594
607 #[cfg(sdmmc_v1)] 595 #[cfg(sdmmc_v1)]
608 let transfer = { 596 let transfer = unsafe {
609 let request = self.dma.request(); 597 let request = self.dma.request();
610 Transfer::new_write( 598 Transfer::new_write(
611 &mut self.dma, 599 &mut self.dma,
612 request, 600 request,
613 buffer, 601 buffer,
614 regs.fifor().ptr() as *mut u32, 602 regs.fifor().as_ptr() as *mut u32,
615 DMA_TRANSFER_OPTIONS, 603 DMA_TRANSFER_OPTIONS,
616 ) 604 )
617 }; 605 };
618 #[cfg(sdmmc_v2)] 606 #[cfg(sdmmc_v2)]
619 let transfer = { 607 let transfer = {
620 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32)); 608 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
621 regs.idmactrlr().modify(|w| w.set_idmaen(true)); 609 regs.idmactrlr().modify(|w| w.set_idmaen(true));
622 Transfer { 610 Transfer {
623 _dummy: core::marker::PhantomData, 611 _dummy: core::marker::PhantomData,
624 } 612 }
625 }; 613 };
626 614
627 regs.dctrl().modify(|w| { 615 regs.dctrl().modify(|w| {
628 w.set_dblocksize(block_size); 616 w.set_dblocksize(block_size);
629 w.set_dtdir(false); 617 w.set_dtdir(false);
630 #[cfg(sdmmc_v1)] 618 #[cfg(sdmmc_v1)]
631 { 619 {
632 w.set_dmaen(true); 620 w.set_dmaen(true);
633 w.set_dten(true); 621 w.set_dten(true);
634 } 622 }
635 }); 623 });
636 624
637 transfer 625 transfer
638 }
639 } 626 }
640 627
641 /// Stops the DMA datapath 628 /// Stops the DMA datapath
642 fn stop_datapath() { 629 fn stop_datapath() {
643 let regs = T::regs(); 630 let regs = T::regs();
644 631
645 unsafe { 632 #[cfg(sdmmc_v1)]
646 #[cfg(sdmmc_v1)] 633 regs.dctrl().modify(|w| {
647 regs.dctrl().modify(|w| { 634 w.set_dmaen(false);
648 w.set_dmaen(false); 635 w.set_dten(false);
649 w.set_dten(false); 636 });
650 }); 637 #[cfg(sdmmc_v2)]
651 #[cfg(sdmmc_v2)] 638 regs.idmactrlr().modify(|w| w.set_idmaen(false));
652 regs.idmactrlr().modify(|w| w.set_idmaen(false));
653 }
654 } 639 }
655 640
656 /// Sets the CLKDIV field in CLKCR. Updates clock field in self 641 /// Sets the CLKDIV field in CLKCR. Updates clock field in self
@@ -673,16 +658,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
673 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); 658 assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
674 self.clock = new_clock; 659 self.clock = new_clock;
675 660
676 // NOTE(unsafe) We have exclusive access to the regblock 661 // CPSMACT and DPSMACT must be 0 to set CLKDIV
677 unsafe { 662 Self::wait_idle();
678 // CPSMACT and DPSMACT must be 0 to set CLKDIV 663 regs.clkcr().modify(|w| {
679 Self::wait_idle(); 664 w.set_clkdiv(clkdiv);
680 regs.clkcr().modify(|w| { 665 #[cfg(sdmmc_v1)]
681 w.set_clkdiv(clkdiv); 666 w.set_bypass(_bypass);
682 #[cfg(sdmmc_v1)] 667 });
683 w.set_bypass(_bypass);
684 });
685 }
686 668
687 Ok(()) 669 Ok(())
688 } 670 }
@@ -710,7 +692,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
710 692
711 // Arm `OnDrop` after the buffer, so it will be dropped first 693 // Arm `OnDrop` after the buffer, so it will be dropped first
712 let regs = T::regs(); 694 let regs = T::regs();
713 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 695 let on_drop = OnDrop::new(|| Self::on_drop());
714 696
715 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 697 let transfer = self.prepare_datapath_read(&mut status, 64, 6);
716 InterruptHandler::<T>::data_interrupts(true); 698 InterruptHandler::<T>::data_interrupts(true);
@@ -718,7 +700,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
718 700
719 let res = poll_fn(|cx| { 701 let res = poll_fn(|cx| {
720 T::state().register(cx.waker()); 702 T::state().register(cx.waker());
721 let status = unsafe { regs.star().read() }; 703 let status = regs.star().read();
722 704
723 if status.dcrcfail() { 705 if status.dcrcfail() {
724 return Poll::Ready(Err(Error::Crc)); 706 return Poll::Ready(Err(Error::Crc));
@@ -769,8 +751,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
769 751
770 Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 752 Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13
771 753
772 // NOTE(unsafe) Atomic read with no side-effects 754 let r1 = regs.respr(0).read().cardstatus();
773 let r1 = unsafe { regs.respr(0).read().cardstatus() };
774 Ok(r1.into()) 755 Ok(r1.into())
775 } 756 }
776 757
@@ -786,7 +767,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
786 767
787 // Arm `OnDrop` after the buffer, so it will be dropped first 768 // Arm `OnDrop` after the buffer, so it will be dropped first
788 let regs = T::regs(); 769 let regs = T::regs();
789 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 770 let on_drop = OnDrop::new(|| Self::on_drop());
790 771
791 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 772 let transfer = self.prepare_datapath_read(&mut status, 64, 6);
792 InterruptHandler::<T>::data_interrupts(true); 773 InterruptHandler::<T>::data_interrupts(true);
@@ -794,7 +775,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
794 775
795 let res = poll_fn(|cx| { 776 let res = poll_fn(|cx| {
796 T::state().register(cx.waker()); 777 T::state().register(cx.waker());
797 let status = unsafe { regs.star().read() }; 778 let status = regs.star().read();
798 779
799 if status.dcrcfail() { 780 if status.dcrcfail() {
800 return Poll::Ready(Err(Error::Crc)); 781 return Poll::Ready(Err(Error::Crc));
@@ -840,35 +821,32 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
840 #[inline(always)] 821 #[inline(always)]
841 fn clear_interrupt_flags() { 822 fn clear_interrupt_flags() {
842 let regs = T::regs(); 823 let regs = T::regs();
843 // NOTE(unsafe) Atomic write 824 regs.icr().write(|w| {
844 unsafe { 825 w.set_ccrcfailc(true);
845 regs.icr().write(|w| { 826 w.set_dcrcfailc(true);
846 w.set_ccrcfailc(true); 827 w.set_ctimeoutc(true);
847 w.set_dcrcfailc(true); 828 w.set_dtimeoutc(true);
848 w.set_ctimeoutc(true); 829 w.set_txunderrc(true);
849 w.set_dtimeoutc(true); 830 w.set_rxoverrc(true);
850 w.set_txunderrc(true); 831 w.set_cmdrendc(true);
851 w.set_rxoverrc(true); 832 w.set_cmdsentc(true);
852 w.set_cmdrendc(true); 833 w.set_dataendc(true);
853 w.set_cmdsentc(true); 834 w.set_dbckendc(true);
854 w.set_dataendc(true); 835 w.set_sdioitc(true);
855 w.set_dbckendc(true);
856 w.set_sdioitc(true);
857 836
858 #[cfg(sdmmc_v2)] 837 #[cfg(sdmmc_v2)]
859 { 838 {
860 w.set_dholdc(true); 839 w.set_dholdc(true);
861 w.set_dabortc(true); 840 w.set_dabortc(true);
862 w.set_busyd0endc(true); 841 w.set_busyd0endc(true);
863 w.set_ackfailc(true); 842 w.set_ackfailc(true);
864 w.set_acktimeoutc(true); 843 w.set_acktimeoutc(true);
865 w.set_vswendc(true); 844 w.set_vswendc(true);
866 w.set_ckstopc(true); 845 w.set_ckstopc(true);
867 w.set_idmatec(true); 846 w.set_idmatec(true);
868 w.set_idmabtcc(true); 847 w.set_idmabtcc(true);
869 } 848 }
870 }); 849 });
871 }
872 } 850 }
873 851
874 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { 852 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
@@ -880,7 +858,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
880 858
881 // Arm `OnDrop` after the buffer, so it will be dropped first 859 // Arm `OnDrop` after the buffer, so it will be dropped first
882 let regs = T::regs(); 860 let regs = T::regs();
883 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 861 let on_drop = OnDrop::new(|| Self::on_drop());
884 862
885 let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); 863 let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
886 InterruptHandler::<T>::data_interrupts(true); 864 InterruptHandler::<T>::data_interrupts(true);
@@ -888,7 +866,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
888 866
889 let res = poll_fn(|cx| { 867 let res = poll_fn(|cx| {
890 T::state().register(cx.waker()); 868 T::state().register(cx.waker());
891 let status = unsafe { regs.star().read() }; 869 let status = regs.star().read();
892 870
893 if status.dcrcfail() { 871 if status.dcrcfail() {
894 return Poll::Ready(Err(Error::Crc)); 872 return Poll::Ready(Err(Error::Crc));
@@ -921,59 +899,53 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
921 let regs = T::regs(); 899 let regs = T::regs();
922 900
923 Self::clear_interrupt_flags(); 901 Self::clear_interrupt_flags();
924 // NOTE(safety) Atomic operations 902 // CP state machine must be idle
925 unsafe { 903 while Self::cmd_active() {}
926 // CP state machine must be idle
927 while Self::cmd_active() {}
928 904
929 // Command arg 905 // Command arg
930 regs.argr().write(|w| w.set_cmdarg(cmd.arg)); 906 regs.argr().write(|w| w.set_cmdarg(cmd.arg));
931 907
932 // Command index and start CP State Machine 908 // Command index and start CP State Machine
933 regs.cmdr().write(|w| { 909 regs.cmdr().write(|w| {
934 w.set_waitint(false); 910 w.set_waitint(false);
935 w.set_waitresp(cmd.resp as u8); 911 w.set_waitresp(cmd.resp as u8);
936 w.set_cmdindex(cmd.cmd); 912 w.set_cmdindex(cmd.cmd);
937 w.set_cpsmen(true); 913 w.set_cpsmen(true);
938 914
939 #[cfg(sdmmc_v2)] 915 #[cfg(sdmmc_v2)]
940 { 916 {
941 // Special mode in CP State Machine 917 // Special mode in CP State Machine
942 // CMD12: Stop Transmission 918 // CMD12: Stop Transmission
943 let cpsm_stop_transmission = cmd.cmd == 12; 919 let cpsm_stop_transmission = cmd.cmd == 12;
944 w.set_cmdstop(cpsm_stop_transmission); 920 w.set_cmdstop(cpsm_stop_transmission);
945 w.set_cmdtrans(data); 921 w.set_cmdtrans(data);
946 }
947 });
948
949 let mut status;
950 if cmd.resp == Response::None {
951 // Wait for CMDSENT or a timeout
952 while {
953 status = regs.star().read();
954 !(status.ctimeout() || status.cmdsent())
955 } {}
956 } else {
957 // Wait for CMDREND or CCRCFAIL or a timeout
958 while {
959 status = regs.star().read();
960 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
961 } {}
962 } 922 }
923 });
963 924
964 if status.ctimeout() { 925 let mut status;
965 return Err(Error::Timeout); 926 if cmd.resp == Response::None {
966 } else if status.ccrcfail() { 927 // Wait for CMDSENT or a timeout
967 return Err(Error::Crc); 928 while {
968 } 929 status = regs.star().read();
969 Ok(()) 930 !(status.ctimeout() || status.cmdsent())
931 } {}
932 } else {
933 // Wait for CMDREND or CCRCFAIL or a timeout
934 while {
935 status = regs.star().read();
936 !(status.ctimeout() || status.cmdrend() || status.ccrcfail())
937 } {}
938 }
939
940 if status.ctimeout() {
941 return Err(Error::Timeout);
942 } else if status.ccrcfail() {
943 return Err(Error::Crc);
970 } 944 }
945 Ok(())
971 } 946 }
972 947
973 /// # Safety 948 fn on_drop() {
974 ///
975 /// Ensure that `regs` has exclusive access to the regblocks
976 unsafe fn on_drop() {
977 let regs = T::regs(); 949 let regs = T::regs();
978 if Self::data_active() { 950 if Self::data_active() {
979 Self::clear_interrupt_flags(); 951 Self::clear_interrupt_flags();
@@ -1017,141 +989,138 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1017 false => BusWidth::One, 989 false => BusWidth::One,
1018 }; 990 };
1019 991
1020 // NOTE(unsafe) We have exclusive access to the peripheral 992 // While the SD/SDIO card or eMMC is in identification mode,
1021 unsafe { 993 // the SDMMC_CK frequency must be no more than 400 kHz.
1022 // While the SD/SDIO card or eMMC is in identification mode, 994 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1023 // the SDMMC_CK frequency must be no more than 400 kHz. 995 self.clock = init_clock;
1024 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1025 self.clock = init_clock;
1026
1027 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1028 Self::wait_idle();
1029
1030 regs.clkcr().modify(|w| {
1031 w.set_widbus(0);
1032 w.set_clkdiv(clkdiv);
1033 #[cfg(sdmmc_v1)]
1034 w.set_bypass(_bypass);
1035 });
1036 996
1037 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); 997 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1038 Self::cmd(Cmd::idle(), false)?; 998 Self::wait_idle();
1039 999
1040 // Check if cards supports CMD8 (with pattern) 1000 regs.clkcr().modify(|w| {
1041 Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; 1001 w.set_widbus(0);
1042 let r1 = regs.respr(0).read().cardstatus(); 1002 w.set_clkdiv(clkdiv);
1003 #[cfg(sdmmc_v1)]
1004 w.set_bypass(_bypass);
1005 });
1043 1006
1044 let mut card = if r1 == 0x1AA { 1007 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1045 // Card echoed back the pattern. Must be at least v2 1008 Self::cmd(Cmd::idle(), false)?;
1046 Card::default()
1047 } else {
1048 return Err(Error::UnsupportedCardVersion);
1049 };
1050 1009
1051 let ocr = loop { 1010 // Check if cards supports CMD8 (with pattern)
1052 // Signal that next command is a app command 1011 Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
1053 Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 1012 let r1 = regs.respr(0).read().cardstatus();
1054 1013
1055 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 1014 let mut card = if r1 == 0x1AA {
1056 | CmdAppOper::HIGH_CAPACITY as u32 1015 // Card echoed back the pattern. Must be at least v2
1057 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; 1016 Card::default()
1017 } else {
1018 return Err(Error::UnsupportedCardVersion);
1019 };
1058 1020
1059 // Initialize card 1021 let ocr = loop {
1060 match Self::cmd(Cmd::app_op_cmd(arg), false) { 1022 // Signal that next command is a app command
1061 // ACMD41 1023 Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
1062 Ok(_) => (),
1063 Err(Error::Crc) => (),
1064 Err(err) => return Err(err),
1065 }
1066 let ocr: OCR = regs.respr(0).read().cardstatus().into();
1067 if !ocr.is_busy() {
1068 // Power up done
1069 break ocr;
1070 }
1071 };
1072 1024
1073 if ocr.high_capacity() { 1025 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
1074 // Card is SDHC or SDXC or SDUC 1026 | CmdAppOper::HIGH_CAPACITY as u32
1075 card.card_type = CardCapacity::SDHC; 1027 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
1076 } else {
1077 card.card_type = CardCapacity::SDSC;
1078 }
1079 card.ocr = ocr;
1080
1081 Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
1082 let cid0 = regs.respr(0).read().cardstatus() as u128;
1083 let cid1 = regs.respr(1).read().cardstatus() as u128;
1084 let cid2 = regs.respr(2).read().cardstatus() as u128;
1085 let cid3 = regs.respr(3).read().cardstatus() as u128;
1086 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1087 card.cid = cid.into();
1088
1089 Self::cmd(Cmd::send_rel_addr(), false)?;
1090 card.rca = regs.respr(0).read().cardstatus() >> 16;
1091
1092 Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
1093 let csd0 = regs.respr(0).read().cardstatus() as u128;
1094 let csd1 = regs.respr(1).read().cardstatus() as u128;
1095 let csd2 = regs.respr(2).read().cardstatus() as u128;
1096 let csd3 = regs.respr(3).read().cardstatus() as u128;
1097 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1098 card.csd = csd.into();
1099
1100 self.select_card(Some(&card))?;
1101
1102 self.get_scr(&mut card).await?;
1103
1104 // Set bus width
1105 let (width, acmd_arg) = match bus_width {
1106 BusWidth::Eight => unimplemented!(),
1107 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
1108 _ => (BusWidth::One, 0),
1109 };
1110 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
1111 Self::cmd(Cmd::cmd6(acmd_arg), false)?;
1112
1113 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1114 Self::wait_idle();
1115
1116 regs.clkcr().modify(|w| {
1117 w.set_widbus(match width {
1118 BusWidth::One => 0,
1119 BusWidth::Four => 1,
1120 BusWidth::Eight => 2,
1121 _ => panic!("Invalid Bus Width"),
1122 })
1123 });
1124 1028
1125 // Set Clock 1029 // Initialize card
1126 if freq.0 <= 25_000_000 { 1030 match Self::cmd(Cmd::app_op_cmd(arg), false) {
1127 // Final clock frequency 1031 // ACMD41
1128 self.clkcr_set_clkdiv(freq.0, width)?; 1032 Ok(_) => (),
1129 } else { 1033 Err(Error::Crc) => (),
1130 // Switch to max clock for SDR12 1034 Err(err) => return Err(err),
1131 self.clkcr_set_clkdiv(25_000_000, width)?;
1132 } 1035 }
1036 let ocr: OCR = regs.respr(0).read().cardstatus().into();
1037 if !ocr.is_busy() {
1038 // Power up done
1039 break ocr;
1040 }
1041 };
1042
1043 if ocr.high_capacity() {
1044 // Card is SDHC or SDXC or SDUC
1045 card.card_type = CardCapacity::SDHC;
1046 } else {
1047 card.card_type = CardCapacity::SDSC;
1048 }
1049 card.ocr = ocr;
1050
1051 Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
1052 let cid0 = regs.respr(0).read().cardstatus() as u128;
1053 let cid1 = regs.respr(1).read().cardstatus() as u128;
1054 let cid2 = regs.respr(2).read().cardstatus() as u128;
1055 let cid3 = regs.respr(3).read().cardstatus() as u128;
1056 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1057 card.cid = cid.into();
1058
1059 Self::cmd(Cmd::send_rel_addr(), false)?;
1060 card.rca = regs.respr(0).read().cardstatus() >> 16;
1061
1062 Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
1063 let csd0 = regs.respr(0).read().cardstatus() as u128;
1064 let csd1 = regs.respr(1).read().cardstatus() as u128;
1065 let csd2 = regs.respr(2).read().cardstatus() as u128;
1066 let csd3 = regs.respr(3).read().cardstatus() as u128;
1067 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1068 card.csd = csd.into();
1069
1070 self.select_card(Some(&card))?;
1071
1072 self.get_scr(&mut card).await?;
1073
1074 // Set bus width
1075 let (width, acmd_arg) = match bus_width {
1076 BusWidth::Eight => unimplemented!(),
1077 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
1078 _ => (BusWidth::One, 0),
1079 };
1080 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
1081 Self::cmd(Cmd::cmd6(acmd_arg), false)?;
1082
1083 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1084 Self::wait_idle();
1133 1085
1134 self.card = Some(card); 1086 regs.clkcr().modify(|w| {
1087 w.set_widbus(match width {
1088 BusWidth::One => 0,
1089 BusWidth::Four => 1,
1090 BusWidth::Eight => 2,
1091 _ => panic!("Invalid Bus Width"),
1092 })
1093 });
1094
1095 // Set Clock
1096 if freq.0 <= 25_000_000 {
1097 // Final clock frequency
1098 self.clkcr_set_clkdiv(freq.0, width)?;
1099 } else {
1100 // Switch to max clock for SDR12
1101 self.clkcr_set_clkdiv(25_000_000, width)?;
1102 }
1135 1103
1136 // Read status 1104 self.card = Some(card);
1137 self.read_sd_status().await?;
1138 1105
1139 if freq.0 > 25_000_000 { 1106 // Read status
1140 // Switch to SDR25 1107 self.read_sd_status().await?;
1141 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1142 1108
1143 if self.signalling == Signalling::SDR25 { 1109 if freq.0 > 25_000_000 {
1144 // Set final clock frequency 1110 // Switch to SDR25
1145 self.clkcr_set_clkdiv(freq.0, width)?; 1111 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1146 1112
1147 if self.read_status(&card)?.state() != CurrentState::Transfer { 1113 if self.signalling == Signalling::SDR25 {
1148 return Err(Error::SignalingSwitchFailed); 1114 // Set final clock frequency
1149 } 1115 self.clkcr_set_clkdiv(freq.0, width)?;
1116
1117 if self.read_status(&card)?.state() != CurrentState::Transfer {
1118 return Err(Error::SignalingSwitchFailed);
1150 } 1119 }
1151 } 1120 }
1152 // Read status after signalling change
1153 self.read_sd_status().await?;
1154 } 1121 }
1122 // Read status after signalling change
1123 self.read_sd_status().await?;
1155 1124
1156 Ok(()) 1125 Ok(())
1157 } 1126 }
@@ -1172,7 +1141,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1172 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 1141 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
1173 1142
1174 let regs = T::regs(); 1143 let regs = T::regs();
1175 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 1144 let on_drop = OnDrop::new(|| Self::on_drop());
1176 1145
1177 let transfer = self.prepare_datapath_read(buffer, 512, 9); 1146 let transfer = self.prepare_datapath_read(buffer, 512, 9);
1178 InterruptHandler::<T>::data_interrupts(true); 1147 InterruptHandler::<T>::data_interrupts(true);
@@ -1180,7 +1149,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1180 1149
1181 let res = poll_fn(|cx| { 1150 let res = poll_fn(|cx| {
1182 T::state().register(cx.waker()); 1151 T::state().register(cx.waker());
1183 let status = unsafe { regs.star().read() }; 1152 let status = regs.star().read();
1184 1153
1185 if status.dcrcfail() { 1154 if status.dcrcfail() {
1186 return Poll::Ready(Err(Error::Crc)); 1155 return Poll::Ready(Err(Error::Crc));
@@ -1217,7 +1186,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1217 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 1186 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
1218 1187
1219 let regs = T::regs(); 1188 let regs = T::regs();
1220 let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); 1189 let on_drop = OnDrop::new(|| Self::on_drop());
1221 1190
1222 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes 1191 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
1223 #[cfg(sdmmc_v1)] 1192 #[cfg(sdmmc_v1)]
@@ -1231,7 +1200,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1231 1200
1232 let res = poll_fn(|cx| { 1201 let res = poll_fn(|cx| {
1233 T::state().register(cx.waker()); 1202 T::state().register(cx.waker());
1234 let status = unsafe { regs.star().read() }; 1203 let status = regs.star().read();
1235 1204
1236 if status.dcrcfail() { 1205 if status.dcrcfail() {
1237 return Poll::Ready(Err(Error::Crc)); 1206 return Poll::Ready(Err(Error::Crc));
@@ -1289,9 +1258,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1289impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { 1258impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
1290 fn drop(&mut self) { 1259 fn drop(&mut self) {
1291 T::Interrupt::disable(); 1260 T::Interrupt::disable();
1292 unsafe { Self::on_drop() }; 1261 Self::on_drop();
1293 1262
1294 critical_section::with(|_| unsafe { 1263 critical_section::with(|_| {
1295 self.clk.set_as_disconnected(); 1264 self.clk.set_as_disconnected();
1296 self.cmd.set_as_disconnected(); 1265 self.cmd.set_as_disconnected();
1297 self.d0.set_as_disconnected(); 1266 self.d0.set_as_disconnected();
@@ -1401,7 +1370,7 @@ pub(crate) mod sealed {
1401 use super::*; 1370 use super::*;
1402 1371
1403 pub trait Instance { 1372 pub trait Instance {
1404 type Interrupt: Interrupt; 1373 type Interrupt: interrupt::typelevel::Interrupt;
1405 1374
1406 fn regs() -> RegBlock; 1375 fn regs() -> RegBlock;
1407 fn state() -> &'static AtomicWaker; 1376 fn state() -> &'static AtomicWaker;
@@ -1490,7 +1459,7 @@ cfg_if::cfg_if! {
1490foreach_peripheral!( 1459foreach_peripheral!(
1491 (sdmmc, $inst:ident) => { 1460 (sdmmc, $inst:ident) => {
1492 impl sealed::Instance for peripherals::$inst { 1461 impl sealed::Instance for peripherals::$inst {
1493 type Interrupt = crate::interrupt::$inst; 1462 type Interrupt = crate::interrupt::typelevel::$inst;
1494 1463
1495 fn regs() -> RegBlock { 1464 fn regs() -> RegBlock {
1496 crate::pac::$inst 1465 crate::pac::$inst
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 580971e45..c3224073d 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -98,14 +98,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
98 Polarity::IdleHigh => Pull::Up, 98 Polarity::IdleHigh => Pull::Up,
99 }; 99 };
100 100
101 unsafe { 101 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
102 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode); 102 sck.set_speed(crate::gpio::Speed::VeryHigh);
103 sck.set_speed(crate::gpio::Speed::VeryHigh); 103 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
104 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); 104 mosi.set_speed(crate::gpio::Speed::VeryHigh);
105 mosi.set_speed(crate::gpio::Speed::VeryHigh); 105 miso.set_as_af(miso.af_num(), AFType::Input);
106 miso.set_as_af(miso.af_num(), AFType::Input); 106 miso.set_speed(crate::gpio::Speed::VeryHigh);
107 miso.set_speed(crate::gpio::Speed::VeryHigh);
108 }
109 107
110 Self::new_inner( 108 Self::new_inner(
111 peri, 109 peri,
@@ -129,12 +127,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
129 config: Config, 127 config: Config,
130 ) -> Self { 128 ) -> Self {
131 into_ref!(sck, miso); 129 into_ref!(sck, miso);
132 unsafe { 130 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
133 sck.set_as_af(sck.af_num(), AFType::OutputPushPull); 131 sck.set_speed(crate::gpio::Speed::VeryHigh);
134 sck.set_speed(crate::gpio::Speed::VeryHigh); 132 miso.set_as_af(miso.af_num(), AFType::Input);
135 miso.set_as_af(miso.af_num(), AFType::Input); 133 miso.set_speed(crate::gpio::Speed::VeryHigh);
136 miso.set_speed(crate::gpio::Speed::VeryHigh);
137 }
138 134
139 Self::new_inner( 135 Self::new_inner(
140 peri, 136 peri,
@@ -158,12 +154,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
158 config: Config, 154 config: Config,
159 ) -> Self { 155 ) -> Self {
160 into_ref!(sck, mosi); 156 into_ref!(sck, mosi);
161 unsafe { 157 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
162 sck.set_as_af(sck.af_num(), AFType::OutputPushPull); 158 sck.set_speed(crate::gpio::Speed::VeryHigh);
163 sck.set_speed(crate::gpio::Speed::VeryHigh); 159 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
164 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); 160 mosi.set_speed(crate::gpio::Speed::VeryHigh);
165 mosi.set_speed(crate::gpio::Speed::VeryHigh);
166 }
167 161
168 Self::new_inner( 162 Self::new_inner(
169 peri, 163 peri,
@@ -186,10 +180,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
186 config: Config, 180 config: Config,
187 ) -> Self { 181 ) -> Self {
188 into_ref!(mosi); 182 into_ref!(mosi);
189 unsafe { 183 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
190 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down); 184 mosi.set_speed(crate::gpio::Speed::Medium);
191 mosi.set_speed(crate::gpio::Speed::Medium);
192 }
193 185
194 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config) 186 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
195 } 187 }
@@ -247,7 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
247 T::reset(); 239 T::reset();
248 240
249 #[cfg(any(spi_v1, spi_f1))] 241 #[cfg(any(spi_v1, spi_f1))]
250 unsafe { 242 {
251 T::REGS.cr2().modify(|w| { 243 T::REGS.cr2().modify(|w| {
252 w.set_ssoe(false); 244 w.set_ssoe(false);
253 }); 245 });
@@ -270,7 +262,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
270 }); 262 });
271 } 263 }
272 #[cfg(spi_v2)] 264 #[cfg(spi_v2)]
273 unsafe { 265 {
274 T::REGS.cr2().modify(|w| { 266 T::REGS.cr2().modify(|w| {
275 let (ds, frxth) = <u8 as sealed::Word>::CONFIG; 267 let (ds, frxth) = <u8 as sealed::Word>::CONFIG;
276 w.set_frxth(frxth); 268 w.set_frxth(frxth);
@@ -292,7 +284,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
292 }); 284 });
293 } 285 }
294 #[cfg(any(spi_v3, spi_v4, spi_v5))] 286 #[cfg(any(spi_v3, spi_v4, spi_v5))]
295 unsafe { 287 {
296 T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); 288 T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff);
297 T::REGS.cfg2().modify(|w| { 289 T::REGS.cfg2().modify(|w| {
298 //w.set_ssoe(true); 290 //w.set_ssoe(true);
@@ -343,29 +335,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
343 let lsbfirst = config.raw_byte_order(); 335 let lsbfirst = config.raw_byte_order();
344 336
345 #[cfg(any(spi_v1, spi_f1, spi_v2))] 337 #[cfg(any(spi_v1, spi_f1, spi_v2))]
346 unsafe { 338 T::REGS.cr1().modify(|w| {
347 T::REGS.cr1().modify(|w| { 339 w.set_cpha(cpha);
348 w.set_cpha(cpha); 340 w.set_cpol(cpol);
349 w.set_cpol(cpol); 341 w.set_lsbfirst(lsbfirst);
350 w.set_lsbfirst(lsbfirst); 342 });
351 });
352 }
353 343
354 #[cfg(any(spi_v3, spi_v4, spi_v5))] 344 #[cfg(any(spi_v3, spi_v4, spi_v5))]
355 unsafe { 345 T::REGS.cfg2().modify(|w| {
356 T::REGS.cfg2().modify(|w| { 346 w.set_cpha(cpha);
357 w.set_cpha(cpha); 347 w.set_cpol(cpol);
358 w.set_cpol(cpol); 348 w.set_lsbfirst(lsbfirst);
359 w.set_lsbfirst(lsbfirst); 349 });
360 });
361 }
362 } 350 }
363 351
364 pub fn get_current_config(&self) -> Config { 352 pub fn get_current_config(&self) -> Config {
365 #[cfg(any(spi_v1, spi_f1, spi_v2))] 353 #[cfg(any(spi_v1, spi_f1, spi_v2))]
366 let cfg = unsafe { T::REGS.cr1().read() }; 354 let cfg = T::REGS.cr1().read();
367 #[cfg(any(spi_v3, spi_v4, spi_v5))] 355 #[cfg(any(spi_v3, spi_v4, spi_v5))]
368 let cfg = unsafe { T::REGS.cfg2().read() }; 356 let cfg = T::REGS.cfg2().read();
369 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { 357 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
370 Polarity::IdleLow 358 Polarity::IdleLow
371 } else { 359 } else {
@@ -395,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
395 } 383 }
396 384
397 #[cfg(any(spi_v1, spi_f1))] 385 #[cfg(any(spi_v1, spi_f1))]
398 unsafe { 386 {
399 T::REGS.cr1().modify(|reg| { 387 T::REGS.cr1().modify(|reg| {
400 reg.set_spe(false); 388 reg.set_spe(false);
401 reg.set_dff(word_size) 389 reg.set_dff(word_size)
@@ -405,7 +393,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
405 }); 393 });
406 } 394 }
407 #[cfg(spi_v2)] 395 #[cfg(spi_v2)]
408 unsafe { 396 {
409 T::REGS.cr1().modify(|w| { 397 T::REGS.cr1().modify(|w| {
410 w.set_spe(false); 398 w.set_spe(false);
411 }); 399 });
@@ -418,7 +406,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
418 }); 406 });
419 } 407 }
420 #[cfg(any(spi_v3, spi_v4, spi_v5))] 408 #[cfg(any(spi_v3, spi_v4, spi_v5))]
421 unsafe { 409 {
422 T::REGS.cr1().modify(|w| { 410 T::REGS.cr1().modify(|w| {
423 w.set_csusp(true); 411 w.set_csusp(true);
424 }); 412 });
@@ -447,26 +435,22 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
447 } 435 }
448 436
449 self.set_word_size(W::CONFIG); 437 self.set_word_size(W::CONFIG);
450 unsafe { 438 T::REGS.cr1().modify(|w| {
451 T::REGS.cr1().modify(|w| { 439 w.set_spe(false);
452 w.set_spe(false); 440 });
453 });
454 }
455 441
456 let tx_request = self.txdma.request(); 442 let tx_request = self.txdma.request();
457 let tx_dst = T::REGS.tx_ptr(); 443 let tx_dst = T::REGS.tx_ptr();
458 let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; 444 let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
459 445
460 unsafe { 446 set_txdmaen(T::REGS, true);
461 set_txdmaen(T::REGS, true); 447 T::REGS.cr1().modify(|w| {
462 T::REGS.cr1().modify(|w| { 448 w.set_spe(true);
463 w.set_spe(true); 449 });
464 }); 450 #[cfg(any(spi_v3, spi_v4, spi_v5))]
465 #[cfg(any(spi_v3, spi_v4, spi_v5))] 451 T::REGS.cr1().modify(|w| {
466 T::REGS.cr1().modify(|w| { 452 w.set_cstart(true);
467 w.set_cstart(true); 453 });
468 });
469 }
470 454
471 tx_f.await; 455 tx_f.await;
472 456
@@ -485,11 +469,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
485 } 469 }
486 470
487 self.set_word_size(W::CONFIG); 471 self.set_word_size(W::CONFIG);
488 unsafe { 472 T::REGS.cr1().modify(|w| {
489 T::REGS.cr1().modify(|w| { 473 w.set_spe(false);
490 w.set_spe(false); 474 });
491 });
492 }
493 475
494 // SPIv3 clears rxfifo on SPE=0 476 // SPIv3 clears rxfifo on SPE=0
495 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 477 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
@@ -517,16 +499,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
517 ) 499 )
518 }; 500 };
519 501
520 unsafe { 502 set_txdmaen(T::REGS, true);
521 set_txdmaen(T::REGS, true); 503 T::REGS.cr1().modify(|w| {
522 T::REGS.cr1().modify(|w| { 504 w.set_spe(true);
523 w.set_spe(true); 505 });
524 }); 506 #[cfg(any(spi_v3, spi_v4, spi_v5))]
525 #[cfg(any(spi_v3, spi_v4, spi_v5))] 507 T::REGS.cr1().modify(|w| {
526 T::REGS.cr1().modify(|w| { 508 w.set_cstart(true);
527 w.set_cstart(true); 509 });
528 });
529 }
530 510
531 join(tx_f, rx_f).await; 511 join(tx_f, rx_f).await;
532 512
@@ -548,11 +528,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
548 } 528 }
549 529
550 self.set_word_size(W::CONFIG); 530 self.set_word_size(W::CONFIG);
551 unsafe { 531 T::REGS.cr1().modify(|w| {
552 T::REGS.cr1().modify(|w| { 532 w.set_spe(false);
553 w.set_spe(false); 533 });
554 });
555 }
556 534
557 // SPIv3 clears rxfifo on SPE=0 535 // SPIv3 clears rxfifo on SPE=0
558 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 536 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
@@ -568,16 +546,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
568 let tx_dst = T::REGS.tx_ptr(); 546 let tx_dst = T::REGS.tx_ptr();
569 let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; 547 let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) };
570 548
571 unsafe { 549 set_txdmaen(T::REGS, true);
572 set_txdmaen(T::REGS, true); 550 T::REGS.cr1().modify(|w| {
573 T::REGS.cr1().modify(|w| { 551 w.set_spe(true);
574 w.set_spe(true); 552 });
575 }); 553 #[cfg(any(spi_v3, spi_v4, spi_v5))]
576 #[cfg(any(spi_v3, spi_v4, spi_v5))] 554 T::REGS.cr1().modify(|w| {
577 T::REGS.cr1().modify(|w| { 555 w.set_cstart(true);
578 w.set_cstart(true); 556 });
579 });
580 }
581 557
582 join(tx_f, rx_f).await; 558 join(tx_f, rx_f).await;
583 559
@@ -603,7 +579,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
603 } 579 }
604 580
605 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { 581 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
606 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 582 T::REGS.cr1().modify(|w| w.set_spe(true));
607 flush_rx_fifo(T::REGS); 583 flush_rx_fifo(T::REGS);
608 self.set_word_size(W::CONFIG); 584 self.set_word_size(W::CONFIG);
609 for word in words.iter() { 585 for word in words.iter() {
@@ -613,7 +589,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
613 } 589 }
614 590
615 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 591 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
616 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 592 T::REGS.cr1().modify(|w| w.set_spe(true));
617 flush_rx_fifo(T::REGS); 593 flush_rx_fifo(T::REGS);
618 self.set_word_size(W::CONFIG); 594 self.set_word_size(W::CONFIG);
619 for word in words.iter_mut() { 595 for word in words.iter_mut() {
@@ -623,7 +599,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
623 } 599 }
624 600
625 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 601 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
626 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 602 T::REGS.cr1().modify(|w| w.set_spe(true));
627 flush_rx_fifo(T::REGS); 603 flush_rx_fifo(T::REGS);
628 self.set_word_size(W::CONFIG); 604 self.set_word_size(W::CONFIG);
629 for word in words.iter_mut() { 605 for word in words.iter_mut() {
@@ -633,7 +609,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
633 } 609 }
634 610
635 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 611 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
636 unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } 612 T::REGS.cr1().modify(|w| w.set_spe(true));
637 flush_rx_fifo(T::REGS); 613 flush_rx_fifo(T::REGS);
638 self.set_word_size(W::CONFIG); 614 self.set_word_size(W::CONFIG);
639 let len = read.len().max(write.len()); 615 let len = read.len().max(write.len());
@@ -650,11 +626,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
650 626
651impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { 627impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
652 fn drop(&mut self) { 628 fn drop(&mut self) {
653 unsafe { 629 self.sck.as_ref().map(|x| x.set_as_disconnected());
654 self.sck.as_ref().map(|x| x.set_as_disconnected()); 630 self.mosi.as_ref().map(|x| x.set_as_disconnected());
655 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 631 self.miso.as_ref().map(|x| x.set_as_disconnected());
656 self.miso.as_ref().map(|x| x.set_as_disconnected());
657 }
658 } 632 }
659} 633}
660 634
@@ -676,7 +650,7 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
676 _ => 0b111, 650 _ => 0b111,
677 }; 651 };
678 652
679 Br(val) 653 Br::from_bits(val)
680} 654}
681 655
682trait RegsExt { 656trait RegsExt {
@@ -690,7 +664,7 @@ impl RegsExt for Regs {
690 let dr = self.dr(); 664 let dr = self.dr();
691 #[cfg(any(spi_v3, spi_v4, spi_v5))] 665 #[cfg(any(spi_v3, spi_v4, spi_v5))]
692 let dr = self.txdr(); 666 let dr = self.txdr();
693 dr.ptr() as *mut W 667 dr.as_ptr() as *mut W
694 } 668 }
695 669
696 fn rx_ptr<W>(&self) -> *mut W { 670 fn rx_ptr<W>(&self) -> *mut W {
@@ -698,7 +672,7 @@ impl RegsExt for Regs {
698 let dr = self.dr(); 672 let dr = self.dr();
699 #[cfg(any(spi_v3, spi_v4, spi_v5))] 673 #[cfg(any(spi_v3, spi_v4, spi_v5))]
700 let dr = self.rxdr(); 674 let dr = self.rxdr();
701 dr.ptr() as *mut W 675 dr.as_ptr() as *mut W
702 } 676 }
703} 677}
704 678
@@ -731,7 +705,7 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
731 705
732fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { 706fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
733 loop { 707 loop {
734 let sr = unsafe { regs.sr().read() }; 708 let sr = regs.sr().read();
735 709
736 check_error_flags(sr)?; 710 check_error_flags(sr)?;
737 711
@@ -748,7 +722,7 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
748 722
749fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { 723fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
750 loop { 724 loop {
751 let sr = unsafe { regs.sr().read() }; 725 let sr = regs.sr().read();
752 726
753 check_error_flags(sr)?; 727 check_error_flags(sr)?;
754 728
@@ -764,72 +738,64 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
764} 738}
765 739
766fn flush_rx_fifo(regs: Regs) { 740fn flush_rx_fifo(regs: Regs) {
767 unsafe { 741 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
768 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 742 while regs.sr().read().rxne() {
769 while regs.sr().read().rxne() { 743 let _ = regs.dr().read();
770 let _ = regs.dr().read(); 744 }
771 } 745 #[cfg(any(spi_v3, spi_v4, spi_v5))]
772 #[cfg(any(spi_v3, spi_v4, spi_v5))] 746 while regs.sr().read().rxp() {
773 while regs.sr().read().rxp() { 747 let _ = regs.rxdr().read();
774 let _ = regs.rxdr().read();
775 }
776 } 748 }
777} 749}
778 750
779fn set_txdmaen(regs: Regs, val: bool) { 751fn set_txdmaen(regs: Regs, val: bool) {
780 unsafe { 752 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
781 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 753 regs.cr2().modify(|reg| {
782 regs.cr2().modify(|reg| { 754 reg.set_txdmaen(val);
783 reg.set_txdmaen(val); 755 });
784 }); 756 #[cfg(any(spi_v3, spi_v4, spi_v5))]
785 #[cfg(any(spi_v3, spi_v4, spi_v5))] 757 regs.cfg1().modify(|reg| {
786 regs.cfg1().modify(|reg| { 758 reg.set_txdmaen(val);
787 reg.set_txdmaen(val); 759 });
788 });
789 }
790} 760}
791 761
792fn set_rxdmaen(regs: Regs, val: bool) { 762fn set_rxdmaen(regs: Regs, val: bool) {
793 unsafe { 763 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
794 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 764 regs.cr2().modify(|reg| {
795 regs.cr2().modify(|reg| { 765 reg.set_rxdmaen(val);
796 reg.set_rxdmaen(val); 766 });
797 }); 767 #[cfg(any(spi_v3, spi_v4, spi_v5))]
798 #[cfg(any(spi_v3, spi_v4, spi_v5))] 768 regs.cfg1().modify(|reg| {
799 regs.cfg1().modify(|reg| { 769 reg.set_rxdmaen(val);
800 reg.set_rxdmaen(val); 770 });
801 });
802 }
803} 771}
804 772
805fn finish_dma(regs: Regs) { 773fn finish_dma(regs: Regs) {
806 unsafe { 774 #[cfg(spi_v2)]
807 #[cfg(spi_v2)] 775 while regs.sr().read().ftlvl().to_bits() > 0 {}
808 while regs.sr().read().ftlvl() > 0 {}
809 776
810 #[cfg(any(spi_v3, spi_v4, spi_v5))] 777 #[cfg(any(spi_v3, spi_v4, spi_v5))]
811 while !regs.sr().read().txc() {} 778 while !regs.sr().read().txc() {}
812 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 779 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
813 while regs.sr().read().bsy() {} 780 while regs.sr().read().bsy() {}
814 781
815 // Disable the spi peripheral 782 // Disable the spi peripheral
816 regs.cr1().modify(|w| { 783 regs.cr1().modify(|w| {
817 w.set_spe(false); 784 w.set_spe(false);
818 }); 785 });
819 786
820 // The peripheral automatically disables the DMA stream on completion without error, 787 // The peripheral automatically disables the DMA stream on completion without error,
821 // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. 788 // but it does not clear the RXDMAEN/TXDMAEN flag in CR2.
822 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 789 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
823 regs.cr2().modify(|reg| { 790 regs.cr2().modify(|reg| {
824 reg.set_txdmaen(false); 791 reg.set_txdmaen(false);
825 reg.set_rxdmaen(false); 792 reg.set_rxdmaen(false);
826 }); 793 });
827 #[cfg(any(spi_v3, spi_v4, spi_v5))] 794 #[cfg(any(spi_v3, spi_v4, spi_v5))]
828 regs.cfg1().modify(|reg| { 795 regs.cfg1().modify(|reg| {
829 reg.set_txdmaen(false); 796 reg.set_txdmaen(false);
830 reg.set_rxdmaen(false); 797 reg.set_rxdmaen(false);
831 }); 798 });
832 }
833} 799}
834 800
835fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { 801fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index bab700993..2622442f4 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -11,7 +11,7 @@ use embassy_time::driver::{AlarmHandle, Driver};
11use embassy_time::TICK_HZ; 11use embassy_time::TICK_HZ;
12use stm32_metapac::timer::regs; 12use stm32_metapac::timer::regs;
13 13
14use crate::interrupt::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::pac::timer::vals; 15use crate::pac::timer::vals;
16use crate::rcc::sealed::RccPeripheral; 16use crate::rcc::sealed::RccPeripheral;
17use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; 17use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance};
@@ -40,6 +40,7 @@ type T = peripherals::TIM15;
40foreach_interrupt! { 40foreach_interrupt! {
41 (TIM2, timer, $block:ident, UP, $irq:ident) => { 41 (TIM2, timer, $block:ident, UP, $irq:ident) => {
42 #[cfg(time_driver_tim2)] 42 #[cfg(time_driver_tim2)]
43 #[cfg(feature = "rt")]
43 #[interrupt] 44 #[interrupt]
44 fn $irq() { 45 fn $irq() {
45 DRIVER.on_interrupt() 46 DRIVER.on_interrupt()
@@ -47,6 +48,7 @@ foreach_interrupt! {
47 }; 48 };
48 (TIM3, timer, $block:ident, UP, $irq:ident) => { 49 (TIM3, timer, $block:ident, UP, $irq:ident) => {
49 #[cfg(time_driver_tim3)] 50 #[cfg(time_driver_tim3)]
51 #[cfg(feature = "rt")]
50 #[interrupt] 52 #[interrupt]
51 fn $irq() { 53 fn $irq() {
52 DRIVER.on_interrupt() 54 DRIVER.on_interrupt()
@@ -54,6 +56,7 @@ foreach_interrupt! {
54 }; 56 };
55 (TIM4, timer, $block:ident, UP, $irq:ident) => { 57 (TIM4, timer, $block:ident, UP, $irq:ident) => {
56 #[cfg(time_driver_tim4)] 58 #[cfg(time_driver_tim4)]
59 #[cfg(feature = "rt")]
57 #[interrupt] 60 #[interrupt]
58 fn $irq() { 61 fn $irq() {
59 DRIVER.on_interrupt() 62 DRIVER.on_interrupt()
@@ -61,6 +64,7 @@ foreach_interrupt! {
61 }; 64 };
62 (TIM5, timer, $block:ident, UP, $irq:ident) => { 65 (TIM5, timer, $block:ident, UP, $irq:ident) => {
63 #[cfg(time_driver_tim5)] 66 #[cfg(time_driver_tim5)]
67 #[cfg(feature = "rt")]
64 #[interrupt] 68 #[interrupt]
65 fn $irq() { 69 fn $irq() {
66 DRIVER.on_interrupt() 70 DRIVER.on_interrupt()
@@ -68,6 +72,7 @@ foreach_interrupt! {
68 }; 72 };
69 (TIM12, timer, $block:ident, UP, $irq:ident) => { 73 (TIM12, timer, $block:ident, UP, $irq:ident) => {
70 #[cfg(time_driver_tim12)] 74 #[cfg(time_driver_tim12)]
75 #[cfg(feature = "rt")]
71 #[interrupt] 76 #[interrupt]
72 fn $irq() { 77 fn $irq() {
73 DRIVER.on_interrupt() 78 DRIVER.on_interrupt()
@@ -75,6 +80,7 @@ foreach_interrupt! {
75 }; 80 };
76 (TIM15, timer, $block:ident, UP, $irq:ident) => { 81 (TIM15, timer, $block:ident, UP, $irq:ident) => {
77 #[cfg(time_driver_tim15)] 82 #[cfg(time_driver_tim15)]
83 #[cfg(feature = "rt")]
78 #[interrupt] 84 #[interrupt]
79 fn $irq() { 85 fn $irq() {
80 DRIVER.on_interrupt() 86 DRIVER.on_interrupt()
@@ -149,8 +155,7 @@ impl RtcDriver {
149 155
150 let timer_freq = T::frequency(); 156 let timer_freq = T::frequency();
151 157
152 // NOTE(unsafe) Critical section to use the unsafe methods 158 critical_section::with(|_| {
153 critical_section::with(|_| unsafe {
154 r.cr1().modify(|w| w.set_cen(false)); 159 r.cr1().modify(|w| w.set_cen(false));
155 r.cnt().write(|w| w.set_cnt(0)); 160 r.cnt().write(|w| w.set_cnt(0));
156 161
@@ -178,7 +183,7 @@ impl RtcDriver {
178 }); 183 });
179 184
180 <T as BasicInstance>::Interrupt::unpend(); 185 <T as BasicInstance>::Interrupt::unpend();
181 <T as BasicInstance>::Interrupt::enable(); 186 unsafe { <T as BasicInstance>::Interrupt::enable() };
182 187
183 r.cr1().modify(|w| w.set_cen(true)); 188 r.cr1().modify(|w| w.set_cen(true));
184 }) 189 })
@@ -187,9 +192,8 @@ impl RtcDriver {
187 fn on_interrupt(&self) { 192 fn on_interrupt(&self) {
188 let r = T::regs_gp16(); 193 let r = T::regs_gp16();
189 194
190 // NOTE(unsafe) Use critical section to access the methods
191 // XXX: reduce the size of this critical section ? 195 // XXX: reduce the size of this critical section ?
192 critical_section::with(|cs| unsafe { 196 critical_section::with(|cs| {
193 let sr = r.sr().read(); 197 let sr = r.sr().read();
194 let dier = r.dier().read(); 198 let dier = r.dier().read();
195 199
@@ -222,7 +226,7 @@ impl RtcDriver {
222 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; 226 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
223 let t = (period as u64) << 15; 227 let t = (period as u64) << 15;
224 228
225 critical_section::with(move |cs| unsafe { 229 critical_section::with(move |cs| {
226 r.dier().modify(move |w| { 230 r.dier().modify(move |w| {
227 for n in 0..ALARM_COUNT { 231 for n in 0..ALARM_COUNT {
228 let alarm = &self.alarms.borrow(cs)[n]; 232 let alarm = &self.alarms.borrow(cs)[n];
@@ -263,8 +267,7 @@ impl Driver for RtcDriver {
263 267
264 let period = self.period.load(Ordering::Relaxed); 268 let period = self.period.load(Ordering::Relaxed);
265 compiler_fence(Ordering::Acquire); 269 compiler_fence(Ordering::Acquire);
266 // NOTE(unsafe) Atomic read with no side-effects 270 let counter = r.cnt().read().cnt();
267 let counter = unsafe { r.cnt().read().cnt() };
268 calc_now(period, counter) 271 calc_now(period, counter)
269 } 272 }
270 273
@@ -304,7 +307,7 @@ impl Driver for RtcDriver {
304 if timestamp <= t { 307 if timestamp <= t {
305 // If alarm timestamp has passed the alarm will not fire. 308 // If alarm timestamp has passed the alarm will not fire.
306 // Disarm the alarm and return `false` to indicate that. 309 // Disarm the alarm and return `false` to indicate that.
307 unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) }; 310 r.dier().modify(|w| w.set_ccie(n + 1, false));
308 311
309 alarm.timestamp.set(u64::MAX); 312 alarm.timestamp.set(u64::MAX);
310 313
@@ -315,12 +318,11 @@ impl Driver for RtcDriver {
315 318
316 // Write the CCR value regardless of whether we're going to enable it now or not. 319 // Write the CCR value regardless of whether we're going to enable it now or not.
317 // This way, when we enable it later, the right value is already set. 320 // This way, when we enable it later, the right value is already set.
318 unsafe { r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)) }; 321 r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16));
319 322
320 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 323 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
321 let diff = timestamp - t; 324 let diff = timestamp - t;
322 // NOTE(unsafe) We're in a critical section 325 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
323 unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) };
324 326
325 true 327 true
326 }) 328 })
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 772c67686..09b7a3776 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,6 +1,6 @@
1use stm32_metapac::timer::vals; 1use stm32_metapac::timer::vals;
2 2
3use crate::interrupt::Interrupt; 3use crate::interrupt;
4use crate::rcc::sealed::RccPeripheral as __RccPeri; 4use crate::rcc::sealed::RccPeripheral as __RccPeri;
5use crate::rcc::RccPeripheral; 5use crate::rcc::RccPeripheral;
6use crate::time::Hertz; 6use crate::time::Hertz;
@@ -13,7 +13,7 @@ pub mod low_level {
13pub(crate) mod sealed { 13pub(crate) mod sealed {
14 use super::*; 14 use super::*;
15 pub trait Basic16bitInstance: RccPeripheral { 15 pub trait Basic16bitInstance: RccPeripheral {
16 type Interrupt: Interrupt; 16 type Interrupt: interrupt::typelevel::Interrupt;
17 17
18 fn regs() -> crate::pac::timer::TimBasic; 18 fn regs() -> crate::pac::timer::TimBasic;
19 19
@@ -57,28 +57,22 @@ pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
57macro_rules! impl_basic_16bit_timer { 57macro_rules! impl_basic_16bit_timer {
58 ($inst:ident, $irq:ident) => { 58 ($inst:ident, $irq:ident) => {
59 impl sealed::Basic16bitInstance for crate::peripherals::$inst { 59 impl sealed::Basic16bitInstance for crate::peripherals::$inst {
60 type Interrupt = crate::interrupt::$irq; 60 type Interrupt = crate::interrupt::typelevel::$irq;
61 61
62 fn regs() -> crate::pac::timer::TimBasic { 62 fn regs() -> crate::pac::timer::TimBasic {
63 crate::pac::timer::TimBasic(crate::pac::$inst.0) 63 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
64 } 64 }
65 65
66 fn start(&mut self) { 66 fn start(&mut self) {
67 unsafe { 67 Self::regs().cr1().modify(|r| r.set_cen(true));
68 Self::regs().cr1().modify(|r| r.set_cen(true));
69 }
70 } 68 }
71 69
72 fn stop(&mut self) { 70 fn stop(&mut self) {
73 unsafe { 71 Self::regs().cr1().modify(|r| r.set_cen(false));
74 Self::regs().cr1().modify(|r| r.set_cen(false));
75 }
76 } 72 }
77 73
78 fn reset(&mut self) { 74 fn reset(&mut self) {
79 unsafe { 75 Self::regs().cnt().write(|r| r.set_cnt(0));
80 Self::regs().cnt().write(|r| r.set_cnt(0));
81 }
82 } 76 }
83 77
84 fn set_frequency(&mut self, frequency: Hertz) { 78 fn set_frequency(&mut self, frequency: Hertz) {
@@ -90,35 +84,29 @@ macro_rules! impl_basic_16bit_timer {
90 let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); 84 let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
91 85
92 let regs = Self::regs(); 86 let regs = Self::regs();
93 unsafe { 87 regs.psc().write(|r| r.set_psc(psc));
94 regs.psc().write(|r| r.set_psc(psc)); 88 regs.arr().write(|r| r.set_arr(arr));
95 regs.arr().write(|r| r.set_arr(arr));
96 89
97 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 90 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
98 regs.egr().write(|r| r.set_ug(true)); 91 regs.egr().write(|r| r.set_ug(true));
99 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 92 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
100 }
101 } 93 }
102 94
103 fn clear_update_interrupt(&mut self) -> bool { 95 fn clear_update_interrupt(&mut self) -> bool {
104 let regs = Self::regs(); 96 let regs = Self::regs();
105 unsafe { 97 let sr = regs.sr().read();
106 let sr = regs.sr().read(); 98 if sr.uif() {
107 if sr.uif() { 99 regs.sr().modify(|r| {
108 regs.sr().modify(|r| { 100 r.set_uif(false);
109 r.set_uif(false); 101 });
110 }); 102 true
111 true 103 } else {
112 } else { 104 false
113 false
114 }
115 } 105 }
116 } 106 }
117 107
118 fn enable_update_interrupt(&mut self, enable: bool) { 108 fn enable_update_interrupt(&mut self, enable: bool) {
119 unsafe { 109 Self::regs().dier().write(|r| r.set_uie(enable));
120 Self::regs().dier().write(|r| r.set_uie(enable));
121 }
122 } 110 }
123 } 111 }
124 }; 112 };
@@ -141,14 +129,12 @@ macro_rules! impl_32bit_timer {
141 let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into())); 129 let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()));
142 130
143 let regs = Self::regs_gp32(); 131 let regs = Self::regs_gp32();
144 unsafe { 132 regs.psc().write(|r| r.set_psc(psc));
145 regs.psc().write(|r| r.set_psc(psc)); 133 regs.arr().write(|r| r.set_arr(arr));
146 regs.arr().write(|r| r.set_arr(arr));
147 134
148 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 135 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
149 regs.egr().write(|r| r.set_ug(true)); 136 regs.egr().write(|r| r.set_ug(true));
150 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 137 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
151 }
152 } 138 }
153 } 139 }
154 }; 140 };
@@ -185,7 +171,7 @@ foreach_interrupt! {
185 171
186 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 172 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
187 fn regs_gp16() -> crate::pac::timer::TimGp16 { 173 fn regs_gp16() -> crate::pac::timer::TimGp16 {
188 crate::pac::timer::TimGp16(crate::pac::$inst.0) 174 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
189 } 175 }
190 } 176 }
191 177
@@ -206,7 +192,7 @@ foreach_interrupt! {
206 192
207 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 193 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
208 fn regs_gp16() -> crate::pac::timer::TimGp16 { 194 fn regs_gp16() -> crate::pac::timer::TimGp16 {
209 crate::pac::timer::TimGp16(crate::pac::$inst.0) 195 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
210 } 196 }
211 } 197 }
212 198
diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs
deleted file mode 100644
index 062377999..000000000
--- a/embassy-stm32/src/tl_mbox/ble.rs
+++ /dev/null
@@ -1,64 +0,0 @@
1use embassy_futures::block_on;
2
3use super::cmd::CmdSerial;
4use super::consts::TlPacketType;
5use super::evt::EvtBox;
6use super::unsafe_linked_list::LinkedListNode;
7use super::{
8 channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL,
9 TL_REF_TABLE,
10};
11use crate::tl_mbox::cmd::CmdPacket;
12use crate::tl_mbox::ipcc::Ipcc;
13
14pub struct Ble;
15
16impl Ble {
17 pub fn enable() {
18 unsafe {
19 LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
20
21 TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
22 pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
23 pcs_buffer: CS_BUFFER.as_mut_ptr().cast(),
24 pevt_queue: EVT_QUEUE.as_ptr().cast(),
25 phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
26 });
27 }
28
29 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true);
30 }
31
32 pub fn evt_handler() {
33 unsafe {
34 let mut node_ptr = core::ptr::null_mut();
35 let node_ptr_ptr: *mut _ = &mut node_ptr;
36
37 while !LinkedListNode::is_empty(EVT_QUEUE.as_mut_ptr()) {
38 LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
39
40 let event = node_ptr.cast();
41 let event = EvtBox::new(event);
42
43 block_on(TL_CHANNEL.send(event));
44 }
45 }
46
47 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
48 }
49
50 pub fn send_cmd(buf: &[u8]) {
51 unsafe {
52 let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
53 let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial;
54 let pcmd_serial_buf: *mut u8 = pcmd_serial.cast();
55
56 core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
57
58 let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
59 cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8;
60 }
61
62 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
63 }
64}
diff --git a/embassy-stm32/src/tl_mbox/cmd.rs b/embassy-stm32/src/tl_mbox/cmd.rs
deleted file mode 100644
index 3507c3231..000000000
--- a/embassy-stm32/src/tl_mbox/cmd.rs
+++ /dev/null
@@ -1,49 +0,0 @@
1use super::PacketHeader;
2
3#[repr(C, packed)]
4#[derive(Copy, Clone)]
5pub struct Cmd {
6 pub cmd_code: u16,
7 pub payload_len: u8,
8 pub payload: [u8; 255],
9}
10
11impl Default for Cmd {
12 fn default() -> Self {
13 Self {
14 cmd_code: 0,
15 payload_len: 0,
16 payload: [0u8; 255],
17 }
18 }
19}
20
21#[repr(C, packed)]
22#[derive(Copy, Clone, Default)]
23pub struct CmdSerial {
24 pub ty: u8,
25 pub cmd: Cmd,
26}
27
28#[repr(C, packed)]
29#[derive(Copy, Clone, Default)]
30pub struct CmdPacket {
31 pub header: PacketHeader,
32 pub cmd_serial: CmdSerial,
33}
34
35#[repr(C, packed)]
36#[derive(Copy, Clone)]
37pub struct AclDataSerial {
38 pub ty: u8,
39 pub handle: u16,
40 pub length: u16,
41 pub acl_data: [u8; 1],
42}
43
44#[repr(C, packed)]
45#[derive(Copy, Clone)]
46pub struct AclDataPacket {
47 pub header: PacketHeader,
48 pub acl_data_serial: AclDataSerial,
49}
diff --git a/embassy-stm32/src/tl_mbox/consts.rs b/embassy-stm32/src/tl_mbox/consts.rs
deleted file mode 100644
index e16a26cd0..000000000
--- a/embassy-stm32/src/tl_mbox/consts.rs
+++ /dev/null
@@ -1,53 +0,0 @@
1#[derive(PartialEq)]
2#[repr(C)]
3pub enum TlPacketType {
4 BleCmd = 0x01,
5 AclData = 0x02,
6 BleEvt = 0x04,
7
8 OtCmd = 0x08,
9 OtRsp = 0x09,
10 CliCmd = 0x0A,
11 OtNot = 0x0C,
12 OtAck = 0x0D,
13 CliNot = 0x0E,
14 CliAck = 0x0F,
15
16 SysCmd = 0x10,
17 SysRsp = 0x11,
18 SysEvt = 0x12,
19
20 LocCmd = 0x20,
21 LocRsp = 0x21,
22
23 TracesApp = 0x40,
24 TracesWl = 0x41,
25}
26
27impl TryFrom<u8> for TlPacketType {
28 type Error = ();
29
30 fn try_from(value: u8) -> Result<Self, Self::Error> {
31 match value {
32 0x01 => Ok(TlPacketType::BleCmd),
33 0x02 => Ok(TlPacketType::AclData),
34 0x04 => Ok(TlPacketType::BleEvt),
35 0x08 => Ok(TlPacketType::OtCmd),
36 0x09 => Ok(TlPacketType::OtRsp),
37 0x0A => Ok(TlPacketType::CliCmd),
38 0x0C => Ok(TlPacketType::OtNot),
39 0x0D => Ok(TlPacketType::OtAck),
40 0x0E => Ok(TlPacketType::CliNot),
41 0x0F => Ok(TlPacketType::CliAck),
42 0x10 => Ok(TlPacketType::SysCmd),
43 0x11 => Ok(TlPacketType::SysRsp),
44 0x12 => Ok(TlPacketType::SysEvt),
45 0x20 => Ok(TlPacketType::LocCmd),
46 0x21 => Ok(TlPacketType::LocRsp),
47 0x40 => Ok(TlPacketType::TracesApp),
48 0x41 => Ok(TlPacketType::TracesWl),
49
50 _ => Err(()),
51 }
52 }
53}
diff --git a/embassy-stm32/src/tl_mbox/evt.rs b/embassy-stm32/src/tl_mbox/evt.rs
deleted file mode 100644
index 47a8b72fd..000000000
--- a/embassy-stm32/src/tl_mbox/evt.rs
+++ /dev/null
@@ -1,136 +0,0 @@
1use core::mem::MaybeUninit;
2
3use super::cmd::{AclDataPacket, AclDataSerial};
4use super::consts::TlPacketType;
5use super::{PacketHeader, TL_EVT_HEADER_SIZE};
6use crate::tl_mbox::mm::MemoryManager;
7
8/// the payload of [`Evt`] for a command status event
9#[derive(Copy, Clone)]
10#[repr(C, packed)]
11pub struct CsEvt {
12 pub status: u8,
13 pub num_cmd: u8,
14 pub cmd_code: u16,
15}
16
17/// the payload of [`Evt`] for a command complete event
18#[derive(Clone, Copy, Default)]
19#[repr(C, packed)]
20pub struct CcEvt {
21 pub num_cmd: u8,
22 pub cmd_code: u8,
23 pub payload: [u8; 1],
24}
25
26#[derive(Clone, Copy, Default)]
27#[repr(C, packed)]
28pub struct Evt {
29 pub evt_code: u8,
30 pub payload_len: u8,
31 pub payload: [u8; 1],
32}
33
34#[derive(Clone, Copy, Default)]
35#[repr(C, packed)]
36pub struct EvtSerial {
37 pub kind: u8,
38 pub evt: Evt,
39}
40
41/// This format shall be used for all events (asynchronous and command response) reported
42/// by the CPU2 except for the command response of a system command where the header is not there
43/// and the format to be used shall be `EvtSerial`.
44///
45/// ### Note:
46/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
47/// include the header and shall use `EvtPacket` format. Only the command response format on the
48/// system channel is different.
49#[derive(Clone, Copy, Default)]
50#[repr(C, packed)]
51pub struct EvtPacket {
52 pub header: PacketHeader,
53 pub evt_serial: EvtSerial,
54}
55
56/// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop
57pub struct EvtBox {
58 ptr: *mut EvtPacket,
59}
60
61unsafe impl Send for EvtBox {}
62impl EvtBox {
63 pub(super) fn new(ptr: *mut EvtPacket) -> Self {
64 Self { ptr }
65 }
66
67 /// Copies the event data from inner pointer and returns and event structure
68 pub fn evt(&self) -> EvtPacket {
69 let mut evt = MaybeUninit::uninit();
70 unsafe {
71 self.ptr.copy_to(evt.as_mut_ptr(), 1);
72 evt.assume_init()
73 }
74 }
75
76 /// Returns the size of a buffer required to hold this event
77 pub fn size(&self) -> Result<usize, ()> {
78 unsafe {
79 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
80
81 if evt_kind == TlPacketType::AclData {
82 let acl_data: *const AclDataPacket = self.ptr.cast();
83 let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
84
85 Ok((*acl_serial).length as usize + 5)
86 } else {
87 let evt_data: *const EvtPacket = self.ptr.cast();
88 let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
89
90 Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
91 }
92 }
93 }
94
95 /// writes an underlying [`EvtPacket`] into the provided buffer. Returns the number of bytes that were
96 /// written. Returns an error if event kind is unkown or if provided buffer size is not enough
97 pub fn copy_into_slice(&self, buf: &mut [u8]) -> Result<usize, ()> {
98 unsafe {
99 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
100
101 let evt_data: *const EvtPacket = self.ptr.cast();
102 let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
103 let evt_serial_buf: *const u8 = evt_serial.cast();
104
105 let acl_data: *const AclDataPacket = self.ptr.cast();
106 let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
107 let acl_serial_buf: *const u8 = acl_serial.cast();
108
109 if let TlPacketType::AclData = evt_kind {
110 let len = (*acl_serial).length as usize + 5;
111 if len > buf.len() {
112 return Err(());
113 }
114
115 core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
116
117 Ok(len)
118 } else {
119 let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
120 if len > buf.len() {
121 return Err(());
122 }
123
124 core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
125
126 Ok(len)
127 }
128 }
129 }
130}
131
132impl Drop for EvtBox {
133 fn drop(&mut self) {
134 MemoryManager::evt_drop(self.ptr);
135 }
136}
diff --git a/embassy-stm32/src/tl_mbox/ipcc.rs b/embassy-stm32/src/tl_mbox/ipcc.rs
deleted file mode 100644
index d1ac731ed..000000000
--- a/embassy-stm32/src/tl_mbox/ipcc.rs
+++ /dev/null
@@ -1,174 +0,0 @@
1use self::sealed::Instance;
2use crate::peripherals::IPCC;
3use crate::rcc::sealed::RccPeripheral;
4
5#[non_exhaustive]
6#[derive(Clone, Copy, Default)]
7pub struct Config {
8 // TODO: add IPCC peripheral configuration, if any, here
9 // reserved for future use
10}
11
12#[derive(Debug, Clone, Copy)]
13#[repr(C)]
14pub enum IpccChannel {
15 Channel1 = 0,
16 Channel2 = 1,
17 Channel3 = 2,
18 Channel4 = 3,
19 Channel5 = 4,
20 Channel6 = 5,
21}
22
23pub mod sealed {
24 pub trait Instance: crate::rcc::RccPeripheral {
25 fn regs() -> crate::pac::ipcc::Ipcc;
26 fn set_cpu2(enabled: bool);
27 }
28}
29
30pub struct Ipcc;
31
32impl Ipcc {
33 pub fn enable(_config: Config) {
34 IPCC::enable();
35 IPCC::reset();
36 IPCC::set_cpu2(true);
37
38 unsafe { _configure_pwr() };
39
40 let regs = IPCC::regs();
41
42 unsafe {
43 regs.cpu(0).cr().modify(|w| {
44 w.set_rxoie(true);
45 w.set_txfie(true);
46 })
47 }
48 }
49
50 pub fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) {
51 let regs = IPCC::regs();
52
53 // If bit is set to 1 then interrupt is disabled
54 unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
55 }
56
57 pub fn c1_get_rx_channel(channel: IpccChannel) -> bool {
58 let regs = IPCC::regs();
59
60 // If bit is set to 1 then interrupt is disabled
61 unsafe { !regs.cpu(0).mr().read().chom(channel as usize) }
62 }
63
64 #[allow(dead_code)]
65 pub fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) {
66 let regs = IPCC::regs();
67
68 // If bit is set to 1 then interrupt is disabled
69 unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
70 }
71
72 #[allow(dead_code)]
73 pub fn c2_get_rx_channel(channel: IpccChannel) -> bool {
74 let regs = IPCC::regs();
75
76 // If bit is set to 1 then interrupt is disabled
77 unsafe { !regs.cpu(1).mr().read().chom(channel as usize) }
78 }
79
80 pub fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) {
81 let regs = IPCC::regs();
82
83 // If bit is set to 1 then interrupt is disabled
84 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
85 }
86
87 pub fn c1_get_tx_channel(channel: IpccChannel) -> bool {
88 let regs = IPCC::regs();
89
90 // If bit is set to 1 then interrupt is disabled
91 unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) }
92 }
93
94 #[allow(dead_code)]
95 pub fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) {
96 let regs = IPCC::regs();
97
98 // If bit is set to 1 then interrupt is disabled
99 unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
100 }
101
102 #[allow(dead_code)]
103 pub fn c2_get_tx_channel(channel: IpccChannel) -> bool {
104 let regs = IPCC::regs();
105
106 // If bit is set to 1 then interrupt is disabled
107 unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) }
108 }
109
110 /// clears IPCC receive channel status for CPU1
111 pub fn c1_clear_flag_channel(channel: IpccChannel) {
112 let regs = IPCC::regs();
113
114 unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) }
115 }
116
117 #[allow(dead_code)]
118 /// clears IPCC receive channel status for CPU2
119 pub fn c2_clear_flag_channel(channel: IpccChannel) {
120 let regs = IPCC::regs();
121
122 unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) }
123 }
124
125 pub fn c1_set_flag_channel(channel: IpccChannel) {
126 let regs = IPCC::regs();
127
128 unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) }
129 }
130
131 #[allow(dead_code)]
132 pub fn c2_set_flag_channel(channel: IpccChannel) {
133 let regs = IPCC::regs();
134
135 unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) }
136 }
137
138 pub fn c1_is_active_flag(channel: IpccChannel) -> bool {
139 let regs = IPCC::regs();
140
141 unsafe { regs.cpu(0).sr().read().chf(channel as usize) }
142 }
143
144 pub fn c2_is_active_flag(channel: IpccChannel) -> bool {
145 let regs = IPCC::regs();
146
147 unsafe { regs.cpu(1).sr().read().chf(channel as usize) }
148 }
149
150 pub fn is_tx_pending(channel: IpccChannel) -> bool {
151 !Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel)
152 }
153
154 pub fn is_rx_pending(channel: IpccChannel) -> bool {
155 Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel)
156 }
157}
158
159impl sealed::Instance for crate::peripherals::IPCC {
160 fn regs() -> crate::pac::ipcc::Ipcc {
161 crate::pac::IPCC
162 }
163
164 fn set_cpu2(enabled: bool) {
165 unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) }
166 }
167}
168
169unsafe fn _configure_pwr() {
170 let rcc = crate::pac::RCC;
171
172 // set RF wake-up clock = LSE
173 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
174}
diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs
deleted file mode 100644
index e28a6aa0c..000000000
--- a/embassy-stm32/src/tl_mbox/mm.rs
+++ /dev/null
@@ -1,67 +0,0 @@
1use super::evt::EvtPacket;
2use super::unsafe_linked_list::LinkedListNode;
3use super::{
4 channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE,
5 SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
6};
7use crate::tl_mbox::ipcc::Ipcc;
8
9pub struct MemoryManager;
10
11impl MemoryManager {
12 pub fn enable() {
13 unsafe {
14 LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr());
15 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
16
17 TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
18 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
19 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
20 ble_pool: EVT_POOL.as_ptr().cast(),
21 ble_pool_size: POOL_SIZE as u32,
22 pevt_free_buffer_queue: FREE_BUFF_QUEUE.as_mut_ptr(),
23 traces_evt_pool: core::ptr::null(),
24 traces_pool_size: 0,
25 });
26 }
27 }
28
29 pub fn evt_handler() {
30 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
31 Self::send_free_buf();
32 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
33 }
34
35 pub fn evt_drop(evt: *mut EvtPacket) {
36 unsafe {
37 let list_node = evt.cast();
38
39 LinkedListNode::remove_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
40 }
41
42 let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
43
44 // postpone event buffer freeing to IPCC interrupt handler
45 if channel_is_busy {
46 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
47 } else {
48 Self::send_free_buf();
49 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
50 }
51 }
52
53 fn send_free_buf() {
54 unsafe {
55 let mut node_ptr = core::ptr::null_mut();
56 let node_ptr_ptr: *mut _ = &mut node_ptr;
57
58 while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
59 LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
60 LinkedListNode::insert_tail(
61 (*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
62 node_ptr,
63 );
64 }
65 }
66 }
67}
diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs
deleted file mode 100644
index efbbf2d1d..000000000
--- a/embassy-stm32/src/tl_mbox/mod.rs
+++ /dev/null
@@ -1,417 +0,0 @@
1use core::mem::MaybeUninit;
2
3use atomic_polyfill::{compiler_fence, Ordering};
4use bit_field::BitField;
5use embassy_cortex_m::interrupt::Interrupt;
6use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::channel::Channel;
9
10use self::ble::Ble;
11use self::cmd::{AclDataPacket, CmdPacket};
12use self::evt::{CsEvt, EvtBox};
13use self::mm::MemoryManager;
14use self::shci::{shci_ble_init, ShciBleInitCmdParam};
15use self::sys::Sys;
16use self::unsafe_linked_list::LinkedListNode;
17use crate::interrupt;
18use crate::peripherals::IPCC;
19pub use crate::tl_mbox::ipcc::Config;
20use crate::tl_mbox::ipcc::Ipcc;
21
22mod ble;
23mod channels;
24mod cmd;
25mod consts;
26mod evt;
27mod ipcc;
28mod mm;
29mod shci;
30mod sys;
31mod unsafe_linked_list;
32
33pub type PacketHeader = LinkedListNode;
34
35const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
36const TL_EVT_HEADER_SIZE: usize = 3;
37const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>();
38
39const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5;
40const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
41const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
42
43const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
44
45const fn divc(x: usize, y: usize) -> usize {
46 (x + y - 1) / y
47}
48
49#[repr(C, packed)]
50#[derive(Copy, Clone)]
51pub struct SafeBootInfoTable {
52 version: u32,
53}
54
55#[repr(C, packed)]
56#[derive(Copy, Clone)]
57pub struct FusInfoTable {
58 version: u32,
59 memory_size: u32,
60 fus_info: u32,
61}
62
63/// Interrupt handler.
64pub struct ReceiveInterruptHandler {}
65
66impl interrupt::Handler<interrupt::IPCC_C1_RX> for ReceiveInterruptHandler {
67 unsafe fn on_interrupt() {
68 // info!("ipcc rx interrupt");
69
70 if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
71 sys::Sys::evt_handler();
72 } else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
73 ble::Ble::evt_handler();
74 } else {
75 todo!()
76 }
77 }
78}
79
80pub struct TransmitInterruptHandler {}
81
82impl interrupt::Handler<interrupt::IPCC_C1_TX> for TransmitInterruptHandler {
83 unsafe fn on_interrupt() {
84 // info!("ipcc tx interrupt");
85
86 if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
87 // TODO: handle this case
88 let _ = sys::Sys::cmd_evt_handler();
89 } else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
90 mm::MemoryManager::evt_handler();
91 } else {
92 todo!()
93 }
94 }
95}
96
97/// # Version
98/// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version
99/// - 4 -> 7 = branch - 0: Mass Market - x: ...
100/// - 8 -> 15 = Subversion
101/// - 16 -> 23 = Version minor
102/// - 24 -> 31 = Version major
103/// # Memory Size
104/// - 0 -> 7 = Flash ( Number of 4k sector)
105/// - 8 -> 15 = Reserved ( Shall be set to 0 - may be used as flash extension )
106/// - 16 -> 23 = SRAM2b ( Number of 1k sector)
107/// - 24 -> 31 = SRAM2a ( Number of 1k sector)
108#[repr(C, packed)]
109#[derive(Copy, Clone)]
110pub struct WirelessFwInfoTable {
111 version: u32,
112 memory_size: u32,
113 info_stack: u32,
114 reserved: u32,
115}
116
117impl WirelessFwInfoTable {
118 pub fn version_major(&self) -> u8 {
119 let version = self.version;
120 (version.get_bits(24..31) & 0xff) as u8
121 }
122
123 pub fn version_minor(&self) -> u8 {
124 let version = self.version;
125 (version.get_bits(16..23) & 0xff) as u8
126 }
127
128 pub fn subversion(&self) -> u8 {
129 let version = self.version;
130 (version.get_bits(8..15) & 0xff) as u8
131 }
132
133 /// size of FLASH, expressed in number of 4K sectors
134 pub fn flash_size(&self) -> u8 {
135 let memory_size = self.memory_size;
136 (memory_size.get_bits(0..7) & 0xff) as u8
137 }
138
139 /// size for SRAM2a, expressed in number of 1K sectors
140 pub fn sram2a_size(&self) -> u8 {
141 let memory_size = self.memory_size;
142 (memory_size.get_bits(24..31) & 0xff) as u8
143 }
144
145 /// size of SRAM2b, expressed in number of 1K sectors
146 pub fn sram2b_size(&self) -> u8 {
147 let memory_size = self.memory_size;
148 (memory_size.get_bits(16..23) & 0xff) as u8
149 }
150}
151
152#[repr(C, packed)]
153#[derive(Copy, Clone)]
154pub struct DeviceInfoTable {
155 pub safe_boot_info_table: SafeBootInfoTable,
156 pub fus_info_table: FusInfoTable,
157 pub wireless_fw_info_table: WirelessFwInfoTable,
158}
159
160#[repr(C, packed)]
161struct BleTable {
162 pcmd_buffer: *mut CmdPacket,
163 pcs_buffer: *const u8,
164 pevt_queue: *const u8,
165 phci_acl_data_buffer: *mut AclDataPacket,
166}
167
168#[repr(C, packed)]
169struct ThreadTable {
170 no_stack_buffer: *const u8,
171 cli_cmd_rsp_buffer: *const u8,
172 ot_cmd_rsp_buffer: *const u8,
173}
174
175#[repr(C, packed)]
176struct SysTable {
177 pcmd_buffer: *mut CmdPacket,
178 sys_queue: *const LinkedListNode,
179}
180
181#[allow(dead_code)] // Not used currently but reserved
182#[repr(C, packed)]
183struct LldTestTable {
184 cli_cmd_rsp_buffer: *const u8,
185 m0_cmd_buffer: *const u8,
186}
187
188#[allow(dead_code)] // Not used currently but reserved
189#[repr(C, packed)]
190struct BleLldTable {
191 cmd_rsp_buffer: *const u8,
192 m0_cmd_buffer: *const u8,
193}
194
195#[allow(dead_code)] // Not used currently but reserved
196#[repr(C, packed)]
197struct ZigbeeTable {
198 notif_m0_to_m4_buffer: *const u8,
199 appli_cmd_m4_to_m0_buffer: *const u8,
200 request_m0_to_m4_buffer: *const u8,
201}
202
203#[repr(C, packed)]
204struct MemManagerTable {
205 spare_ble_buffer: *const u8,
206 spare_sys_buffer: *const u8,
207
208 ble_pool: *const u8,
209 ble_pool_size: u32,
210
211 pevt_free_buffer_queue: *mut LinkedListNode,
212
213 traces_evt_pool: *const u8,
214 traces_pool_size: u32,
215}
216
217#[repr(C, packed)]
218struct TracesTable {
219 traces_queue: *const u8,
220}
221
222#[repr(C, packed)]
223struct Mac802_15_4Table {
224 pcmd_rsp_buffer: *const u8,
225 pnotack_buffer: *const u8,
226 evt_queue: *const u8,
227}
228
229/// reference table. Contains pointers to all other tables
230#[repr(C, packed)]
231#[derive(Copy, Clone)]
232pub struct RefTable {
233 pub device_info_table: *const DeviceInfoTable,
234 ble_table: *const BleTable,
235 thread_table: *const ThreadTable,
236 sys_table: *const SysTable,
237 mem_manager_table: *const MemManagerTable,
238 traces_table: *const TracesTable,
239 mac_802_15_4_table: *const Mac802_15_4Table,
240 zigbee_table: *const ZigbeeTable,
241 lld_tests_table: *const LldTestTable,
242 ble_lld_table: *const BleLldTable,
243}
244
245#[link_section = "TL_REF_TABLE"]
246pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
247
248#[link_section = "MB_MEM1"]
249static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
250
251#[link_section = "MB_MEM1"]
252static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
253
254#[link_section = "MB_MEM1"]
255static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
256
257#[link_section = "MB_MEM1"]
258static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit();
259
260#[link_section = "MB_MEM1"]
261static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit();
262
263#[link_section = "MB_MEM1"]
264static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
265
266#[link_section = "MB_MEM1"]
267static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
268
269#[link_section = "MB_MEM1"]
270static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
271
272#[link_section = "MB_MEM1"]
273static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
274
275#[link_section = "MB_MEM1"]
276static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit();
277
278#[allow(dead_code)] // Not used currently but reserved
279#[link_section = "MB_MEM1"]
280static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
281
282// not in shared RAM
283static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
284
285#[link_section = "MB_MEM2"]
286static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
287 MaybeUninit::uninit();
288
289#[link_section = "MB_MEM2"]
290static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
291
292#[link_section = "MB_MEM2"]
293static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
294
295#[link_section = "MB_MEM2"]
296static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
297
298#[link_section = "MB_MEM2"]
299static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
300
301#[link_section = "MB_MEM2"]
302static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
303 MaybeUninit::uninit();
304
305#[link_section = "MB_MEM2"]
306static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
307 MaybeUninit::uninit();
308
309#[link_section = "MB_MEM2"]
310static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
311
312#[link_section = "MB_MEM2"]
313// "magic" numbers from ST ---v---v
314static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
315
316// TODO: get a better size, this is a placeholder
317pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new();
318
319pub struct TlMbox<'d> {
320 _ipcc: PeripheralRef<'d, IPCC>,
321}
322
323impl<'d> TlMbox<'d> {
324 /// initializes low-level transport between CPU1 and BLE stack on CPU2
325 pub fn new(
326 ipcc: impl Peripheral<P = IPCC> + 'd,
327 _irqs: impl interrupt::Binding<interrupt::IPCC_C1_RX, ReceiveInterruptHandler>
328 + interrupt::Binding<interrupt::IPCC_C1_TX, TransmitInterruptHandler>,
329 config: Config,
330 ) -> Self {
331 into_ref!(ipcc);
332
333 unsafe {
334 compiler_fence(Ordering::AcqRel);
335
336 TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
337 device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
338 ble_table: TL_BLE_TABLE.as_ptr(),
339 thread_table: TL_THREAD_TABLE.as_ptr(),
340 sys_table: TL_SYS_TABLE.as_ptr(),
341 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
342 traces_table: TL_TRACES_TABLE.as_ptr(),
343 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
344 zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
345 lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
346 ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
347 });
348
349 // info!("TL_REF_TABLE addr: {:x}", TL_REF_TABLE.as_ptr() as usize);
350
351 compiler_fence(Ordering::AcqRel);
352
353 TL_SYS_TABLE = MaybeUninit::zeroed();
354 TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed();
355 TL_BLE_TABLE = MaybeUninit::zeroed();
356 TL_THREAD_TABLE = MaybeUninit::zeroed();
357 TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
358 TL_TRACES_TABLE = MaybeUninit::zeroed();
359 TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed();
360 TL_ZIGBEE_TABLE = MaybeUninit::zeroed();
361 TL_LLD_TESTS_TABLE = MaybeUninit::zeroed();
362 TL_BLE_LLD_TABLE = MaybeUninit::zeroed();
363
364 EVT_POOL = MaybeUninit::zeroed();
365 SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
366 BLE_SPARE_EVT_BUF = MaybeUninit::zeroed();
367
368 CS_BUFFER = MaybeUninit::zeroed();
369 BLE_CMD_BUFFER = MaybeUninit::zeroed();
370 HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed();
371
372 compiler_fence(Ordering::AcqRel);
373 }
374
375 Ipcc::enable(config);
376
377 Sys::enable();
378 Ble::enable();
379 MemoryManager::enable();
380
381 // enable interrupts
382 crate::interrupt::IPCC_C1_RX::unpend();
383 crate::interrupt::IPCC_C1_TX::unpend();
384
385 unsafe { crate::interrupt::IPCC_C1_RX::enable() };
386 unsafe { crate::interrupt::IPCC_C1_TX::enable() };
387
388 Self { _ipcc: ipcc }
389 }
390
391 pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
392 let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table };
393
394 // zero version indicates that CPU2 wasn't active and didn't fill the information table
395 if info.version != 0 {
396 Some(*info)
397 } else {
398 None
399 }
400 }
401
402 pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) {
403 shci_ble_init(param);
404 }
405
406 pub fn send_ble_cmd(&self, buf: &[u8]) {
407 ble::Ble::send_cmd(buf);
408 }
409
410 // pub fn send_sys_cmd(&self, buf: &[u8]) {
411 // sys::Sys::send_cmd(buf);
412 // }
413
414 pub async fn read(&self) -> EvtBox {
415 TL_CHANNEL.recv().await
416 }
417}
diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32/src/tl_mbox/shci.rs
deleted file mode 100644
index 6b5b2dd19..000000000
--- a/embassy-stm32/src/tl_mbox/shci.rs
+++ /dev/null
@@ -1,101 +0,0 @@
1//! HCI commands for system channel
2
3use super::cmd::CmdPacket;
4use super::consts::TlPacketType;
5use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
6use crate::tl_mbox::ipcc::Ipcc;
7
8const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
9pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
10#[allow(dead_code)]
11const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
12
13#[derive(Clone, Copy)]
14#[repr(C, packed)]
15pub struct ShciBleInitCmdParam {
16 /// NOT USED CURRENTLY
17 pub p_ble_buffer_address: u32,
18
19 /// Size of the Buffer allocated in pBleBufferAddress
20 pub ble_buffer_size: u32,
21
22 pub num_attr_record: u16,
23 pub num_attr_serv: u16,
24 pub attr_value_arr_size: u16,
25 pub num_of_links: u8,
26 pub extended_packet_length_enable: u8,
27 pub pr_write_list_size: u8,
28 pub mb_lock_count: u8,
29
30 pub att_mtu: u16,
31 pub slave_sca: u16,
32 pub master_sca: u8,
33 pub ls_source: u8,
34 pub max_conn_event_length: u32,
35 pub hs_startup_time: u16,
36 pub viterbi_enable: u8,
37 pub ll_only: u8,
38 pub hw_version: u8,
39}
40
41impl Default for ShciBleInitCmdParam {
42 fn default() -> Self {
43 Self {
44 p_ble_buffer_address: 0,
45 ble_buffer_size: 0,
46 num_attr_record: 68,
47 num_attr_serv: 8,
48 attr_value_arr_size: 1344,
49 num_of_links: 2,
50 extended_packet_length_enable: 1,
51 pr_write_list_size: 0x3A,
52 mb_lock_count: 0x79,
53 att_mtu: 156,
54 slave_sca: 500,
55 master_sca: 0,
56 ls_source: 1,
57 max_conn_event_length: 0xFFFFFFFF,
58 hs_startup_time: 0x148,
59 viterbi_enable: 1,
60 ll_only: 0,
61 hw_version: 0,
62 }
63 }
64}
65
66#[derive(Clone, Copy, Default)]
67#[repr(C, packed)]
68pub struct ShciHeader {
69 metadata: [u32; 3],
70}
71
72#[derive(Clone, Copy)]
73#[repr(C, packed)]
74pub struct ShciBleInitCmdPacket {
75 header: ShciHeader,
76 param: ShciBleInitCmdParam,
77}
78
79pub fn shci_ble_init(param: ShciBleInitCmdParam) {
80 let mut packet = ShciBleInitCmdPacket {
81 header: ShciHeader::default(),
82 param,
83 };
84
85 let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet;
86
87 unsafe {
88 let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
89
90 (*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
91 (*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
92
93 let cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
94 core::ptr::write(cmd_buf, *cmd_ptr);
95
96 cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8;
97
98 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
99 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
100 }
101}
diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs
deleted file mode 100644
index 9685fb920..000000000
--- a/embassy-stm32/src/tl_mbox/sys.rs
+++ /dev/null
@@ -1,83 +0,0 @@
1use embassy_futures::block_on;
2
3use super::cmd::{CmdPacket, CmdSerial};
4use super::consts::TlPacketType;
5use super::evt::{CcEvt, EvtBox, EvtSerial};
6use super::unsafe_linked_list::LinkedListNode;
7use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE};
8use crate::tl_mbox::ipcc::Ipcc;
9
10pub struct Sys;
11
12impl Sys {
13 pub fn enable() {
14 unsafe {
15 LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
16
17 TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
18 pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
19 sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
20 });
21 }
22
23 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true);
24 }
25
26 pub fn evt_handler() {
27 unsafe {
28 let mut node_ptr = core::ptr::null_mut();
29 let node_ptr_ptr: *mut _ = &mut node_ptr;
30
31 while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
32 LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
33
34 let event = node_ptr.cast();
35 let event = EvtBox::new(event);
36
37 // TODO: not really happy about this
38 block_on(TL_CHANNEL.send(event));
39 }
40 }
41
42 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
43 }
44
45 pub fn cmd_evt_handler() -> CcEvt {
46 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
47
48 // ST's command response data structure is really convoluted.
49 //
50 // for command response events on SYS channel, the header is missing
51 // and one should:
52 // 1. interpret the content of CMD_BUFFER as CmdPacket
53 // 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial
54 // 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt
55 // 4. CcEvt type is the actual SHCI response
56 // 5. profit
57 unsafe {
58 let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
59 let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial;
60 let evt_serial: *const EvtSerial = cmd_serial.cast();
61 let cc = (*evt_serial).evt.payload.as_ptr().cast();
62 *cc
63 }
64 }
65
66 #[allow(dead_code)]
67 pub fn send_cmd(buf: &[u8]) {
68 unsafe {
69 // TODO: check this
70 let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
71 let cmd_serial: *mut CmdSerial = &mut cmd_buffer.cmd_serial;
72 let cmd_serial_buf = cmd_serial.cast();
73
74 core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len());
75
76 let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
77 cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8;
78
79 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
80 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
81 }
82 }
83}
diff --git a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs b/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs
deleted file mode 100644
index 482e2bf5a..000000000
--- a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs
+++ /dev/null
@@ -1,125 +0,0 @@
1//! Unsafe linked list.
2//! Translated from ST's C by `c2rust` tool.
3
4#![allow(
5 dead_code,
6 mutable_transmutes,
7 non_camel_case_types,
8 non_snake_case,
9 non_upper_case_globals,
10 unused_assignments,
11 unused_mut
12)]
13
14use cortex_m::interrupt;
15
16#[derive(Copy, Clone)]
17#[repr(C, packed(4))]
18pub struct LinkedListNode {
19 pub next: *mut LinkedListNode,
20 pub prev: *mut LinkedListNode,
21}
22
23impl Default for LinkedListNode {
24 fn default() -> Self {
25 LinkedListNode {
26 next: core::ptr::null_mut(),
27 prev: core::ptr::null_mut(),
28 }
29 }
30}
31
32impl LinkedListNode {
33 pub unsafe fn init_head(mut list_head: *mut LinkedListNode) {
34 (*list_head).next = list_head;
35 (*list_head).prev = list_head;
36 }
37
38 pub unsafe fn is_empty(mut list_head: *mut LinkedListNode) -> bool {
39 interrupt::free(|_| ((*list_head).next) == list_head)
40 }
41
42 pub unsafe fn insert_head(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
43 interrupt::free(|_| {
44 (*node).next = (*list_head).next;
45 (*node).prev = list_head;
46 (*list_head).next = node;
47 (*(*node).next).prev = node;
48 });
49 }
50
51 pub unsafe fn insert_tail(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
52 interrupt::free(|_| {
53 (*node).next = list_head;
54 (*node).prev = (*list_head).prev;
55 (*list_head).prev = node;
56 (*(*node).prev).next = node;
57 });
58 }
59
60 pub unsafe fn remove_node(mut node: *mut LinkedListNode) {
61 interrupt::free(|_| {
62 (*(*node).prev).next = (*node).next;
63 (*(*node).next).prev = (*node).prev;
64 });
65 }
66
67 pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
68 interrupt::free(|_| {
69 *node = (*list_head).next;
70 Self::remove_node((*list_head).next);
71 });
72 }
73
74 pub unsafe fn remove_tail(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
75 interrupt::free(|_| {
76 *node = (*list_head).prev;
77 Self::remove_node((*list_head).prev);
78 });
79 }
80
81 pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
82 interrupt::free(|_| {
83 (*node).next = (*ref_node).next;
84 (*node).prev = ref_node;
85 (*ref_node).next = node;
86 (*(*node).next).prev = node;
87 });
88 }
89
90 pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
91 interrupt::free(|_| {
92 (*node).next = ref_node;
93 (*node).prev = (*ref_node).prev;
94 (*ref_node).prev = node;
95 (*(*node).prev).next = node;
96 });
97 }
98
99 pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
100 interrupt::free(|_| {
101 let mut size = 0;
102 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
103
104 temp = (*list_head).next;
105 while temp != list_head {
106 size += 1;
107 temp = (*temp).next
108 }
109
110 size
111 })
112 }
113
114 pub unsafe fn get_next_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
115 interrupt::free(|_| {
116 *node = (*ref_node).next;
117 });
118 }
119
120 pub unsafe fn get_prev_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
121 interrupt::free(|_| {
122 *node = (*ref_node).prev;
123 });
124 }
125}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 252e945da..433ad299c 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -2,79 +2,81 @@ use core::future::poll_fn;
2use core::slice; 2use core::slice;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_cortex_m::interrupt::Interrupt;
6use embassy_hal_common::atomic_ring_buffer::RingBuffer; 5use embassy_hal_common::atomic_ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
8 7
9use super::*; 8use super::*;
9use crate::interrupt::typelevel::Interrupt;
10 10
11/// Interrupt handler. 11/// Interrupt handler.
12pub struct InterruptHandler<T: BasicInstance> { 12pub struct InterruptHandler<T: BasicInstance> {
13 _phantom: PhantomData<T>, 13 _phantom: PhantomData<T>,
14} 14}
15 15
16impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 16impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
17 unsafe fn on_interrupt() { 17 unsafe fn on_interrupt() {
18 let r = T::regs(); 18 let r = T::regs();
19 let state = T::buffered_state(); 19 let state = T::buffered_state();
20 20
21 // RX 21 // RX
22 unsafe { 22 let sr_val = sr(r).read();
23 let sr = sr(r).read(); 23 // On v1 & v2, reading DR clears the rxne, error and idle interrupt
24 clear_interrupt_flags(r, sr); 24 // flags. Keep this close to the SR read to reduce the chance of a
25 25 // flag being set in-between.
26 if sr.rxne() { 26 let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) {
27 if sr.pe() { 27 Some(rdr(r).read_volatile())
28 warn!("Parity error"); 28 } else {
29 } 29 None
30 if sr.fe() { 30 };
31 warn!("Framing error"); 31 clear_interrupt_flags(r, sr_val);
32 } 32
33 if sr.ne() { 33 if sr_val.pe() {
34 warn!("Noise error"); 34 warn!("Parity error");
35 } 35 }
36 if sr.ore() { 36 if sr_val.fe() {
37 warn!("Overrun error"); 37 warn!("Framing error");
38 } 38 }
39 39 if sr_val.ne() {
40 let mut rx_writer = state.rx_buf.writer(); 40 warn!("Noise error");
41 let buf = rx_writer.push_slice(); 41 }
42 if !buf.is_empty() { 42 if sr_val.ore() {
43 // This read also clears the error and idle interrupt flags on v1. 43 warn!("Overrun error");
44 buf[0] = rdr(r).read_volatile(); 44 }
45 rx_writer.push_done(1); 45 if sr_val.rxne() {
46 } else { 46 let mut rx_writer = state.rx_buf.writer();
47 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 47 let buf = rx_writer.push_slice();
48 } 48 if !buf.is_empty() {
49 49 buf[0] = dr.unwrap();
50 if state.rx_buf.is_full() { 50 rx_writer.push_done(1);
51 state.rx_waker.wake(); 51 } else {
52 } 52 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
53 } 53 }
54 54
55 if sr.idle() { 55 if state.rx_buf.is_full() {
56 state.rx_waker.wake(); 56 state.rx_waker.wake();
57 }; 57 }
58 }
59
60 if sr_val.idle() {
61 state.rx_waker.wake();
58 } 62 }
59 63
60 // TX 64 // TX
61 unsafe { 65 if sr(r).read().txe() {
62 if sr(r).read().txe() { 66 let mut tx_reader = state.tx_buf.reader();
63 let mut tx_reader = state.tx_buf.reader(); 67 let buf = tx_reader.pop_slice();
64 let buf = tx_reader.pop_slice(); 68 if !buf.is_empty() {
65 if !buf.is_empty() { 69 r.cr1().modify(|w| {
66 r.cr1().modify(|w| { 70 w.set_txeie(true);
67 w.set_txeie(true); 71 });
68 }); 72 tdr(r).write_volatile(buf[0].into());
69 tdr(r).write_volatile(buf[0].into()); 73 tx_reader.pop_done(1);
70 tx_reader.pop_done(1); 74 state.tx_waker.wake();
71 state.tx_waker.wake(); 75 } else {
72 } else { 76 // Disable interrupt until we have something to transmit again
73 // Disable interrupt until we have something to transmit again 77 r.cr1().modify(|w| {
74 r.cr1().modify(|w| { 78 w.set_txeie(false);
75 w.set_txeie(false); 79 });
76 });
77 }
78 } 80 }
79 } 81 }
80 } 82 }
@@ -115,7 +117,7 @@ pub struct BufferedUartRx<'d, T: BasicInstance> {
115impl<'d, T: BasicInstance> BufferedUart<'d, T> { 117impl<'d, T: BasicInstance> BufferedUart<'d, T> {
116 pub fn new( 118 pub fn new(
117 peri: impl Peripheral<P = T> + 'd, 119 peri: impl Peripheral<P = T> + 'd,
118 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 120 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
119 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 121 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
120 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 122 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
121 tx_buffer: &'d mut [u8], 123 tx_buffer: &'d mut [u8],
@@ -130,7 +132,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
130 132
131 pub fn new_with_rtscts( 133 pub fn new_with_rtscts(
132 peri: impl Peripheral<P = T> + 'd, 134 peri: impl Peripheral<P = T> + 'd,
133 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 135 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
134 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 136 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
135 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 137 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
136 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 138 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
@@ -144,14 +146,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
144 T::enable(); 146 T::enable();
145 T::reset(); 147 T::reset();
146 148
147 unsafe { 149 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
148 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 150 cts.set_as_af(cts.af_num(), AFType::Input);
149 cts.set_as_af(cts.af_num(), AFType::Input); 151 T::regs().cr3().write(|w| {
150 T::regs().cr3().write(|w| { 152 w.set_rtse(true);
151 w.set_rtse(true); 153 w.set_ctse(true);
152 w.set_ctse(true); 154 });
153 });
154 }
155 155
156 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 156 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
157 } 157 }
@@ -159,7 +159,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
159 #[cfg(not(any(usart_v1, usart_v2)))] 159 #[cfg(not(any(usart_v1, usart_v2)))]
160 pub fn new_with_de( 160 pub fn new_with_de(
161 peri: impl Peripheral<P = T> + 'd, 161 peri: impl Peripheral<P = T> + 'd,
162 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 162 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
163 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 163 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
164 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 164 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
165 de: impl Peripheral<P = impl DePin<T>> + 'd, 165 de: impl Peripheral<P = impl DePin<T>> + 'd,
@@ -172,12 +172,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
172 T::enable(); 172 T::enable();
173 T::reset(); 173 T::reset();
174 174
175 unsafe { 175 de.set_as_af(de.af_num(), AFType::OutputPushPull);
176 de.set_as_af(de.af_num(), AFType::OutputPushPull); 176 T::regs().cr3().write(|w| {
177 T::regs().cr3().write(|w| { 177 w.set_dem(true);
178 w.set_dem(true); 178 });
179 });
180 }
181 179
182 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 180 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
183 } 181 }
@@ -199,22 +197,18 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
199 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; 197 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
200 198
201 let r = T::regs(); 199 let r = T::regs();
202 unsafe { 200 rx.set_as_af(rx.af_num(), AFType::Input);
203 rx.set_as_af(rx.af_num(), AFType::Input); 201 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
204 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
205 }
206 202
207 configure(r, &config, T::frequency(), T::KIND, true, true); 203 configure(r, &config, T::frequency(), T::KIND, true, true);
208 204
209 unsafe { 205 r.cr1().modify(|w| {
210 r.cr1().modify(|w| { 206 #[cfg(lpuart_v2)]
211 #[cfg(lpuart_v2)] 207 w.set_fifoen(true);
212 w.set_fifoen(true);
213 208
214 w.set_rxneie(true); 209 w.set_rxneie(true);
215 w.set_idleie(true); 210 w.set_idleie(true);
216 }); 211 });
217 }
218 212
219 T::Interrupt::unpend(); 213 T::Interrupt::unpend();
220 unsafe { T::Interrupt::enable() }; 214 unsafe { T::Interrupt::enable() };
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index ef1080153..c97efbf0a 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -5,13 +5,13 @@ use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_cortex_m::interrupt::Interrupt;
9use embassy_hal_common::drop::OnDrop; 8use embassy_hal_common::drop::OnDrop;
10use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
11use futures::future::{select, Either}; 10use futures::future::{select, Either};
12 11
13use crate::dma::{NoDma, Transfer}; 12use crate::dma::{NoDma, Transfer};
14use crate::gpio::sealed::AFType; 13use crate::gpio::sealed::AFType;
14use crate::interrupt::typelevel::Interrupt;
15#[cfg(not(any(usart_v1, usart_v2)))] 15#[cfg(not(any(usart_v1, usart_v2)))]
16#[allow(unused_imports)] 16#[allow(unused_imports)]
17use crate::pac::usart::regs::Isr as Sr; 17use crate::pac::usart::regs::Isr as Sr;
@@ -31,40 +31,36 @@ pub struct InterruptHandler<T: BasicInstance> {
31 _phantom: PhantomData<T>, 31 _phantom: PhantomData<T>,
32} 32}
33 33
34impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 34impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
35 unsafe fn on_interrupt() { 35 unsafe fn on_interrupt() {
36 let r = T::regs(); 36 let r = T::regs();
37 let s = T::state(); 37 let s = T::state();
38 38
39 let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; 39 let (sr, cr1, cr3) = (sr(r).read(), r.cr1().read(), r.cr3().read());
40 40
41 let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); 41 let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
42 if has_errors { 42 if has_errors {
43 // clear all interrupts and DMA Rx Request 43 // clear all interrupts and DMA Rx Request
44 unsafe { 44 r.cr1().modify(|w| {
45 r.cr1().modify(|w| { 45 // disable RXNE interrupt
46 // disable RXNE interrupt 46 w.set_rxneie(false);
47 w.set_rxneie(false); 47 // disable parity interrupt
48 // disable parity interrupt 48 w.set_peie(false);
49 w.set_peie(false); 49 // disable idle line interrupt
50 // disable idle line interrupt 50 w.set_idleie(false);
51 w.set_idleie(false); 51 });
52 }); 52 r.cr3().modify(|w| {
53 r.cr3().modify(|w| { 53 // disable Error Interrupt: (Frame error, Noise error, Overrun error)
54 // disable Error Interrupt: (Frame error, Noise error, Overrun error) 54 w.set_eie(false);
55 w.set_eie(false); 55 // disable DMA Rx Request
56 // disable DMA Rx Request 56 w.set_dmar(false);
57 w.set_dmar(false); 57 });
58 });
59 }
60 } else if cr1.idleie() && sr.idle() { 58 } else if cr1.idleie() && sr.idle() {
61 // IDLE detected: no more data will come 59 // IDLE detected: no more data will come
62 unsafe { 60 r.cr1().modify(|w| {
63 r.cr1().modify(|w| { 61 // disable idle line detection
64 // disable idle line detection 62 w.set_idleie(false);
65 w.set_idleie(false); 63 });
66 });
67 }
68 } else if cr1.rxneie() { 64 } else if cr1.rxneie() {
69 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller 65 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller
70 66
@@ -205,12 +201,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
205 T::enable(); 201 T::enable();
206 T::reset(); 202 T::reset();
207 203
208 unsafe { 204 cts.set_as_af(cts.af_num(), AFType::Input);
209 cts.set_as_af(cts.af_num(), AFType::Input); 205 T::regs().cr3().write(|w| {
210 T::regs().cr3().write(|w| { 206 w.set_ctse(true);
211 w.set_ctse(true); 207 });
212 });
213 }
214 Self::new_inner(peri, tx, tx_dma, config) 208 Self::new_inner(peri, tx, tx_dma, config)
215 } 209 }
216 210
@@ -224,9 +218,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
224 218
225 let r = T::regs(); 219 let r = T::regs();
226 220
227 unsafe { 221 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
228 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
229 }
230 222
231 configure(r, &config, T::frequency(), T::KIND, false, true); 223 configure(r, &config, T::frequency(), T::KIND, false, true);
232 224
@@ -245,11 +237,9 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
245 { 237 {
246 let ch = &mut self.tx_dma; 238 let ch = &mut self.tx_dma;
247 let request = ch.request(); 239 let request = ch.request();
248 unsafe { 240 T::regs().cr3().modify(|reg| {
249 T::regs().cr3().modify(|reg| { 241 reg.set_dmat(true);
250 reg.set_dmat(true); 242 });
251 });
252 }
253 // If we don't assign future to a variable, the data register pointer 243 // If we don't assign future to a variable, the data register pointer
254 // is held across an await and makes the future non-Send. 244 // is held across an await and makes the future non-Send.
255 let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) }; 245 let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
@@ -258,21 +248,17 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
258 } 248 }
259 249
260 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 250 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
261 unsafe { 251 let r = T::regs();
262 let r = T::regs(); 252 for &b in buffer {
263 for &b in buffer { 253 while !sr(r).read().txe() {}
264 while !sr(r).read().txe() {} 254 unsafe { tdr(r).write_volatile(b) };
265 tdr(r).write_volatile(b);
266 }
267 } 255 }
268 Ok(()) 256 Ok(())
269 } 257 }
270 258
271 pub fn blocking_flush(&mut self) -> Result<(), Error> { 259 pub fn blocking_flush(&mut self) -> Result<(), Error> {
272 unsafe { 260 let r = T::regs();
273 let r = T::regs(); 261 while !sr(r).read().tc() {}
274 while !sr(r).read().tc() {}
275 }
276 Ok(()) 262 Ok(())
277 } 263 }
278} 264}
@@ -281,7 +267,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
281 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 267 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
282 pub fn new( 268 pub fn new(
283 peri: impl Peripheral<P = T> + 'd, 269 peri: impl Peripheral<P = T> + 'd,
284 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 270 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
285 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 271 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
286 rx_dma: impl Peripheral<P = RxDma> + 'd, 272 rx_dma: impl Peripheral<P = RxDma> + 'd,
287 config: Config, 273 config: Config,
@@ -294,7 +280,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
294 280
295 pub fn new_with_rts( 281 pub fn new_with_rts(
296 peri: impl Peripheral<P = T> + 'd, 282 peri: impl Peripheral<P = T> + 'd,
297 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 283 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
298 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 284 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
299 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 285 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
300 rx_dma: impl Peripheral<P = RxDma> + 'd, 286 rx_dma: impl Peripheral<P = RxDma> + 'd,
@@ -305,12 +291,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
305 T::enable(); 291 T::enable();
306 T::reset(); 292 T::reset();
307 293
308 unsafe { 294 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
309 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 295 T::regs().cr3().write(|w| {
310 T::regs().cr3().write(|w| { 296 w.set_rtse(true);
311 w.set_rtse(true); 297 });
312 });
313 }
314 298
315 Self::new_inner(peri, rx, rx_dma, config) 299 Self::new_inner(peri, rx, rx_dma, config)
316 } 300 }
@@ -325,9 +309,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
325 309
326 let r = T::regs(); 310 let r = T::regs();
327 311
328 unsafe { 312 rx.set_as_af(rx.af_num(), AFType::Input);
329 rx.set_as_af(rx.af_num(), AFType::Input);
330 }
331 313
332 configure(r, &config, T::frequency(), T::KIND, true, false); 314 configure(r, &config, T::frequency(), T::KIND, true, false);
333 315
@@ -347,7 +329,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
347 } 329 }
348 330
349 #[cfg(any(usart_v1, usart_v2))] 331 #[cfg(any(usart_v1, usart_v2))]
350 unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { 332 fn check_rx_flags(&mut self) -> Result<bool, Error> {
351 let r = T::regs(); 333 let r = T::regs();
352 loop { 334 loop {
353 // Handle all buffered error flags. 335 // Handle all buffered error flags.
@@ -380,7 +362,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
380 } 362 }
381 363
382 #[cfg(any(usart_v3, usart_v4))] 364 #[cfg(any(usart_v3, usart_v4))]
383 unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { 365 fn check_rx_flags(&mut self) -> Result<bool, Error> {
384 let r = T::regs(); 366 let r = T::regs();
385 let sr = r.isr().read(); 367 let sr = r.isr().read();
386 if sr.pe() { 368 if sr.pe() {
@@ -410,22 +392,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
410 392
411 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 393 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
412 let r = T::regs(); 394 let r = T::regs();
413 unsafe { 395 if self.check_rx_flags()? {
414 if self.check_rx_flags()? { 396 Ok(unsafe { rdr(r).read_volatile() })
415 Ok(rdr(r).read_volatile()) 397 } else {
416 } else { 398 Err(nb::Error::WouldBlock)
417 Err(nb::Error::WouldBlock)
418 }
419 } 399 }
420 } 400 }
421 401
422 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 402 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
423 unsafe { 403 let r = T::regs();
424 let r = T::regs(); 404 for b in buffer {
425 for b in buffer { 405 while !self.check_rx_flags()? {}
426 while !self.check_rx_flags()? {} 406 unsafe { *b = rdr(r).read_volatile() }
427 *b = rdr(r).read_volatile();
428 }
429 } 407 }
430 Ok(()) 408 Ok(())
431 } 409 }
@@ -451,23 +429,20 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
451 let on_drop = OnDrop::new(move || { 429 let on_drop = OnDrop::new(move || {
452 // defmt::trace!("Clear all USART interrupts and DMA Read Request"); 430 // defmt::trace!("Clear all USART interrupts and DMA Read Request");
453 // clear all interrupts and DMA Rx Request 431 // clear all interrupts and DMA Rx Request
454 // SAFETY: only clears Rx related flags 432 r.cr1().modify(|w| {
455 unsafe { 433 // disable RXNE interrupt
456 r.cr1().modify(|w| { 434 w.set_rxneie(false);
457 // disable RXNE interrupt 435 // disable parity interrupt
458 w.set_rxneie(false); 436 w.set_peie(false);
459 // disable parity interrupt 437 // disable idle line interrupt
460 w.set_peie(false); 438 w.set_idleie(false);
461 // disable idle line interrupt 439 });
462 w.set_idleie(false); 440 r.cr3().modify(|w| {
463 }); 441 // disable Error Interrupt: (Frame error, Noise error, Overrun error)
464 r.cr3().modify(|w| { 442 w.set_eie(false);
465 // disable Error Interrupt: (Frame error, Noise error, Overrun error) 443 // disable DMA Rx Request
466 w.set_eie(false); 444 w.set_dmar(false);
467 // disable DMA Rx Request 445 });
468 w.set_dmar(false);
469 });
470 }
471 }); 446 });
472 447
473 let ch = &mut self.rx_dma; 448 let ch = &mut self.rx_dma;
@@ -480,78 +455,74 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
480 // future which will complete when DMA Read request completes 455 // future which will complete when DMA Read request completes
481 let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; 456 let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) };
482 457
483 // SAFETY: The only way we might have a problem is using split rx and tx 458 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
484 // here we only modify or read Rx related flags, interrupts and DMA channel 459 if !self.detect_previous_overrun {
485 unsafe { 460 let sr = sr(r).read();
486 // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer 461 // This read also clears the error and idle interrupt flags on v1.
487 if !self.detect_previous_overrun { 462 unsafe { rdr(r).read_volatile() };
488 let sr = sr(r).read(); 463 clear_interrupt_flags(r, sr);
489 // This read also clears the error and idle interrupt flags on v1. 464 }
490 rdr(r).read_volatile();
491 clear_interrupt_flags(r, sr);
492 }
493
494 r.cr1().modify(|w| {
495 // disable RXNE interrupt
496 w.set_rxneie(false);
497 // enable parity interrupt if not ParityNone
498 w.set_peie(w.pce());
499 });
500 465
501 r.cr3().modify(|w| { 466 r.cr1().modify(|w| {
502 // enable Error Interrupt: (Frame error, Noise error, Overrun error) 467 // disable RXNE interrupt
503 w.set_eie(true); 468 w.set_rxneie(false);
504 // enable DMA Rx Request 469 // enable parity interrupt if not ParityNone
505 w.set_dmar(true); 470 w.set_peie(w.pce());
506 }); 471 });
507 472
508 compiler_fence(Ordering::SeqCst); 473 r.cr3().modify(|w| {
474 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
475 w.set_eie(true);
476 // enable DMA Rx Request
477 w.set_dmar(true);
478 });
509 479
510 // In case of errors already pending when reception started, interrupts may have already been raised 480 compiler_fence(Ordering::SeqCst);
511 // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
512 // have been disabled in interrupt handler and DMA Rx Request has been disabled.
513 481
514 let cr3 = r.cr3().read(); 482 // In case of errors already pending when reception started, interrupts may have already been raised
483 // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
484 // have been disabled in interrupt handler and DMA Rx Request has been disabled.
515 485
516 if !cr3.dmar() { 486 let cr3 = r.cr3().read();
517 // something went wrong
518 // because the only way to get this flag cleared is to have an interrupt
519 487
520 // DMA will be stopped when transfer is dropped 488 if !cr3.dmar() {
489 // something went wrong
490 // because the only way to get this flag cleared is to have an interrupt
521 491
522 let sr = sr(r).read(); 492 // DMA will be stopped when transfer is dropped
523 // This read also clears the error and idle interrupt flags on v1.
524 rdr(r).read_volatile();
525 clear_interrupt_flags(r, sr);
526 493
527 if sr.pe() { 494 let sr = sr(r).read();
528 return Err(Error::Parity); 495 // This read also clears the error and idle interrupt flags on v1.
529 } 496 unsafe { rdr(r).read_volatile() };
530 if sr.fe() { 497 clear_interrupt_flags(r, sr);
531 return Err(Error::Framing);
532 }
533 if sr.ne() {
534 return Err(Error::Noise);
535 }
536 if sr.ore() {
537 return Err(Error::Overrun);
538 }
539 498
540 unreachable!(); 499 if sr.pe() {
500 return Err(Error::Parity);
541 } 501 }
542 502 if sr.fe() {
543 if enable_idle_line_detection { 503 return Err(Error::Framing);
544 // clear idle flag
545 let sr = sr(r).read();
546 // This read also clears the error and idle interrupt flags on v1.
547 rdr(r).read_volatile();
548 clear_interrupt_flags(r, sr);
549
550 // enable idle interrupt
551 r.cr1().modify(|w| {
552 w.set_idleie(true);
553 });
554 } 504 }
505 if sr.ne() {
506 return Err(Error::Noise);
507 }
508 if sr.ore() {
509 return Err(Error::Overrun);
510 }
511
512 unreachable!();
513 }
514
515 if enable_idle_line_detection {
516 // clear idle flag
517 let sr = sr(r).read();
518 // This read also clears the error and idle interrupt flags on v1.
519 unsafe { rdr(r).read_volatile() };
520 clear_interrupt_flags(r, sr);
521
522 // enable idle interrupt
523 r.cr1().modify(|w| {
524 w.set_idleie(true);
525 });
555 } 526 }
556 527
557 compiler_fence(Ordering::SeqCst); 528 compiler_fence(Ordering::SeqCst);
@@ -562,15 +533,11 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
562 533
563 s.rx_waker.register(cx.waker()); 534 s.rx_waker.register(cx.waker());
564 535
565 // SAFETY: read only and we only use Rx related flags 536 let sr = sr(r).read();
566 let sr = unsafe { sr(r).read() };
567 537
568 // SAFETY: only clears Rx related flags 538 // This read also clears the error and idle interrupt flags on v1.
569 unsafe { 539 unsafe { rdr(r).read_volatile() };
570 // This read also clears the error and idle interrupt flags on v1. 540 clear_interrupt_flags(r, sr);
571 rdr(r).read_volatile();
572 clear_interrupt_flags(r, sr);
573 }
574 541
575 compiler_fence(Ordering::SeqCst); 542 compiler_fence(Ordering::SeqCst);
576 543
@@ -650,7 +617,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
650 peri: impl Peripheral<P = T> + 'd, 617 peri: impl Peripheral<P = T> + 'd,
651 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 618 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
652 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 619 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
653 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 620 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
654 tx_dma: impl Peripheral<P = TxDma> + 'd, 621 tx_dma: impl Peripheral<P = TxDma> + 'd,
655 rx_dma: impl Peripheral<P = RxDma> + 'd, 622 rx_dma: impl Peripheral<P = RxDma> + 'd,
656 config: Config, 623 config: Config,
@@ -665,7 +632,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
665 peri: impl Peripheral<P = T> + 'd, 632 peri: impl Peripheral<P = T> + 'd,
666 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 633 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
667 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 634 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
668 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 635 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
669 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 636 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
670 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 637 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
671 tx_dma: impl Peripheral<P = TxDma> + 'd, 638 tx_dma: impl Peripheral<P = TxDma> + 'd,
@@ -677,14 +644,12 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
677 T::enable(); 644 T::enable();
678 T::reset(); 645 T::reset();
679 646
680 unsafe { 647 rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
681 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 648 cts.set_as_af(cts.af_num(), AFType::Input);
682 cts.set_as_af(cts.af_num(), AFType::Input); 649 T::regs().cr3().write(|w| {
683 T::regs().cr3().write(|w| { 650 w.set_rtse(true);
684 w.set_rtse(true); 651 w.set_ctse(true);
685 w.set_ctse(true); 652 });
686 });
687 }
688 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 653 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
689 } 654 }
690 655
@@ -693,7 +658,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
693 peri: impl Peripheral<P = T> + 'd, 658 peri: impl Peripheral<P = T> + 'd,
694 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 659 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
695 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 660 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
696 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 661 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
697 de: impl Peripheral<P = impl DePin<T>> + 'd, 662 de: impl Peripheral<P = impl DePin<T>> + 'd,
698 tx_dma: impl Peripheral<P = TxDma> + 'd, 663 tx_dma: impl Peripheral<P = TxDma> + 'd,
699 rx_dma: impl Peripheral<P = RxDma> + 'd, 664 rx_dma: impl Peripheral<P = RxDma> + 'd,
@@ -704,12 +669,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
704 T::enable(); 669 T::enable();
705 T::reset(); 670 T::reset();
706 671
707 unsafe { 672 de.set_as_af(de.af_num(), AFType::OutputPushPull);
708 de.set_as_af(de.af_num(), AFType::OutputPushPull); 673 T::regs().cr3().write(|w| {
709 T::regs().cr3().write(|w| { 674 w.set_dem(true);
710 w.set_dem(true); 675 });
711 });
712 }
713 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 676 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
714 } 677 }
715 678
@@ -725,10 +688,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
725 688
726 let r = T::regs(); 689 let r = T::regs();
727 690
728 unsafe { 691 rx.set_as_af(rx.af_num(), AFType::Input);
729 rx.set_as_af(rx.af_num(), AFType::Input); 692 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
730 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
731 }
732 693
733 configure(r, &config, T::frequency(), T::KIND, true, true); 694 configure(r, &config, T::frequency(), T::KIND, true, true);
734 695
@@ -847,11 +808,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
847 if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { 808 if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
848 over8 = true; 809 over8 = true;
849 let div = div as u32; 810 let div = div as u32;
850 unsafe { 811 r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
851 r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); 812 #[cfg(usart_v4)]
852 #[cfg(usart_v4)] 813 r.presc().write(|w| w.set_prescaler(_presc_val));
853 r.presc().write(|w| w.set_prescaler(_presc_val));
854 }
855 found = Some(div); 814 found = Some(div);
856 break; 815 break;
857 } 816 }
@@ -860,11 +819,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
860 819
861 if div < brr_max { 820 if div < brr_max {
862 let div = div as u32; 821 let div = div as u32;
863 unsafe { 822 r.brr().write_value(regs::Brr(div));
864 r.brr().write_value(regs::Brr(div)); 823 #[cfg(usart_v4)]
865 #[cfg(usart_v4)] 824 r.presc().write(|w| w.set_prescaler(_presc_val));
866 r.presc().write(|w| w.set_prescaler(_presc_val));
867 }
868 found = Some(div); 825 found = Some(div);
869 break; 826 break;
870 } 827 }
@@ -883,44 +840,42 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
883 pclk_freq.0 / div 840 pclk_freq.0 / div
884 ); 841 );
885 842
886 unsafe { 843 r.cr2().write(|w| {
887 r.cr2().write(|w| { 844 w.set_stop(match config.stop_bits {
888 w.set_stop(match config.stop_bits { 845 StopBits::STOP0P5 => vals::Stop::STOP0P5,
889 StopBits::STOP0P5 => vals::Stop::STOP0P5, 846 StopBits::STOP1 => vals::Stop::STOP1,
890 StopBits::STOP1 => vals::Stop::STOP1, 847 StopBits::STOP1P5 => vals::Stop::STOP1P5,
891 StopBits::STOP1P5 => vals::Stop::STOP1P5, 848 StopBits::STOP2 => vals::Stop::STOP2,
892 StopBits::STOP2 => vals::Stop::STOP2,
893 });
894 }); 849 });
895 r.cr1().write(|w| { 850 });
896 // enable uart 851 r.cr1().write(|w| {
897 w.set_ue(true); 852 // enable uart
898 // enable transceiver 853 w.set_ue(true);
899 w.set_te(enable_tx); 854 // enable transceiver
900 // enable receiver 855 w.set_te(enable_tx);
901 w.set_re(enable_rx); 856 // enable receiver
902 // configure word size 857 w.set_re(enable_rx);
903 w.set_m0(if config.parity != Parity::ParityNone { 858 // configure word size
904 vals::M0::BIT9 859 w.set_m0(if config.parity != Parity::ParityNone {
905 } else { 860 vals::M0::BIT9
906 vals::M0::BIT8 861 } else {
907 }); 862 vals::M0::BIT8
908 // configure parity
909 w.set_pce(config.parity != Parity::ParityNone);
910 w.set_ps(match config.parity {
911 Parity::ParityOdd => vals::Ps::ODD,
912 Parity::ParityEven => vals::Ps::EVEN,
913 _ => vals::Ps::EVEN,
914 });
915 #[cfg(not(usart_v1))]
916 w.set_over8(vals::Over8(over8 as _));
917 }); 863 });
918 864 // configure parity
919 #[cfg(not(usart_v1))] 865 w.set_pce(config.parity != Parity::ParityNone);
920 r.cr3().modify(|w| { 866 w.set_ps(match config.parity {
921 w.set_onebit(config.assume_noise_free); 867 Parity::ParityOdd => vals::Ps::ODD,
868 Parity::ParityEven => vals::Ps::EVEN,
869 _ => vals::Ps::EVEN,
922 }); 870 });
923 } 871 #[cfg(not(usart_v1))]
872 w.set_over8(vals::Over8::from_bits(over8 as _));
873 });
874
875 #[cfg(not(usart_v1))]
876 r.cr3().modify(|w| {
877 w.set_onebit(config.assume_noise_free);
878 });
924} 879}
925 880
926mod eh02 { 881mod eh02 {
@@ -1111,12 +1066,12 @@ use self::sealed::Kind;
1111 1066
1112#[cfg(any(usart_v1, usart_v2))] 1067#[cfg(any(usart_v1, usart_v2))]
1113fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { 1068fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
1114 r.dr().ptr() as _ 1069 r.dr().as_ptr() as _
1115} 1070}
1116 1071
1117#[cfg(any(usart_v1, usart_v2))] 1072#[cfg(any(usart_v1, usart_v2))]
1118fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { 1073fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
1119 r.dr().ptr() as _ 1074 r.dr().as_ptr() as _
1120} 1075}
1121 1076
1122#[cfg(any(usart_v1, usart_v2))] 1077#[cfg(any(usart_v1, usart_v2))]
@@ -1126,18 +1081,18 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::p
1126 1081
1127#[cfg(any(usart_v1, usart_v2))] 1082#[cfg(any(usart_v1, usart_v2))]
1128#[allow(unused)] 1083#[allow(unused)]
1129unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { 1084fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
1130 // On v1 the flags are cleared implicitly by reads and writes to DR. 1085 // On v1 the flags are cleared implicitly by reads and writes to DR.
1131} 1086}
1132 1087
1133#[cfg(any(usart_v3, usart_v4))] 1088#[cfg(any(usart_v3, usart_v4))]
1134fn tdr(r: Regs) -> *mut u8 { 1089fn tdr(r: Regs) -> *mut u8 {
1135 r.tdr().ptr() as _ 1090 r.tdr().as_ptr() as _
1136} 1091}
1137 1092
1138#[cfg(any(usart_v3, usart_v4))] 1093#[cfg(any(usart_v3, usart_v4))]
1139fn rdr(r: Regs) -> *mut u8 { 1094fn rdr(r: Regs) -> *mut u8 {
1140 r.rdr().ptr() as _ 1095 r.rdr().as_ptr() as _
1141} 1096}
1142 1097
1143#[cfg(any(usart_v3, usart_v4))] 1098#[cfg(any(usart_v3, usart_v4))]
@@ -1147,7 +1102,7 @@ fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
1147 1102
1148#[cfg(any(usart_v3, usart_v4))] 1103#[cfg(any(usart_v3, usart_v4))]
1149#[allow(unused)] 1104#[allow(unused)]
1150unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { 1105fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
1151 r.icr().write(|w| *w = regs::Icr(sr.0)); 1106 r.icr().write(|w| *w = regs::Icr(sr.0));
1152} 1107}
1153 1108
@@ -1179,7 +1134,7 @@ pub(crate) mod sealed {
1179 1134
1180 pub trait BasicInstance: crate::rcc::RccPeripheral { 1135 pub trait BasicInstance: crate::rcc::RccPeripheral {
1181 const KIND: Kind; 1136 const KIND: Kind;
1182 type Interrupt: crate::interrupt::Interrupt; 1137 type Interrupt: interrupt::typelevel::Interrupt;
1183 1138
1184 fn regs() -> Regs; 1139 fn regs() -> Regs;
1185 fn state() -> &'static State; 1140 fn state() -> &'static State;
@@ -1211,10 +1166,10 @@ macro_rules! impl_usart {
1211 ($inst:ident, $irq:ident, $kind:expr) => { 1166 ($inst:ident, $irq:ident, $kind:expr) => {
1212 impl sealed::BasicInstance for crate::peripherals::$inst { 1167 impl sealed::BasicInstance for crate::peripherals::$inst {
1213 const KIND: Kind = $kind; 1168 const KIND: Kind = $kind;
1214 type Interrupt = crate::interrupt::$irq; 1169 type Interrupt = crate::interrupt::typelevel::$irq;
1215 1170
1216 fn regs() -> Regs { 1171 fn regs() -> Regs {
1217 Regs(crate::pac::$inst.0) 1172 unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }
1218 } 1173 }
1219 1174
1220 fn state() -> &'static crate::usart::sealed::State { 1175 fn state() -> &'static crate::usart::sealed::State {
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 511b71c7f..c74d7e092 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -59,23 +59,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
59 59
60 let r = T::regs(); 60 let r = T::regs();
61 // clear all interrupts and DMA Rx Request 61 // clear all interrupts and DMA Rx Request
62 // SAFETY: only clears Rx related flags 62 r.cr1().modify(|w| {
63 unsafe { 63 // disable RXNE interrupt
64 r.cr1().modify(|w| { 64 w.set_rxneie(false);
65 // disable RXNE interrupt 65 // enable parity interrupt if not ParityNone
66 w.set_rxneie(false); 66 w.set_peie(w.pce());
67 // enable parity interrupt if not ParityNone 67 // enable idle line interrupt
68 w.set_peie(w.pce()); 68 w.set_idleie(true);
69 // enable idle line interrupt 69 });
70 w.set_idleie(true); 70 r.cr3().modify(|w| {
71 }); 71 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
72 r.cr3().modify(|w| { 72 w.set_eie(true);
73 // enable Error Interrupt: (Frame error, Noise error, Overrun error) 73 // enable DMA Rx Request
74 w.set_eie(true); 74 w.set_dmar(true);
75 // enable DMA Rx Request 75 });
76 w.set_dmar(true);
77 });
78 }
79 } 76 }
80 77
81 /// Stop uart background receive 78 /// Stop uart background receive
@@ -84,23 +81,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
84 81
85 let r = T::regs(); 82 let r = T::regs();
86 // clear all interrupts and DMA Rx Request 83 // clear all interrupts and DMA Rx Request
87 // SAFETY: only clears Rx related flags 84 r.cr1().modify(|w| {
88 unsafe { 85 // disable RXNE interrupt
89 r.cr1().modify(|w| { 86 w.set_rxneie(false);
90 // disable RXNE interrupt 87 // disable parity interrupt
91 w.set_rxneie(false); 88 w.set_peie(false);
92 // disable parity interrupt 89 // disable idle line interrupt
93 w.set_peie(false); 90 w.set_idleie(false);
94 // disable idle line interrupt 91 });
95 w.set_idleie(false); 92 r.cr3().modify(|w| {
96 }); 93 // disable Error Interrupt: (Frame error, Noise error, Overrun error)
97 r.cr3().modify(|w| { 94 w.set_eie(false);
98 // disable Error Interrupt: (Frame error, Noise error, Overrun error) 95 // disable DMA Rx Request
99 w.set_eie(false); 96 w.set_dmar(false);
100 // disable DMA Rx Request 97 });
101 w.set_dmar(false);
102 });
103 }
104 98
105 compiler_fence(Ordering::SeqCst); 99 compiler_fence(Ordering::SeqCst);
106 } 100 }
@@ -117,8 +111,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
117 let r = T::regs(); 111 let r = T::regs();
118 112
119 // Start background receive if it was not already started 113 // Start background receive if it was not already started
120 // SAFETY: read only 114 match r.cr3().read().dmar() {
121 match unsafe { r.cr3().read().dmar() } {
122 false => self.start()?, 115 false => self.start()?,
123 _ => {} 116 _ => {}
124 }; 117 };
@@ -213,19 +206,17 @@ fn check_for_errors(s: Sr) -> Result<(), Error> {
213 206
214/// Clear IDLE and return the Sr register 207/// Clear IDLE and return the Sr register
215fn clear_idle_flag(r: Regs) -> Sr { 208fn clear_idle_flag(r: Regs) -> Sr {
216 unsafe { 209 // SAFETY: read only and we only use Rx related flags
217 // SAFETY: read only and we only use Rx related flags
218 210
219 let sr = sr(r).read(); 211 let sr = sr(r).read();
220 212
221 // This read also clears the error and idle interrupt flags on v1. 213 // This read also clears the error and idle interrupt flags on v1.
222 rdr(r).read_volatile(); 214 unsafe { rdr(r).read_volatile() };
223 clear_interrupt_flags(r, sr); 215 clear_interrupt_flags(r, sr);
224 216
225 r.cr1().modify(|w| w.set_idleie(true)); 217 r.cr1().modify(|w| w.set_idleie(true));
226 218
227 sr 219 sr
228 }
229} 220}
230 221
231#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 222#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index fbd1fa823..bee287fe6 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -1,4 +1,4 @@
1use crate::interrupt::Interrupt; 1use crate::interrupt;
2use crate::rcc::RccPeripheral; 2use crate::rcc::RccPeripheral;
3 3
4#[cfg(feature = "nightly")] 4#[cfg(feature = "nightly")]
@@ -13,7 +13,7 @@ pub(crate) mod sealed {
13} 13}
14 14
15pub trait Instance: sealed::Instance + RccPeripheral + 'static { 15pub trait Instance: sealed::Instance + RccPeripheral + 'static {
16 type Interrupt: Interrupt; 16 type Interrupt: interrupt::typelevel::Interrupt;
17} 17}
18 18
19// Internal PHY pins 19// Internal PHY pins
@@ -29,7 +29,7 @@ foreach_interrupt!(
29 } 29 }
30 30
31 impl Instance for crate::peripherals::$inst { 31 impl Instance for crate::peripherals::$inst {
32 type Interrupt = crate::interrupt::$irq; 32 type Interrupt = crate::interrupt::typelevel::$irq;
33 } 33 }
34 }; 34 };
35); 35);
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 134107978..ecdd1d0b8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -14,7 +14,7 @@ use embassy_usb_driver::{
14 14
15use super::{DmPin, DpPin, Instance}; 15use super::{DmPin, DpPin, Instance};
16use crate::gpio::sealed::AFType; 16use crate::gpio::sealed::AFType;
17use crate::interrupt::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::usb::regs; 18use crate::pac::usb::regs;
19use crate::pac::usb::vals::{EpType, Stat}; 19use crate::pac::usb::vals::{EpType, Stat};
20use crate::pac::USBRAM; 20use crate::pac::USBRAM;
@@ -26,84 +26,82 @@ pub struct InterruptHandler<T: Instance> {
26 _phantom: PhantomData<T>, 26 _phantom: PhantomData<T>,
27} 27}
28 28
29impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 29impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
30 unsafe fn on_interrupt() { 30 unsafe fn on_interrupt() {
31 unsafe { 31 let regs = T::regs();
32 let regs = T::regs(); 32 //let x = regs.istr().read().0;
33 //let x = regs.istr().read().0; 33 //trace!("USB IRQ: {:08x}", x);
34 //trace!("USB IRQ: {:08x}", x);
35 34
36 let istr = regs.istr().read(); 35 let istr = regs.istr().read();
37 36
38 if istr.susp() { 37 if istr.susp() {
39 //trace!("USB IRQ: susp"); 38 //trace!("USB IRQ: susp");
40 IRQ_SUSPEND.store(true, Ordering::Relaxed); 39 IRQ_SUSPEND.store(true, Ordering::Relaxed);
41 regs.cntr().modify(|w| { 40 regs.cntr().modify(|w| {
42 w.set_fsusp(true); 41 w.set_fsusp(true);
43 w.set_lpmode(true); 42 w.set_lpmode(true);
44 }); 43 });
45 44
46 // Write 0 to clear. 45 // Write 0 to clear.
47 let mut clear = regs::Istr(!0); 46 let mut clear = regs::Istr(!0);
48 clear.set_susp(false); 47 clear.set_susp(false);
49 regs.istr().write_value(clear); 48 regs.istr().write_value(clear);
50 49
51 // Wake main thread. 50 // Wake main thread.
52 BUS_WAKER.wake(); 51 BUS_WAKER.wake();
53 } 52 }
54 53
55 if istr.wkup() { 54 if istr.wkup() {
56 //trace!("USB IRQ: wkup"); 55 //trace!("USB IRQ: wkup");
57 IRQ_RESUME.store(true, Ordering::Relaxed); 56 IRQ_RESUME.store(true, Ordering::Relaxed);
58 regs.cntr().modify(|w| { 57 regs.cntr().modify(|w| {
59 w.set_fsusp(false); 58 w.set_fsusp(false);
60 w.set_lpmode(false); 59 w.set_lpmode(false);
61 }); 60 });
62 61
63 // Write 0 to clear. 62 // Write 0 to clear.
64 let mut clear = regs::Istr(!0); 63 let mut clear = regs::Istr(!0);
65 clear.set_wkup(false); 64 clear.set_wkup(false);
66 regs.istr().write_value(clear); 65 regs.istr().write_value(clear);
67 66
68 // Wake main thread. 67 // Wake main thread.
69 BUS_WAKER.wake(); 68 BUS_WAKER.wake();
70 } 69 }
71 70
72 if istr.reset() { 71 if istr.reset() {
73 //trace!("USB IRQ: reset"); 72 //trace!("USB IRQ: reset");
74 IRQ_RESET.store(true, Ordering::Relaxed); 73 IRQ_RESET.store(true, Ordering::Relaxed);
75 74
76 // Write 0 to clear. 75 // Write 0 to clear.
77 let mut clear = regs::Istr(!0); 76 let mut clear = regs::Istr(!0);
78 clear.set_reset(false); 77 clear.set_reset(false);
79 regs.istr().write_value(clear); 78 regs.istr().write_value(clear);
80 79
81 // Wake main thread. 80 // Wake main thread.
82 BUS_WAKER.wake(); 81 BUS_WAKER.wake();
83 } 82 }
84 83
85 if istr.ctr() { 84 if istr.ctr() {
86 let index = istr.ep_id() as usize; 85 let index = istr.ep_id() as usize;
87 let mut epr = regs.epr(index).read(); 86 let mut epr = regs.epr(index).read();
88 if epr.ctr_rx() { 87 if epr.ctr_rx() {
89 if index == 0 && epr.setup() { 88 if index == 0 && epr.setup() {
90 EP0_SETUP.store(true, Ordering::Relaxed); 89 EP0_SETUP.store(true, Ordering::Relaxed);
91 }
92 //trace!("EP {} RX, setup={}", index, epr.setup());
93 EP_OUT_WAKERS[index].wake();
94 } 90 }
95 if epr.ctr_tx() { 91 //trace!("EP {} RX, setup={}", index, epr.setup());
96 //trace!("EP {} TX", index); 92 EP_OUT_WAKERS[index].wake();
97 EP_IN_WAKERS[index].wake(); 93 }
98 } 94 if epr.ctr_tx() {
99 epr.set_dtog_rx(false); 95 //trace!("EP {} TX", index);
100 epr.set_dtog_tx(false); 96 EP_IN_WAKERS[index].wake();
101 epr.set_stat_rx(Stat(0));
102 epr.set_stat_tx(Stat(0));
103 epr.set_ctr_rx(!epr.ctr_rx());
104 epr.set_ctr_tx(!epr.ctr_tx());
105 regs.epr(index).write_value(epr);
106 } 97 }
98 epr.set_dtog_rx(false);
99 epr.set_dtog_tx(false);
100 epr.set_stat_rx(Stat::from_bits(0));
101 epr.set_stat_tx(Stat::from_bits(0));
102 epr.set_ctr_rx(!epr.ctr_rx());
103 epr.set_ctr_tx(!epr.ctr_tx());
104 regs.epr(index).write_value(epr);
107 } 105 }
108 } 106 }
109} 107}
@@ -145,8 +143,8 @@ fn invariant(mut r: regs::Epr) -> regs::Epr {
145 r.set_ctr_tx(true); // don't clear 143 r.set_ctr_tx(true); // don't clear
146 r.set_dtog_rx(false); // don't toggle 144 r.set_dtog_rx(false); // don't toggle
147 r.set_dtog_tx(false); // don't toggle 145 r.set_dtog_tx(false); // don't toggle
148 r.set_stat_rx(Stat(0)); 146 r.set_stat_rx(Stat::from_bits(0));
149 r.set_stat_tx(Stat(0)); 147 r.set_stat_tx(Stat::from_bits(0));
150 r 148 r
151} 149}
152 150
@@ -168,20 +166,20 @@ fn calc_out_len(len: u16) -> (u16, u16) {
168mod btable { 166mod btable {
169 use super::*; 167 use super::*;
170 168
171 pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) { 169 pub(super) fn write_in<T: Instance>(index: usize, addr: u16) {
172 USBRAM.mem(index * 4 + 0).write_value(addr); 170 USBRAM.mem(index * 4 + 0).write_value(addr);
173 } 171 }
174 172
175 pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { 173 pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
176 USBRAM.mem(index * 4 + 1).write_value(len); 174 USBRAM.mem(index * 4 + 1).write_value(len);
177 } 175 }
178 176
179 pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 177 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
180 USBRAM.mem(index * 4 + 2).write_value(addr); 178 USBRAM.mem(index * 4 + 2).write_value(addr);
181 USBRAM.mem(index * 4 + 3).write_value(max_len_bits); 179 USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
182 } 180 }
183 181
184 pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { 182 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
185 USBRAM.mem(index * 4 + 3).read() 183 USBRAM.mem(index * 4 + 3).read()
186 } 184 }
187} 185}
@@ -189,19 +187,19 @@ mod btable {
189mod btable { 187mod btable {
190 use super::*; 188 use super::*;
191 189
192 pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {} 190 pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {}
193 191
194 pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { 192 pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
195 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); 193 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
196 } 194 }
197 195
198 pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 196 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
199 USBRAM 197 USBRAM
200 .mem(index * 2 + 1) 198 .mem(index * 2 + 1)
201 .write_value((addr as u32) | ((max_len_bits as u32) << 16)); 199 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
202 } 200 }
203 201
204 pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { 202 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
205 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 203 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16
206 } 204 }
207} 205}
@@ -216,7 +214,7 @@ impl<T: Instance> EndpointBuffer<T> {
216 fn read(&mut self, buf: &mut [u8]) { 214 fn read(&mut self, buf: &mut [u8]) {
217 assert!(buf.len() <= self.len as usize); 215 assert!(buf.len() <= self.len as usize);
218 for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { 216 for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
219 let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() }; 217 let val = USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read();
220 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); 218 let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
221 buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); 219 buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]);
222 } 220 }
@@ -233,7 +231,7 @@ impl<T: Instance> EndpointBuffer<T> {
233 let val = u16::from_le_bytes(val); 231 let val = u16::from_le_bytes(val);
234 #[cfg(usbram_32_2048)] 232 #[cfg(usbram_32_2048)]
235 let val = u32::from_le_bytes(val); 233 let val = u32::from_le_bytes(val);
236 unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) }; 234 USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val);
237 } 235 }
238 } 236 }
239} 237}
@@ -255,7 +253,7 @@ pub struct Driver<'d, T: Instance> {
255impl<'d, T: Instance> Driver<'d, T> { 253impl<'d, T: Instance> Driver<'d, T> {
256 pub fn new( 254 pub fn new(
257 _usb: impl Peripheral<P = T> + 'd, 255 _usb: impl Peripheral<P = T> + 'd,
258 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 256 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
259 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 257 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
260 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 258 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
261 ) -> Self { 259 ) -> Self {
@@ -266,36 +264,32 @@ impl<'d, T: Instance> Driver<'d, T> {
266 let regs = T::regs(); 264 let regs = T::regs();
267 265
268 #[cfg(stm32l5)] 266 #[cfg(stm32l5)]
269 unsafe { 267 {
270 crate::peripherals::PWR::enable(); 268 crate::peripherals::PWR::enable();
271 crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); 269 crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
272 } 270 }
273 271
274 #[cfg(pwr_h5)] 272 #[cfg(pwr_h5)]
275 unsafe { 273 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));
276 crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true))
277 }
278 274
279 unsafe { 275 <T as RccPeripheral>::enable();
280 <T as RccPeripheral>::enable(); 276 <T as RccPeripheral>::reset();
281 <T as RccPeripheral>::reset();
282 277
283 regs.cntr().write(|w| { 278 regs.cntr().write(|w| {
284 w.set_pdwn(false); 279 w.set_pdwn(false);
285 w.set_fres(true); 280 w.set_fres(true);
286 }); 281 });
287 282
288 #[cfg(time)] 283 #[cfg(time)]
289 embassy_time::block_for(embassy_time::Duration::from_millis(100)); 284 embassy_time::block_for(embassy_time::Duration::from_millis(100));
290 #[cfg(not(time))] 285 #[cfg(not(time))]
291 cortex_m::asm::delay(crate::rcc::get_freqs().sys.0 / 10); 286 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10);
292 287
293 #[cfg(not(usb_v4))] 288 #[cfg(not(usb_v4))]
294 regs.btable().write(|w| w.set_btable(0)); 289 regs.btable().write(|w| w.set_btable(0));
295 290
296 dp.set_as_af(dp.af_num(), AFType::OutputPushPull); 291 dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
297 dm.set_as_af(dm.af_num(), AFType::OutputPushPull); 292 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
298 }
299 293
300 // Initialize the bus so that it signals that power is available 294 // Initialize the bus so that it signals that power is available
301 BUS_WAKER.wake(); 295 BUS_WAKER.wake();
@@ -363,7 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
363 let addr = self.alloc_ep_mem(len); 357 let addr = self.alloc_ep_mem(len);
364 358
365 trace!(" len_bits = {:04x}", len_bits); 359 trace!(" len_bits = {:04x}", len_bits);
366 unsafe { btable::write_out::<T>(index, addr, len_bits) } 360 btable::write_out::<T>(index, addr, len_bits);
367 361
368 EndpointBuffer { 362 EndpointBuffer {
369 addr, 363 addr,
@@ -379,7 +373,7 @@ impl<'d, T: Instance> Driver<'d, T> {
379 let addr = self.alloc_ep_mem(len); 373 let addr = self.alloc_ep_mem(len);
380 374
381 // ep_in_len is written when actually TXing packets. 375 // ep_in_len is written when actually TXing packets.
382 unsafe { btable::write_in::<T>(index, addr) } 376 btable::write_in::<T>(index, addr);
383 377
384 EndpointBuffer { 378 EndpointBuffer {
385 addr, 379 addr,
@@ -440,19 +434,17 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
440 434
441 let regs = T::regs(); 435 let regs = T::regs();
442 436
443 unsafe { 437 regs.cntr().write(|w| {
444 regs.cntr().write(|w| { 438 w.set_pdwn(false);
445 w.set_pdwn(false); 439 w.set_fres(false);
446 w.set_fres(false); 440 w.set_resetm(true);
447 w.set_resetm(true); 441 w.set_suspm(true);
448 w.set_suspm(true); 442 w.set_wkupm(true);
449 w.set_wkupm(true); 443 w.set_ctrm(true);
450 w.set_ctrm(true); 444 });
451 });
452 445
453 #[cfg(any(usb_v3, usb_v4))] 446 #[cfg(any(usb_v3, usb_v4))]
454 regs.bcdr().write(|w| w.set_dppu(true)) 447 regs.bcdr().write(|w| w.set_dppu(true));
455 }
456 448
457 trace!("enabled"); 449 trace!("enabled");
458 450
@@ -485,59 +477,60 @@ pub struct Bus<'d, T: Instance> {
485 477
486impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 478impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
487 async fn poll(&mut self) -> Event { 479 async fn poll(&mut self) -> Event {
488 poll_fn(move |cx| unsafe { 480 poll_fn(move |cx| {
489 BUS_WAKER.register(cx.waker()); 481 BUS_WAKER.register(cx.waker());
490 482
491 if self.inited { 483 // TODO: implement VBUS detection.
492 let regs = T::regs(); 484 if !self.inited {
485 self.inited = true;
486 return Poll::Ready(Event::PowerDetected);
487 }
493 488
494 if IRQ_RESUME.load(Ordering::Acquire) { 489 let regs = T::regs();
495 IRQ_RESUME.store(false, Ordering::Relaxed);
496 return Poll::Ready(Event::Resume);
497 }
498 490
499 if IRQ_RESET.load(Ordering::Acquire) { 491 if IRQ_RESUME.load(Ordering::Acquire) {
500 IRQ_RESET.store(false, Ordering::Relaxed); 492 IRQ_RESUME.store(false, Ordering::Relaxed);
501 493 return Poll::Ready(Event::Resume);
502 trace!("RESET"); 494 }
503 regs.daddr().write(|w| {
504 w.set_ef(true);
505 w.set_add(0);
506 });
507
508 regs.epr(0).write(|w| {
509 w.set_ep_type(EpType::CONTROL);
510 w.set_stat_rx(Stat::NAK);
511 w.set_stat_tx(Stat::NAK);
512 });
513
514 for i in 1..EP_COUNT {
515 regs.epr(i).write(|w| {
516 w.set_ea(i as _);
517 w.set_ep_type(self.ep_types[i - 1]);
518 })
519 }
520 495
521 for w in &EP_IN_WAKERS { 496 if IRQ_RESET.load(Ordering::Acquire) {
522 w.wake() 497 IRQ_RESET.store(false, Ordering::Relaxed);
523 } 498
524 for w in &EP_OUT_WAKERS { 499 trace!("RESET");
525 w.wake() 500 regs.daddr().write(|w| {
526 } 501 w.set_ef(true);
502 w.set_add(0);
503 });
527 504
528 return Poll::Ready(Event::Reset); 505 regs.epr(0).write(|w| {
506 w.set_ep_type(EpType::CONTROL);
507 w.set_stat_rx(Stat::NAK);
508 w.set_stat_tx(Stat::NAK);
509 });
510
511 for i in 1..EP_COUNT {
512 regs.epr(i).write(|w| {
513 w.set_ea(i as _);
514 w.set_ep_type(self.ep_types[i - 1]);
515 })
529 } 516 }
530 517
531 if IRQ_SUSPEND.load(Ordering::Acquire) { 518 for w in &EP_IN_WAKERS {
532 IRQ_SUSPEND.store(false, Ordering::Relaxed); 519 w.wake()
533 return Poll::Ready(Event::Suspend); 520 }
521 for w in &EP_OUT_WAKERS {
522 w.wake()
534 } 523 }
535 524
536 Poll::Pending 525 return Poll::Ready(Event::Reset);
537 } else {
538 self.inited = true;
539 return Poll::Ready(Event::PowerDetected);
540 } 526 }
527
528 if IRQ_SUSPEND.load(Ordering::Acquire) {
529 IRQ_SUSPEND.store(false, Ordering::Relaxed);
530 return Poll::Ready(Event::Suspend);
531 }
532
533 Poll::Pending
541 }) 534 })
542 .await 535 .await
543 } 536 }
@@ -548,7 +541,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
548 match ep_addr.direction() { 541 match ep_addr.direction() {
549 Direction::In => { 542 Direction::In => {
550 loop { 543 loop {
551 let r = unsafe { reg.read() }; 544 let r = reg.read();
552 match r.stat_tx() { 545 match r.stat_tx() {
553 Stat::DISABLED => break, // if disabled, stall does nothing. 546 Stat::DISABLED => break, // if disabled, stall does nothing.
554 Stat::STALL => break, // done! 547 Stat::STALL => break, // done!
@@ -558,8 +551,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
558 true => Stat::STALL, 551 true => Stat::STALL,
559 }; 552 };
560 let mut w = invariant(r); 553 let mut w = invariant(r);
561 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); 554 w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
562 unsafe { reg.write_value(w) }; 555 reg.write_value(w);
563 } 556 }
564 } 557 }
565 } 558 }
@@ -567,7 +560,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
567 } 560 }
568 Direction::Out => { 561 Direction::Out => {
569 loop { 562 loop {
570 let r = unsafe { reg.read() }; 563 let r = reg.read();
571 match r.stat_rx() { 564 match r.stat_rx() {
572 Stat::DISABLED => break, // if disabled, stall does nothing. 565 Stat::DISABLED => break, // if disabled, stall does nothing.
573 Stat::STALL => break, // done! 566 Stat::STALL => break, // done!
@@ -577,8 +570,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
577 true => Stat::STALL, 570 true => Stat::STALL,
578 }; 571 };
579 let mut w = invariant(r); 572 let mut w = invariant(r);
580 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); 573 w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
581 unsafe { reg.write_value(w) }; 574 reg.write_value(w);
582 } 575 }
583 } 576 }
584 } 577 }
@@ -589,7 +582,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
589 582
590 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { 583 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
591 let regs = T::regs(); 584 let regs = T::regs();
592 let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; 585 let epr = regs.epr(ep_addr.index() as _).read();
593 match ep_addr.direction() { 586 match ep_addr.direction() {
594 Direction::In => epr.stat_tx() == Stat::STALL, 587 Direction::In => epr.stat_tx() == Stat::STALL,
595 Direction::Out => epr.stat_rx() == Stat::STALL, 588 Direction::Out => epr.stat_rx() == Stat::STALL,
@@ -600,7 +593,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
600 trace!("set_enabled {:x} {}", ep_addr, enabled); 593 trace!("set_enabled {:x} {}", ep_addr, enabled);
601 // This can race, so do a retry loop. 594 // This can race, so do a retry loop.
602 let reg = T::regs().epr(ep_addr.index() as _); 595 let reg = T::regs().epr(ep_addr.index() as _);
603 trace!("EPR before: {:04x}", unsafe { reg.read() }.0); 596 trace!("EPR before: {:04x}", reg.read().0);
604 match ep_addr.direction() { 597 match ep_addr.direction() {
605 Direction::In => { 598 Direction::In => {
606 loop { 599 loop {
@@ -608,13 +601,13 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
608 false => Stat::DISABLED, 601 false => Stat::DISABLED,
609 true => Stat::NAK, 602 true => Stat::NAK,
610 }; 603 };
611 let r = unsafe { reg.read() }; 604 let r = reg.read();
612 if r.stat_tx() == want_stat { 605 if r.stat_tx() == want_stat {
613 break; 606 break;
614 } 607 }
615 let mut w = invariant(r); 608 let mut w = invariant(r);
616 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); 609 w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
617 unsafe { reg.write_value(w) }; 610 reg.write_value(w);
618 } 611 }
619 EP_IN_WAKERS[ep_addr.index()].wake(); 612 EP_IN_WAKERS[ep_addr.index()].wake();
620 } 613 }
@@ -624,18 +617,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
624 false => Stat::DISABLED, 617 false => Stat::DISABLED,
625 true => Stat::VALID, 618 true => Stat::VALID,
626 }; 619 };
627 let r = unsafe { reg.read() }; 620 let r = reg.read();
628 if r.stat_rx() == want_stat { 621 if r.stat_rx() == want_stat {
629 break; 622 break;
630 } 623 }
631 let mut w = invariant(r); 624 let mut w = invariant(r);
632 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); 625 w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
633 unsafe { reg.write_value(w) }; 626 reg.write_value(w);
634 } 627 }
635 EP_OUT_WAKERS[ep_addr.index()].wake(); 628 EP_OUT_WAKERS[ep_addr.index()].wake();
636 } 629 }
637 } 630 }
638 trace!("EPR after: {:04x}", unsafe { reg.read() }.0); 631 trace!("EPR after: {:04x}", reg.read().0);
639 } 632 }
640 633
641 async fn enable(&mut self) {} 634 async fn enable(&mut self) {}
@@ -685,12 +678,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
685 fn write_data(&mut self, buf: &[u8]) { 678 fn write_data(&mut self, buf: &[u8]) {
686 let index = self.info.addr.index(); 679 let index = self.info.addr.index();
687 self.buf.write(buf); 680 self.buf.write(buf);
688 unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) } 681 btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _);
689 } 682 }
690 683
691 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 684 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
692 let index = self.info.addr.index(); 685 let index = self.info.addr.index();
693 let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF; 686 let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF;
694 trace!("READ DONE, rx_len = {}", rx_len); 687 trace!("READ DONE, rx_len = {}", rx_len);
695 if rx_len > buf.len() { 688 if rx_len > buf.len() {
696 return Err(EndpointError::BufferOverflow); 689 return Err(EndpointError::BufferOverflow);
@@ -711,7 +704,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
711 poll_fn(|cx| { 704 poll_fn(|cx| {
712 EP_OUT_WAKERS[index].register(cx.waker()); 705 EP_OUT_WAKERS[index].register(cx.waker());
713 let regs = T::regs(); 706 let regs = T::regs();
714 if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED { 707 if regs.epr(index).read().stat_tx() == Stat::DISABLED {
715 Poll::Pending 708 Poll::Pending
716 } else { 709 } else {
717 Poll::Ready(()) 710 Poll::Ready(())
@@ -733,7 +726,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
733 poll_fn(|cx| { 726 poll_fn(|cx| {
734 EP_OUT_WAKERS[index].register(cx.waker()); 727 EP_OUT_WAKERS[index].register(cx.waker());
735 let regs = T::regs(); 728 let regs = T::regs();
736 if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED { 729 if regs.epr(index).read().stat_rx() == Stat::DISABLED {
737 Poll::Pending 730 Poll::Pending
738 } else { 731 } else {
739 Poll::Ready(()) 732 Poll::Ready(())
@@ -751,7 +744,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
751 let stat = poll_fn(|cx| { 744 let stat = poll_fn(|cx| {
752 EP_OUT_WAKERS[index].register(cx.waker()); 745 EP_OUT_WAKERS[index].register(cx.waker());
753 let regs = T::regs(); 746 let regs = T::regs();
754 let stat = unsafe { regs.epr(index).read() }.stat_rx(); 747 let stat = regs.epr(index).read().stat_rx();
755 if matches!(stat, Stat::NAK | Stat::DISABLED) { 748 if matches!(stat, Stat::NAK | Stat::DISABLED) {
756 Poll::Ready(stat) 749 Poll::Ready(stat)
757 } else { 750 } else {
@@ -767,16 +760,14 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
767 let rx_len = self.read_data(buf)?; 760 let rx_len = self.read_data(buf)?;
768 761
769 let regs = T::regs(); 762 let regs = T::regs();
770 unsafe { 763 regs.epr(index).write(|w| {
771 regs.epr(index).write(|w| { 764 w.set_ep_type(convert_type(self.info.ep_type));
772 w.set_ep_type(convert_type(self.info.ep_type)); 765 w.set_ea(self.info.addr.index() as _);
773 w.set_ea(self.info.addr.index() as _); 766 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
774 w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 767 w.set_stat_tx(Stat::from_bits(0));
775 w.set_stat_tx(Stat(0)); 768 w.set_ctr_rx(true); // don't clear
776 w.set_ctr_rx(true); // don't clear 769 w.set_ctr_tx(true); // don't clear
777 w.set_ctr_tx(true); // don't clear 770 });
778 })
779 };
780 trace!("READ OK, rx_len = {}", rx_len); 771 trace!("READ OK, rx_len = {}", rx_len);
781 772
782 Ok(rx_len) 773 Ok(rx_len)
@@ -795,7 +786,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
795 let stat = poll_fn(|cx| { 786 let stat = poll_fn(|cx| {
796 EP_IN_WAKERS[index].register(cx.waker()); 787 EP_IN_WAKERS[index].register(cx.waker());
797 let regs = T::regs(); 788 let regs = T::regs();
798 let stat = unsafe { regs.epr(index).read() }.stat_tx(); 789 let stat = regs.epr(index).read().stat_tx();
799 if matches!(stat, Stat::NAK | Stat::DISABLED) { 790 if matches!(stat, Stat::NAK | Stat::DISABLED) {
800 Poll::Ready(stat) 791 Poll::Ready(stat)
801 } else { 792 } else {
@@ -811,16 +802,14 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
811 self.write_data(buf); 802 self.write_data(buf);
812 803
813 let regs = T::regs(); 804 let regs = T::regs();
814 unsafe { 805 regs.epr(index).write(|w| {
815 regs.epr(index).write(|w| { 806 w.set_ep_type(convert_type(self.info.ep_type));
816 w.set_ep_type(convert_type(self.info.ep_type)); 807 w.set_ea(self.info.addr.index() as _);
817 w.set_ea(self.info.addr.index() as _); 808 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
818 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 809 w.set_stat_rx(Stat::from_bits(0));
819 w.set_stat_rx(Stat(0)); 810 w.set_ctr_rx(true); // don't clear
820 w.set_ctr_rx(true); // don't clear 811 w.set_ctr_tx(true); // don't clear
821 w.set_ctr_tx(true); // don't clear 812 });
822 })
823 };
824 813
825 trace!("WRITE OK"); 814 trace!("WRITE OK");
826 815
@@ -880,31 +869,29 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
880 let mut stat_tx = 0; 869 let mut stat_tx = 0;
881 if first { 870 if first {
882 // change NAK -> VALID 871 // change NAK -> VALID
883 stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0; 872 stat_rx ^= Stat::NAK.to_bits() ^ Stat::VALID.to_bits();
884 stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0; 873 stat_tx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
885 } 874 }
886 if last { 875 if last {
887 // change STALL -> VALID 876 // change STALL -> VALID
888 stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0; 877 stat_tx ^= Stat::STALL.to_bits() ^ Stat::NAK.to_bits();
889 } 878 }
890 // Note: if this is the first AND last transfer, the above effectively 879 // Note: if this is the first AND last transfer, the above effectively
891 // changes stat_tx like NAK -> NAK, so noop. 880 // changes stat_tx like NAK -> NAK, so noop.
892 unsafe { 881 regs.epr(0).write(|w| {
893 regs.epr(0).write(|w| { 882 w.set_ep_type(EpType::CONTROL);
894 w.set_ep_type(EpType::CONTROL); 883 w.set_stat_rx(Stat::from_bits(stat_rx));
895 w.set_stat_rx(Stat(stat_rx)); 884 w.set_stat_tx(Stat::from_bits(stat_tx));
896 w.set_stat_tx(Stat(stat_tx)); 885 w.set_ctr_rx(true); // don't clear
897 w.set_ctr_rx(true); // don't clear 886 w.set_ctr_tx(true); // don't clear
898 w.set_ctr_tx(true); // don't clear 887 });
899 })
900 }
901 } 888 }
902 889
903 trace!("data_out WAITING, buf.len() = {}", buf.len()); 890 trace!("data_out WAITING, buf.len() = {}", buf.len());
904 poll_fn(|cx| { 891 poll_fn(|cx| {
905 EP_OUT_WAKERS[0].register(cx.waker()); 892 EP_OUT_WAKERS[0].register(cx.waker());
906 let regs = T::regs(); 893 let regs = T::regs();
907 if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK { 894 if regs.epr(0).read().stat_rx() == Stat::NAK {
908 Poll::Ready(()) 895 Poll::Ready(())
909 } else { 896 } else {
910 Poll::Pending 897 Poll::Pending
@@ -919,19 +906,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
919 906
920 let rx_len = self.ep_out.read_data(buf)?; 907 let rx_len = self.ep_out.read_data(buf)?;
921 908
922 unsafe { 909 regs.epr(0).write(|w| {
923 regs.epr(0).write(|w| { 910 w.set_ep_type(EpType::CONTROL);
924 w.set_ep_type(EpType::CONTROL); 911 w.set_stat_rx(Stat::from_bits(match last {
925 w.set_stat_rx(Stat(match last { 912 // If last, set STAT_RX=STALL.
926 // If last, set STAT_RX=STALL. 913 true => Stat::NAK.to_bits() ^ Stat::STALL.to_bits(),
927 true => Stat::NAK.0 ^ Stat::STALL.0, 914 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
928 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. 915 false => Stat::NAK.to_bits() ^ Stat::VALID.to_bits(),
929 false => Stat::NAK.0 ^ Stat::VALID.0, 916 }));
930 })); 917 w.set_ctr_rx(true); // don't clear
931 w.set_ctr_rx(true); // don't clear 918 w.set_ctr_tx(true); // don't clear
932 w.set_ctr_tx(true); // don't clear 919 });
933 })
934 };
935 920
936 Ok(rx_len) 921 Ok(rx_len)
937 } 922 }
@@ -952,23 +937,21 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
952 let mut stat_rx = 0; 937 let mut stat_rx = 0;
953 if first { 938 if first {
954 // change NAK -> STALL 939 // change NAK -> STALL
955 stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0; 940 stat_rx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
956 } 941 }
957 if last { 942 if last {
958 // change STALL -> VALID 943 // change STALL -> VALID
959 stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0; 944 stat_rx ^= Stat::STALL.to_bits() ^ Stat::VALID.to_bits();
960 } 945 }
961 // Note: if this is the first AND last transfer, the above effectively 946 // Note: if this is the first AND last transfer, the above effectively
962 // does a change of NAK -> VALID. 947 // does a change of NAK -> VALID.
963 unsafe { 948 regs.epr(0).write(|w| {
964 regs.epr(0).write(|w| { 949 w.set_ep_type(EpType::CONTROL);
965 w.set_ep_type(EpType::CONTROL); 950 w.set_stat_rx(Stat::from_bits(stat_rx));
966 w.set_stat_rx(Stat(stat_rx)); 951 w.set_ep_kind(last); // set OUT_STATUS if last.
967 w.set_ep_kind(last); // set OUT_STATUS if last. 952 w.set_ctr_rx(true); // don't clear
968 w.set_ctr_rx(true); // don't clear 953 w.set_ctr_tx(true); // don't clear
969 w.set_ctr_tx(true); // don't clear 954 });
970 })
971 }
972 } 955 }
973 956
974 trace!("WRITE WAITING"); 957 trace!("WRITE WAITING");
@@ -976,7 +959,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
976 EP_IN_WAKERS[0].register(cx.waker()); 959 EP_IN_WAKERS[0].register(cx.waker());
977 EP_OUT_WAKERS[0].register(cx.waker()); 960 EP_OUT_WAKERS[0].register(cx.waker());
978 let regs = T::regs(); 961 let regs = T::regs();
979 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { 962 if regs.epr(0).read().stat_tx() == Stat::NAK {
980 Poll::Ready(()) 963 Poll::Ready(())
981 } else { 964 } else {
982 Poll::Pending 965 Poll::Pending
@@ -992,15 +975,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
992 self.ep_in.write_data(data); 975 self.ep_in.write_data(data);
993 976
994 let regs = T::regs(); 977 let regs = T::regs();
995 unsafe { 978 regs.epr(0).write(|w| {
996 regs.epr(0).write(|w| { 979 w.set_ep_type(EpType::CONTROL);
997 w.set_ep_type(EpType::CONTROL); 980 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
998 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 981 w.set_ep_kind(last); // set OUT_STATUS if last.
999 w.set_ep_kind(last); // set OUT_STATUS if last. 982 w.set_ctr_rx(true); // don't clear
1000 w.set_ctr_rx(true); // don't clear 983 w.set_ctr_tx(true); // don't clear
1001 w.set_ctr_tx(true); // don't clear 984 });
1002 })
1003 };
1004 985
1005 trace!("WRITE OK"); 986 trace!("WRITE OK");
1006 987
@@ -1014,16 +995,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1014 self.ep_in.write_data(&[]); 995 self.ep_in.write_data(&[]);
1015 996
1016 // Set OUT=stall, IN=accept 997 // Set OUT=stall, IN=accept
1017 unsafe { 998 let epr = regs.epr(0).read();
1018 let epr = regs.epr(0).read(); 999 regs.epr(0).write(|w| {
1019 regs.epr(0).write(|w| { 1000 w.set_ep_type(EpType::CONTROL);
1020 w.set_ep_type(EpType::CONTROL); 1001 w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
1021 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); 1002 w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::VALID.to_bits()));
1022 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); 1003 w.set_ctr_rx(true); // don't clear
1023 w.set_ctr_rx(true); // don't clear 1004 w.set_ctr_tx(true); // don't clear
1024 w.set_ctr_tx(true); // don't clear 1005 });
1025 });
1026 }
1027 trace!("control: accept WAITING"); 1006 trace!("control: accept WAITING");
1028 1007
1029 // Wait is needed, so that we don't set the address too soon, breaking the status stage. 1008 // Wait is needed, so that we don't set the address too soon, breaking the status stage.
@@ -1031,7 +1010,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1031 poll_fn(|cx| { 1010 poll_fn(|cx| {
1032 EP_IN_WAKERS[0].register(cx.waker()); 1011 EP_IN_WAKERS[0].register(cx.waker());
1033 let regs = T::regs(); 1012 let regs = T::regs();
1034 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { 1013 if regs.epr(0).read().stat_tx() == Stat::NAK {
1035 Poll::Ready(()) 1014 Poll::Ready(())
1036 } else { 1015 } else {
1037 Poll::Pending 1016 Poll::Pending
@@ -1047,16 +1026,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1047 trace!("control: reject"); 1026 trace!("control: reject");
1048 1027
1049 // Set IN+OUT to stall 1028 // Set IN+OUT to stall
1050 unsafe { 1029 let epr = regs.epr(0).read();
1051 let epr = regs.epr(0).read(); 1030 regs.epr(0).write(|w| {
1052 regs.epr(0).write(|w| { 1031 w.set_ep_type(EpType::CONTROL);
1053 w.set_ep_type(EpType::CONTROL); 1032 w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
1054 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); 1033 w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::STALL.to_bits()));
1055 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); 1034 w.set_ctr_rx(true); // don't clear
1056 w.set_ctr_rx(true); // don't clear 1035 w.set_ctr_tx(true); // don't clear
1057 w.set_ctr_tx(true); // don't clear 1036 });
1058 });
1059 }
1060 } 1037 }
1061 1038
1062 async fn accept_set_address(&mut self, addr: u8) { 1039 async fn accept_set_address(&mut self, addr: u8) {
@@ -1064,11 +1041,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1064 1041
1065 let regs = T::regs(); 1042 let regs = T::regs();
1066 trace!("setting addr: {}", addr); 1043 trace!("setting addr: {}", addr);
1067 unsafe { 1044 regs.daddr().write(|w| {
1068 regs.daddr().write(|w| { 1045 w.set_ef(true);
1069 w.set_ef(true); 1046 w.set_add(addr);
1070 w.set_add(addr); 1047 });
1071 })
1072 }
1073 } 1048 }
1074} 1049}
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs
index 193e0df0d..12e5f0e60 100644
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ b/embassy-stm32/src/usb_otg/mod.rs
@@ -1,7 +1,5 @@
1use embassy_cortex_m::interrupt::Interrupt;
2
3use crate::peripherals;
4use crate::rcc::RccPeripheral; 1use crate::rcc::RccPeripheral;
2use crate::{interrupt, peripherals};
5 3
6#[cfg(feature = "nightly")] 4#[cfg(feature = "nightly")]
7mod usb; 5mod usb;
@@ -25,7 +23,7 @@ pub(crate) mod sealed {
25} 23}
26 24
27pub trait Instance: sealed::Instance + RccPeripheral { 25pub trait Instance: sealed::Instance + RccPeripheral {
28 type Interrupt: Interrupt; 26 type Interrupt: interrupt::typelevel::Interrupt;
29} 27}
30 28
31// Internal PHY pins 29// Internal PHY pins
@@ -109,7 +107,7 @@ foreach_interrupt!(
109 } 107 }
110 108
111 impl Instance for peripherals::USB_OTG_FS { 109 impl Instance for peripherals::USB_OTG_FS {
112 type Interrupt = crate::interrupt::$irq; 110 type Interrupt = crate::interrupt::typelevel::$irq;
113 } 111 }
114 }; 112 };
115 113
@@ -150,7 +148,7 @@ foreach_interrupt!(
150 148
151 fn regs() -> crate::pac::otg::Otg { 149 fn regs() -> crate::pac::otg::Otg {
152 // OTG HS registers are a superset of FS registers 150 // OTG HS registers are a superset of FS registers
153 crate::pac::otg::Otg(crate::pac::USB_OTG_HS.0) 151 unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
154 } 152 }
155 153
156 #[cfg(feature = "nightly")] 154 #[cfg(feature = "nightly")]
@@ -161,7 +159,7 @@ foreach_interrupt!(
161 } 159 }
162 160
163 impl Instance for peripherals::USB_OTG_HS { 161 impl Instance for peripherals::USB_OTG_HS {
164 type Interrupt = crate::interrupt::$irq; 162 type Interrupt = crate::interrupt::typelevel::$irq;
165 } 163 }
166 }; 164 };
167); 165);
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index e602bcb70..6783db28d 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -3,18 +3,18 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{AtomicBool, AtomicU16, Ordering}; 5use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
6use embassy_cortex_m::interrupt::Interrupt;
7use embassy_hal_common::{into_ref, Peripheral}; 6use embassy_hal_common::{into_ref, Peripheral};
8use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
9use embassy_usb_driver::{ 8use embassy_usb_driver::{
10 self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, 9 self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo,
11 EndpointType, Event, Unsupported, 10 EndpointOut, EndpointType, Event, Unsupported,
12}; 11};
13use futures::future::poll_fn; 12use futures::future::poll_fn;
14 13
15use super::*; 14use super::*;
16use crate::gpio::sealed::AFType; 15use crate::gpio::sealed::AFType;
17use crate::interrupt; 16use crate::interrupt;
17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::otg::{regs, vals}; 18use crate::pac::otg::{regs, vals};
19use crate::rcc::sealed::RccPeripheral; 19use crate::rcc::sealed::RccPeripheral;
20use crate::time::Hertz; 20use crate::time::Hertz;
@@ -24,25 +24,22 @@ pub struct InterruptHandler<T: Instance> {
24 _phantom: PhantomData<T>, 24 _phantom: PhantomData<T>,
25} 25}
26 26
27impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { 27impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
28 unsafe fn on_interrupt() { 28 unsafe fn on_interrupt() {
29 trace!("irq"); 29 trace!("irq");
30 let r = T::regs(); 30 let r = T::regs();
31 let state = T::state(); 31 let state = T::state();
32 32
33 // SAFETY: atomic read/write 33 let ints = r.gintsts().read();
34 let ints = unsafe { r.gintsts().read() }; 34 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
35 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() {
36 // Mask interrupts and notify `Bus` to process them 35 // Mask interrupts and notify `Bus` to process them
37 unsafe { r.gintmsk().write(|_| {}) }; 36 r.gintmsk().write(|_| {});
38 T::state().bus_waker.wake(); 37 T::state().bus_waker.wake();
39 } 38 }
40 39
41 // Handle RX 40 // Handle RX
42 // SAFETY: atomic read with no side effects 41 while r.gintsts().read().rxflvl() {
43 while unsafe { r.gintsts().read().rxflvl() } { 42 let status = r.grxstsp().read();
44 // SAFETY: atomic "pop" register
45 let status = unsafe { r.grxstsp().read() };
46 let ep_num = status.epnum() as usize; 43 let ep_num = status.epnum() as usize;
47 let len = status.bcnt() as usize; 44 let len = status.bcnt() as usize;
48 45
@@ -57,21 +54,15 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
57 if state.ep0_setup_ready.load(Ordering::Relaxed) == false { 54 if state.ep0_setup_ready.load(Ordering::Relaxed) == false {
58 // SAFETY: exclusive access ensured by atomic bool 55 // SAFETY: exclusive access ensured by atomic bool
59 let data = unsafe { &mut *state.ep0_setup_data.get() }; 56 let data = unsafe { &mut *state.ep0_setup_data.get() };
60 // SAFETY: FIFO reads are exclusive to this IRQ 57 data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
61 unsafe { 58 data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
62 data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
63 data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
64 }
65 state.ep0_setup_ready.store(true, Ordering::Release); 59 state.ep0_setup_ready.store(true, Ordering::Release);
66 state.ep_out_wakers[0].wake(); 60 state.ep_out_wakers[0].wake();
67 } else { 61 } else {
68 error!("received SETUP before previous finished processing"); 62 error!("received SETUP before previous finished processing");
69 // discard FIFO 63 // discard FIFO
70 // SAFETY: FIFO reads are exclusive to IRQ 64 r.fifo(0).read();
71 unsafe { 65 r.fifo(0).read();
72 r.fifo(0).read();
73 r.fifo(0).read();
74 }
75 } 66 }
76 } 67 }
77 vals::Pktstsd::OUT_DATA_RX => { 68 vals::Pktstsd::OUT_DATA_RX => {
@@ -84,8 +75,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
84 75
85 for chunk in buf.chunks_mut(4) { 76 for chunk in buf.chunks_mut(4) {
86 // RX FIFO is shared so always read from fifo(0) 77 // RX FIFO is shared so always read from fifo(0)
87 // SAFETY: FIFO reads are exclusive to IRQ 78 let data = r.fifo(0).read().0;
88 let data = unsafe { r.fifo(0).read().0 };
89 chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]); 79 chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]);
90 } 80 }
91 81
@@ -97,8 +87,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
97 // discard FIFO data 87 // discard FIFO data
98 let len_words = (len + 3) / 4; 88 let len_words = (len + 3) / 4;
99 for _ in 0..len_words { 89 for _ in 0..len_words {
100 // SAFETY: FIFO reads are exclusive to IRQ 90 r.fifo(0).read().data();
101 unsafe { r.fifo(0).read().data() };
102 } 91 }
103 } 92 }
104 } 93 }
@@ -108,30 +97,26 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
108 vals::Pktstsd::SETUP_DATA_DONE => { 97 vals::Pktstsd::SETUP_DATA_DONE => {
109 trace!("SETUP_DATA_DONE ep={}", ep_num); 98 trace!("SETUP_DATA_DONE ep={}", ep_num);
110 } 99 }
111 x => trace!("unknown PKTSTS: {}", x.0), 100 x => trace!("unknown PKTSTS: {}", x.to_bits()),
112 } 101 }
113 } 102 }
114 103
115 // IN endpoint interrupt 104 // IN endpoint interrupt
116 if ints.iepint() { 105 if ints.iepint() {
117 // SAFETY: atomic read with no side effects 106 let mut ep_mask = r.daint().read().iepint();
118 let mut ep_mask = unsafe { r.daint().read().iepint() };
119 let mut ep_num = 0; 107 let mut ep_num = 0;
120 108
121 // Iterate over endpoints while there are non-zero bits in the mask 109 // Iterate over endpoints while there are non-zero bits in the mask
122 while ep_mask != 0 { 110 while ep_mask != 0 {
123 if ep_mask & 1 != 0 { 111 if ep_mask & 1 != 0 {
124 // SAFETY: atomic read with no side effects 112 let ep_ints = r.diepint(ep_num).read();
125 let ep_ints = unsafe { r.diepint(ep_num).read() };
126 113
127 // clear all 114 // clear all
128 // SAFETY: DIEPINT is exclusive to IRQ 115 r.diepint(ep_num).write_value(ep_ints);
129 unsafe { r.diepint(ep_num).write_value(ep_ints) };
130 116
131 // TXFE is cleared in DIEPEMPMSK 117 // TXFE is cleared in DIEPEMPMSK
132 if ep_ints.txfe() { 118 if ep_ints.txfe() {
133 // SAFETY: DIEPEMPMSK is shared with `Endpoint` so critical section is needed for RMW 119 critical_section::with(|_| {
134 critical_section::with(|_| unsafe {
135 r.diepempmsk().modify(|w| { 120 r.diepempmsk().modify(|w| {
136 w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num)); 121 w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
137 }); 122 });
@@ -139,7 +124,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
139 } 124 }
140 125
141 state.ep_in_wakers[ep_num].wake(); 126 state.ep_in_wakers[ep_num].wake();
142 trace!("in ep={} irq val={:b}", ep_num, ep_ints.0); 127 trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
143 } 128 }
144 129
145 ep_mask >>= 1; 130 ep_mask >>= 1;
@@ -159,7 +144,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
159 // // clear all 144 // // clear all
160 // r.doepint(ep_num).write_value(ep_ints); 145 // r.doepint(ep_num).write_value(ep_ints);
161 // state.ep_out_wakers[ep_num].wake(); 146 // state.ep_out_wakers[ep_num].wake();
162 // trace!("out ep={} irq val={=u32:b}", ep_num, ep_ints.0); 147 // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
163 // } 148 // }
164 149
165 // ep_mask >>= 1; 150 // ep_mask >>= 1;
@@ -172,8 +157,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
172macro_rules! config_ulpi_pins { 157macro_rules! config_ulpi_pins {
173 ($($pin:ident),*) => { 158 ($($pin:ident),*) => {
174 into_ref!($($pin),*); 159 into_ref!($($pin),*);
175 // NOTE(unsafe) Exclusive access to the registers 160 critical_section::with(|_| {
176 critical_section::with(|_| unsafe {
177 $( 161 $(
178 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); 162 $pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
179 #[cfg(gpio_v2)] 163 #[cfg(gpio_v2)]
@@ -272,7 +256,34 @@ struct EndpointData {
272 fifo_size_words: u16, 256 fifo_size_words: u16,
273} 257}
274 258
259#[non_exhaustive]
260#[derive(Clone, Copy, PartialEq, Eq, Debug)]
261pub struct Config {
262 /// Enable VBUS detection.
263 ///
264 /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
265 /// This is done by checkihg whether there is 5V on the VBUS pin or not.
266 ///
267 /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
268 /// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume
269 /// there's power in VBUS, i.e. the USB cable is always plugged in.)
270 ///
271 /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
272 /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
273 ///
274 /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
275 /// voltage divider. See ST application note AN4879 and the reference manual for more details.
276 pub vbus_detection: bool,
277}
278
279impl Default for Config {
280 fn default() -> Self {
281 Self { vbus_detection: true }
282 }
283}
284
275pub struct Driver<'d, T: Instance> { 285pub struct Driver<'d, T: Instance> {
286 config: Config,
276 phantom: PhantomData<&'d mut T>, 287 phantom: PhantomData<&'d mut T>,
277 ep_in: [Option<EndpointData>; MAX_EP_COUNT], 288 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
278 ep_out: [Option<EndpointData>; MAX_EP_COUNT], 289 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
@@ -291,19 +302,19 @@ impl<'d, T: Instance> Driver<'d, T> {
291 /// Endpoint allocation will fail if it is too small. 302 /// Endpoint allocation will fail if it is too small.
292 pub fn new_fs( 303 pub fn new_fs(
293 _peri: impl Peripheral<P = T> + 'd, 304 _peri: impl Peripheral<P = T> + 'd,
294 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 305 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
295 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 306 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
296 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 307 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
297 ep_out_buffer: &'d mut [u8], 308 ep_out_buffer: &'d mut [u8],
309 config: Config,
298 ) -> Self { 310 ) -> Self {
299 into_ref!(dp, dm); 311 into_ref!(dp, dm);
300 312
301 unsafe { 313 dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
302 dp.set_as_af(dp.af_num(), AFType::OutputPushPull); 314 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
303 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
304 }
305 315
306 Self { 316 Self {
317 config,
307 phantom: PhantomData, 318 phantom: PhantomData,
308 ep_in: [None; MAX_EP_COUNT], 319 ep_in: [None; MAX_EP_COUNT],
309 ep_out: [None; MAX_EP_COUNT], 320 ep_out: [None; MAX_EP_COUNT],
@@ -322,7 +333,7 @@ impl<'d, T: Instance> Driver<'d, T> {
322 /// Endpoint allocation will fail if it is too small. 333 /// Endpoint allocation will fail if it is too small.
323 pub fn new_hs_ulpi( 334 pub fn new_hs_ulpi(
324 _peri: impl Peripheral<P = T> + 'd, 335 _peri: impl Peripheral<P = T> + 'd,
325 _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 336 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
326 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd, 337 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd,
327 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd, 338 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd,
328 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd, 339 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd,
@@ -336,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> {
336 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd, 347 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
337 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd, 348 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
338 ep_out_buffer: &'d mut [u8], 349 ep_out_buffer: &'d mut [u8],
350 config: Config,
339 ) -> Self { 351 ) -> Self {
340 assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); 352 assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
341 353
@@ -345,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
345 ); 357 );
346 358
347 Self { 359 Self {
360 config,
348 phantom: PhantomData, 361 phantom: PhantomData,
349 ep_in: [None; MAX_EP_COUNT], 362 ep_in: [None; MAX_EP_COUNT],
350 ep_out: [None; MAX_EP_COUNT], 363 ep_out: [None; MAX_EP_COUNT],
@@ -482,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
482 495
483 ( 496 (
484 Bus { 497 Bus {
498 config: self.config,
485 phantom: PhantomData, 499 phantom: PhantomData,
486 ep_in: self.ep_in, 500 ep_in: self.ep_in,
487 ep_out: self.ep_out, 501 ep_out: self.ep_out,
488 phy_type: self.phy_type, 502 phy_type: self.phy_type,
489 enabled: false, 503 inited: false,
490 }, 504 },
491 ControlPipe { 505 ControlPipe {
492 _phantom: PhantomData, 506 _phantom: PhantomData,
@@ -499,31 +513,220 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
499} 513}
500 514
501pub struct Bus<'d, T: Instance> { 515pub struct Bus<'d, T: Instance> {
516 config: Config,
502 phantom: PhantomData<&'d mut T>, 517 phantom: PhantomData<&'d mut T>,
503 ep_in: [Option<EndpointData>; MAX_EP_COUNT], 518 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
504 ep_out: [Option<EndpointData>; MAX_EP_COUNT], 519 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
505 phy_type: PhyType, 520 phy_type: PhyType,
506 enabled: bool, 521 inited: bool,
507} 522}
508 523
509impl<'d, T: Instance> Bus<'d, T> { 524impl<'d, T: Instance> Bus<'d, T> {
510 fn restore_irqs() { 525 fn restore_irqs() {
511 // SAFETY: atomic write 526 T::regs().gintmsk().write(|w| {
512 unsafe { 527 w.set_usbrst(true);
513 T::regs().gintmsk().write(|w| { 528 w.set_enumdnem(true);
514 w.set_usbrst(true); 529 w.set_usbsuspm(true);
515 w.set_enumdnem(true); 530 w.set_wuim(true);
516 w.set_usbsuspm(true); 531 w.set_iepint(true);
517 w.set_wuim(true); 532 w.set_oepint(true);
518 w.set_iepint(true); 533 w.set_rxflvlm(true);
519 w.set_oepint(true); 534 w.set_srqim(true);
520 w.set_rxflvlm(true); 535 w.set_otgint(true);
521 }); 536 });
522 }
523 } 537 }
524} 538}
525 539
526impl<'d, T: Instance> Bus<'d, T> { 540impl<'d, T: Instance> Bus<'d, T> {
541 fn init(&mut self) {
542 #[cfg(stm32l4)]
543 {
544 crate::peripherals::PWR::enable();
545 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
546 }
547
548 #[cfg(stm32f7)]
549 {
550 // Enable ULPI clock if external PHY is used
551 let ulpien = !self.phy_type.internal();
552 critical_section::with(|_| {
553 crate::pac::RCC.ahb1enr().modify(|w| {
554 if T::HIGH_SPEED {
555 w.set_usb_otg_hsulpien(ulpien);
556 } else {
557 w.set_usb_otg_hsen(ulpien);
558 }
559 });
560
561 // Low power mode
562 crate::pac::RCC.ahb1lpenr().modify(|w| {
563 if T::HIGH_SPEED {
564 w.set_usb_otg_hsulpilpen(ulpien);
565 } else {
566 w.set_usb_otg_hslpen(ulpien);
567 }
568 });
569 });
570 }
571
572 #[cfg(stm32h7)]
573 {
574 // If true, VDD33USB is generated by internal regulator from VDD50USB
575 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
576 // TODO: unhardcode
577 let internal_regulator = false;
578
579 // Enable USB power
580 critical_section::with(|_| {
581 crate::pac::PWR.cr3().modify(|w| {
582 w.set_usb33den(true);
583 w.set_usbregen(internal_regulator);
584 })
585 });
586
587 // Wait for USB power to stabilize
588 while !crate::pac::PWR.cr3().read().usb33rdy() {}
589
590 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
591 critical_section::with(|_| {
592 crate::pac::RCC
593 .d2ccip2r()
594 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
595 });
596
597 // Enable ULPI clock if external PHY is used
598 let ulpien = !self.phy_type.internal();
599 critical_section::with(|_| {
600 crate::pac::RCC.ahb1enr().modify(|w| {
601 if T::HIGH_SPEED {
602 w.set_usb_otg_hs_ulpien(ulpien);
603 } else {
604 w.set_usb_otg_fs_ulpien(ulpien);
605 }
606 });
607 crate::pac::RCC.ahb1lpenr().modify(|w| {
608 if T::HIGH_SPEED {
609 w.set_usb_otg_hs_ulpilpen(ulpien);
610 } else {
611 w.set_usb_otg_fs_ulpilpen(ulpien);
612 }
613 });
614 });
615 }
616
617 #[cfg(stm32u5)]
618 {
619 // Enable USB power
620 critical_section::with(|_| {
621 crate::pac::RCC.ahb3enr().modify(|w| {
622 w.set_pwren(true);
623 });
624 cortex_m::asm::delay(2);
625
626 crate::pac::PWR.svmcr().modify(|w| {
627 w.set_usv(true);
628 w.set_uvmen(true);
629 });
630 });
631
632 // Wait for USB power to stabilize
633 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
634
635 // Select HSI48 as USB clock source.
636 critical_section::with(|_| {
637 crate::pac::RCC.ccipr1().modify(|w| {
638 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
639 })
640 });
641 }
642
643 <T as RccPeripheral>::enable();
644 <T as RccPeripheral>::reset();
645
646 T::Interrupt::unpend();
647 unsafe { T::Interrupt::enable() };
648
649 let r = T::regs();
650 let core_id = r.cid().read().0;
651 info!("Core id {:08x}", core_id);
652
653 // Wait for AHB ready.
654 while !r.grstctl().read().ahbidl() {}
655
656 // Configure as device.
657 r.gusbcfg().write(|w| {
658 // Force device mode
659 w.set_fdmod(true);
660 // Enable internal full-speed PHY
661 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
662 });
663
664 // Configuring Vbus sense and SOF output
665 match core_id {
666 0x0000_1200 | 0x0000_1100 => {
667 assert!(self.phy_type != PhyType::InternalHighSpeed);
668
669 r.gccfg_v1().modify(|w| {
670 // Enable internal full-speed PHY, logic is inverted
671 w.set_pwrdwn(self.phy_type.internal());
672 });
673
674 // F429-like chips have the GCCFG.NOVBUSSENS bit
675 r.gccfg_v1().modify(|w| {
676 w.set_novbussens(!self.config.vbus_detection);
677 w.set_vbusasen(false);
678 w.set_vbusbsen(self.config.vbus_detection);
679 w.set_sofouten(false);
680 });
681 }
682 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
683 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
684 r.gccfg_v2().modify(|w| {
685 // Enable internal full-speed PHY, logic is inverted
686 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
687 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
688 });
689
690 r.gccfg_v2().modify(|w| {
691 w.set_vbden(self.config.vbus_detection);
692 });
693
694 // Force B-peripheral session
695 r.gotgctl().modify(|w| {
696 w.set_bvaloen(!self.config.vbus_detection);
697 w.set_bvaloval(true);
698 });
699 }
700 _ => unimplemented!("Unknown USB core id {:X}", core_id),
701 }
702
703 // Soft disconnect.
704 r.dctl().write(|w| w.set_sdis(true));
705
706 // Set speed.
707 r.dcfg().write(|w| {
708 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
709 w.set_dspd(self.phy_type.to_dspd());
710 });
711
712 // Unmask transfer complete EP interrupt
713 r.diepmsk().write(|w| {
714 w.set_xfrcm(true);
715 });
716
717 // Unmask and clear core interrupts
718 Bus::<T>::restore_irqs();
719 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
720
721 // Unmask global interrupt
722 r.gahbcfg().write(|w| {
723 w.set_gint(true); // unmask global interrupt
724 });
725
726 // Connect
727 r.dctl().write(|w| w.set_sdis(false));
728 }
729
527 fn init_fifo(&mut self) { 730 fn init_fifo(&mut self) {
528 trace!("init_fifo"); 731 trace!("init_fifo");
529 732
@@ -533,8 +736,7 @@ impl<'d, T: Instance> Bus<'d, T> {
533 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); 736 let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
534 trace!("configuring rx fifo size={}", rx_fifo_size_words); 737 trace!("configuring rx fifo size={}", rx_fifo_size_words);
535 738
536 // SAFETY: register is exclusive to `Bus` with `&mut self` 739 r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
537 unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) };
538 740
539 // Configure TX (USB in direction) fifo size for each endpoint 741 // Configure TX (USB in direction) fifo size for each endpoint
540 let mut fifo_top = rx_fifo_size_words; 742 let mut fifo_top = rx_fifo_size_words;
@@ -549,13 +751,10 @@ impl<'d, T: Instance> Bus<'d, T> {
549 751
550 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; 752 let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
551 753
552 // SAFETY: register is exclusive to `Bus` with `&mut self` 754 dieptxf.write(|w| {
553 unsafe { 755 w.set_fd(ep.fifo_size_words);
554 dieptxf.write(|w| { 756 w.set_sa(fifo_top);
555 w.set_fd(ep.fifo_size_words); 757 });
556 w.set_sa(fifo_top);
557 });
558 }
559 758
560 fifo_top += ep.fifo_size_words; 759 fifo_top += ep.fifo_size_words;
561 } 760 }
@@ -565,6 +764,19 @@ impl<'d, T: Instance> Bus<'d, T> {
565 fifo_top <= T::FIFO_DEPTH_WORDS, 764 fifo_top <= T::FIFO_DEPTH_WORDS,
566 "FIFO allocations exceeded maximum capacity" 765 "FIFO allocations exceeded maximum capacity"
567 ); 766 );
767
768 // Flush fifos
769 r.grstctl().write(|w| {
770 w.set_rxfflsh(true);
771 w.set_txfflsh(true);
772 w.set_txfnum(0x10);
773 });
774 loop {
775 let x = r.grstctl().read();
776 if !x.rxfflsh() && !x.txfflsh() {
777 break;
778 }
779 }
568 } 780 }
569 781
570 fn configure_endpoints(&mut self) { 782 fn configure_endpoints(&mut self) {
@@ -575,8 +787,7 @@ impl<'d, T: Instance> Bus<'d, T> {
575 // Configure IN endpoints 787 // Configure IN endpoints
576 for (index, ep) in self.ep_in.iter().enumerate() { 788 for (index, ep) in self.ep_in.iter().enumerate() {
577 if let Some(ep) = ep { 789 if let Some(ep) = ep {
578 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW 790 critical_section::with(|_| {
579 critical_section::with(|_| unsafe {
580 r.diepctl(index).write(|w| { 791 r.diepctl(index).write(|w| {
581 if index == 0 { 792 if index == 0 {
582 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); 793 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
@@ -584,6 +795,8 @@ impl<'d, T: Instance> Bus<'d, T> {
584 w.set_mpsiz(ep.max_packet_size); 795 w.set_mpsiz(ep.max_packet_size);
585 w.set_eptyp(to_eptyp(ep.ep_type)); 796 w.set_eptyp(to_eptyp(ep.ep_type));
586 w.set_sd0pid_sevnfrm(true); 797 w.set_sd0pid_sevnfrm(true);
798 w.set_txfnum(index as _);
799 w.set_snak(true);
587 } 800 }
588 }); 801 });
589 }); 802 });
@@ -593,8 +806,7 @@ impl<'d, T: Instance> Bus<'d, T> {
593 // Configure OUT endpoints 806 // Configure OUT endpoints
594 for (index, ep) in self.ep_out.iter().enumerate() { 807 for (index, ep) in self.ep_out.iter().enumerate() {
595 if let Some(ep) = ep { 808 if let Some(ep) = ep {
596 // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW 809 critical_section::with(|_| {
597 critical_section::with(|_| unsafe {
598 r.doepctl(index).write(|w| { 810 r.doepctl(index).write(|w| {
599 if index == 0 { 811 if index == 0 {
600 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); 812 w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
@@ -618,13 +830,17 @@ impl<'d, T: Instance> Bus<'d, T> {
618 } 830 }
619 831
620 // Enable IRQs for allocated endpoints 832 // Enable IRQs for allocated endpoints
621 // SAFETY: register is exclusive to `Bus` with `&mut self` 833 r.daintmsk().modify(|w| {
622 unsafe { 834 w.set_iepm(ep_irq_mask(&self.ep_in));
623 r.daintmsk().modify(|w| { 835 // OUT interrupts not used, handled in RXFLVL
624 w.set_iepm(ep_irq_mask(&self.ep_in)); 836 // w.set_oepm(ep_irq_mask(&self.ep_out));
625 // OUT interrupts not used, handled in RXFLVL 837 });
626 // w.set_oepm(ep_irq_mask(&self.ep_out)); 838 }
627 }); 839
840 fn disable_all_endpoints(&mut self) {
841 for i in 0..T::ENDPOINT_COUNT {
842 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
843 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
628 } 844 }
629 } 845 }
630 846
@@ -634,26 +850,55 @@ impl<'d, T: Instance> Bus<'d, T> {
634 <T as RccPeripheral>::disable(); 850 <T as RccPeripheral>::disable();
635 851
636 #[cfg(stm32l4)] 852 #[cfg(stm32l4)]
637 unsafe { 853 crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
638 crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); 854 // Cannot disable PWR, because other peripherals might be using it
639 // Cannot disable PWR, because other peripherals might be using it
640 }
641 } 855 }
642} 856}
643 857
644impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { 858impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
645 async fn poll(&mut self) -> Event { 859 async fn poll(&mut self) -> Event {
646 poll_fn(move |cx| { 860 poll_fn(move |cx| {
647 // TODO: implement VBUS detection 861 if !self.inited {
648 if !self.enabled { 862 self.init();
649 return Poll::Ready(Event::PowerDetected); 863 self.inited = true;
864
865 // If no vbus detection, just return a single PowerDetected event at startup.
866 if !self.config.vbus_detection {
867 return Poll::Ready(Event::PowerDetected);
868 }
650 } 869 }
651 870
652 let r = T::regs(); 871 let r = T::regs();
653 872
654 T::state().bus_waker.register(cx.waker()); 873 T::state().bus_waker.register(cx.waker());
655 874
656 let ints = unsafe { r.gintsts().read() }; 875 let ints = r.gintsts().read();
876
877 if ints.srqint() {
878 trace!("vbus detected");
879
880 r.gintsts().write(|w| w.set_srqint(true)); // clear
881 Self::restore_irqs();
882
883 if self.config.vbus_detection {
884 return Poll::Ready(Event::PowerDetected);
885 }
886 }
887
888 if ints.otgint() {
889 let otgints = r.gotgint().read();
890 r.gotgint().write_value(otgints); // clear all
891 Self::restore_irqs();
892
893 if otgints.sedet() {
894 trace!("vbus removed");
895 if self.config.vbus_detection {
896 self.disable_all_endpoints();
897 return Poll::Ready(Event::PowerRemoved);
898 }
899 }
900 }
901
657 if ints.usbrst() { 902 if ints.usbrst() {
658 trace!("reset"); 903 trace!("reset");
659 904
@@ -661,34 +906,27 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
661 self.configure_endpoints(); 906 self.configure_endpoints();
662 907
663 // Reset address 908 // Reset address
664 // SAFETY: DCFG is shared with `ControlPipe` so critical section is needed for RMW 909 critical_section::with(|_| {
665 critical_section::with(|_| unsafe {
666 r.dcfg().modify(|w| { 910 r.dcfg().modify(|w| {
667 w.set_dad(0); 911 w.set_dad(0);
668 }); 912 });
669 }); 913 });
670 914
671 // SAFETY: atomic clear on rc_w1 register 915 r.gintsts().write(|w| w.set_usbrst(true)); // clear
672 unsafe { r.gintsts().write(|w| w.set_usbrst(true)) }; // clear
673 Self::restore_irqs(); 916 Self::restore_irqs();
674 } 917 }
675 918
676 if ints.enumdne() { 919 if ints.enumdne() {
677 trace!("enumdne"); 920 trace!("enumdne");
678 921
679 // SAFETY: atomic read with no side effects 922 let speed = r.dsts().read().enumspd();
680 let speed = unsafe { r.dsts().read().enumspd() }; 923 trace!(" speed={}", speed.to_bits());
681 trace!(" speed={}", speed.0);
682 924
683 // SAFETY: register is only accessed by `Bus` under `&mut self` 925 r.gusbcfg().modify(|w| {
684 unsafe { 926 w.set_trdt(calculate_trdt(speed, T::frequency()));
685 r.gusbcfg().modify(|w| { 927 });
686 w.set_trdt(calculate_trdt(speed, T::frequency()));
687 })
688 };
689 928
690 // SAFETY: atomic clear on rc_w1 register 929 r.gintsts().write(|w| w.set_enumdne(true)); // clear
691 unsafe { r.gintsts().write(|w| w.set_enumdne(true)) }; // clear
692 Self::restore_irqs(); 930 Self::restore_irqs();
693 931
694 return Poll::Ready(Event::Reset); 932 return Poll::Ready(Event::Reset);
@@ -696,16 +934,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
696 934
697 if ints.usbsusp() { 935 if ints.usbsusp() {
698 trace!("suspend"); 936 trace!("suspend");
699 // SAFETY: atomic clear on rc_w1 register 937 r.gintsts().write(|w| w.set_usbsusp(true)); // clear
700 unsafe { r.gintsts().write(|w| w.set_usbsusp(true)) }; // clear
701 Self::restore_irqs(); 938 Self::restore_irqs();
702 return Poll::Ready(Event::Suspend); 939 return Poll::Ready(Event::Suspend);
703 } 940 }
704 941
705 if ints.wkupint() { 942 if ints.wkupint() {
706 trace!("resume"); 943 trace!("resume");
707 // SAFETY: atomic clear on rc_w1 register 944 r.gintsts().write(|w| w.set_wkupint(true)); // clear
708 unsafe { r.gintsts().write(|w| w.set_wkupint(true)) }; // clear
709 Self::restore_irqs(); 945 Self::restore_irqs();
710 return Poll::Ready(Event::Resume); 946 return Poll::Ready(Event::Resume);
711 } 947 }
@@ -727,8 +963,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
727 let regs = T::regs(); 963 let regs = T::regs();
728 match ep_addr.direction() { 964 match ep_addr.direction() {
729 Direction::Out => { 965 Direction::Out => {
730 // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW 966 critical_section::with(|_| {
731 critical_section::with(|_| unsafe {
732 regs.doepctl(ep_addr.index()).modify(|w| { 967 regs.doepctl(ep_addr.index()).modify(|w| {
733 w.set_stall(stalled); 968 w.set_stall(stalled);
734 }); 969 });
@@ -737,8 +972,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
737 T::state().ep_out_wakers[ep_addr.index()].wake(); 972 T::state().ep_out_wakers[ep_addr.index()].wake();
738 } 973 }
739 Direction::In => { 974 Direction::In => {
740 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW 975 critical_section::with(|_| {
741 critical_section::with(|_| unsafe {
742 regs.diepctl(ep_addr.index()).modify(|w| { 976 regs.diepctl(ep_addr.index()).modify(|w| {
743 w.set_stall(stalled); 977 w.set_stall(stalled);
744 }); 978 });
@@ -758,10 +992,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
758 992
759 let regs = T::regs(); 993 let regs = T::regs();
760 994
761 // SAFETY: atomic read with no side effects
762 match ep_addr.direction() { 995 match ep_addr.direction() {
763 Direction::Out => unsafe { regs.doepctl(ep_addr.index()).read().stall() }, 996 Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
764 Direction::In => unsafe { regs.diepctl(ep_addr.index()).read().stall() }, 997 Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
765 } 998 }
766 } 999 }
767 1000
@@ -777,8 +1010,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
777 let r = T::regs(); 1010 let r = T::regs();
778 match ep_addr.direction() { 1011 match ep_addr.direction() {
779 Direction::Out => { 1012 Direction::Out => {
780 // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW 1013 critical_section::with(|_| {
781 critical_section::with(|_| unsafe {
782 // cancel transfer if active 1014 // cancel transfer if active
783 if !enabled && r.doepctl(ep_addr.index()).read().epena() { 1015 if !enabled && r.doepctl(ep_addr.index()).read().epena() {
784 r.doepctl(ep_addr.index()).modify(|w| { 1016 r.doepctl(ep_addr.index()).modify(|w| {
@@ -789,25 +1021,37 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
789 1021
790 r.doepctl(ep_addr.index()).modify(|w| { 1022 r.doepctl(ep_addr.index()).modify(|w| {
791 w.set_usbaep(enabled); 1023 w.set_usbaep(enabled);
792 }) 1024 });
1025
1026 // Flush tx fifo
1027 r.grstctl().write(|w| {
1028 w.set_txfflsh(true);
1029 w.set_txfnum(ep_addr.index() as _);
1030 });
1031 loop {
1032 let x = r.grstctl().read();
1033 if !x.txfflsh() {
1034 break;
1035 }
1036 }
793 }); 1037 });
794 1038
795 // Wake `Endpoint::wait_enabled()` 1039 // Wake `Endpoint::wait_enabled()`
796 T::state().ep_out_wakers[ep_addr.index()].wake(); 1040 T::state().ep_out_wakers[ep_addr.index()].wake();
797 } 1041 }
798 Direction::In => { 1042 Direction::In => {
799 // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW 1043 critical_section::with(|_| {
800 critical_section::with(|_| unsafe {
801 // cancel transfer if active 1044 // cancel transfer if active
802 if !enabled && r.diepctl(ep_addr.index()).read().epena() { 1045 if !enabled && r.diepctl(ep_addr.index()).read().epena() {
803 r.diepctl(ep_addr.index()).modify(|w| { 1046 r.diepctl(ep_addr.index()).modify(|w| {
804 w.set_snak(true); 1047 w.set_snak(true); // set NAK
805 w.set_epdis(true); 1048 w.set_epdis(true);
806 }) 1049 })
807 } 1050 }
808 1051
809 r.diepctl(ep_addr.index()).modify(|w| { 1052 r.diepctl(ep_addr.index()).modify(|w| {
810 w.set_usbaep(enabled); 1053 w.set_usbaep(enabled);
1054 w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
811 }) 1055 })
812 }); 1056 });
813 1057
@@ -819,206 +1063,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
819 1063
820 async fn enable(&mut self) { 1064 async fn enable(&mut self) {
821 trace!("enable"); 1065 trace!("enable");
822 1066 // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
823 // SAFETY: registers are only accessed by `Bus` under `&mut self`
824 unsafe {
825 #[cfg(stm32l4)]
826 {
827 crate::peripherals::PWR::enable();
828 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
829 }
830
831 #[cfg(stm32f7)]
832 {
833 // Enable ULPI clock if external PHY is used
834 let ulpien = !self.phy_type.internal();
835 critical_section::with(|_| {
836 crate::pac::RCC.ahb1enr().modify(|w| {
837 if T::HIGH_SPEED {
838 w.set_usb_otg_hsulpien(ulpien);
839 } else {
840 w.set_usb_otg_hsen(ulpien);
841 }
842 });
843
844 // Low power mode
845 crate::pac::RCC.ahb1lpenr().modify(|w| {
846 if T::HIGH_SPEED {
847 w.set_usb_otg_hsulpilpen(ulpien);
848 } else {
849 w.set_usb_otg_hslpen(ulpien);
850 }
851 });
852 });
853 }
854
855 #[cfg(stm32h7)]
856 {
857 // If true, VDD33USB is generated by internal regulator from VDD50USB
858 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
859 // TODO: unhardcode
860 let internal_regulator = false;
861
862 // Enable USB power
863 critical_section::with(|_| {
864 crate::pac::PWR.cr3().modify(|w| {
865 w.set_usb33den(true);
866 w.set_usbregen(internal_regulator);
867 })
868 });
869
870 // Wait for USB power to stabilize
871 while !crate::pac::PWR.cr3().read().usb33rdy() {}
872
873 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
874 critical_section::with(|_| {
875 crate::pac::RCC
876 .d2ccip2r()
877 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
878 });
879
880 // Enable ULPI clock if external PHY is used
881 let ulpien = !self.phy_type.internal();
882 critical_section::with(|_| {
883 crate::pac::RCC.ahb1enr().modify(|w| {
884 if T::HIGH_SPEED {
885 w.set_usb_otg_hs_ulpien(ulpien);
886 } else {
887 w.set_usb_otg_fs_ulpien(ulpien);
888 }
889 });
890 crate::pac::RCC.ahb1lpenr().modify(|w| {
891 if T::HIGH_SPEED {
892 w.set_usb_otg_hs_ulpilpen(ulpien);
893 } else {
894 w.set_usb_otg_fs_ulpilpen(ulpien);
895 }
896 });
897 });
898 }
899
900 #[cfg(stm32u5)]
901 {
902 // Enable USB power
903 critical_section::with(|_| {
904 crate::pac::RCC.ahb3enr().modify(|w| {
905 w.set_pwren(true);
906 });
907 cortex_m::asm::delay(2);
908
909 crate::pac::PWR.svmcr().modify(|w| {
910 w.set_usv(true);
911 w.set_uvmen(true);
912 });
913 });
914
915 // Wait for USB power to stabilize
916 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
917
918 // Select HSI48 as USB clock source.
919 critical_section::with(|_| {
920 crate::pac::RCC.ccipr1().modify(|w| {
921 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
922 })
923 });
924 }
925
926 <T as RccPeripheral>::enable();
927 <T as RccPeripheral>::reset();
928
929 T::Interrupt::unpend();
930 T::Interrupt::enable();
931
932 let r = T::regs();
933 let core_id = r.cid().read().0;
934 info!("Core id {:08x}", core_id);
935
936 // Wait for AHB ready.
937 while !r.grstctl().read().ahbidl() {}
938
939 // Configure as device.
940 r.gusbcfg().write(|w| {
941 // Force device mode
942 w.set_fdmod(true);
943 // Enable internal full-speed PHY
944 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
945 });
946
947 // Configuring Vbus sense and SOF output
948 match core_id {
949 0x0000_1200 | 0x0000_1100 => {
950 assert!(self.phy_type != PhyType::InternalHighSpeed);
951
952 r.gccfg_v1().modify(|w| {
953 // Enable internal full-speed PHY, logic is inverted
954 w.set_pwrdwn(self.phy_type.internal());
955 });
956
957 // F429-like chips have the GCCFG.NOVBUSSENS bit
958 r.gccfg_v1().modify(|w| {
959 w.set_novbussens(true);
960 w.set_vbusasen(false);
961 w.set_vbusbsen(false);
962 w.set_sofouten(false);
963 });
964 }
965 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
966 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
967 r.gccfg_v2().modify(|w| {
968 // Enable internal full-speed PHY, logic is inverted
969 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
970 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
971 });
972
973 r.gccfg_v2().modify(|w| {
974 w.set_vbden(false);
975 });
976
977 // Force B-peripheral session
978 r.gotgctl().modify(|w| {
979 w.set_bvaloen(true);
980 w.set_bvaloval(true);
981 });
982 }
983 _ => unimplemented!("Unknown USB core id {:X}", core_id),
984 }
985
986 // Soft disconnect.
987 r.dctl().write(|w| w.set_sdis(true));
988
989 // Set speed.
990 r.dcfg().write(|w| {
991 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
992 w.set_dspd(self.phy_type.to_dspd());
993 });
994
995 // Unmask transfer complete EP interrupt
996 r.diepmsk().write(|w| {
997 w.set_xfrcm(true);
998 });
999
1000 // Unmask and clear core interrupts
1001 Bus::<T>::restore_irqs();
1002 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
1003
1004 // Unmask global interrupt
1005 r.gahbcfg().write(|w| {
1006 w.set_gint(true); // unmask global interrupt
1007 });
1008
1009 // Connect
1010 r.dctl().write(|w| w.set_sdis(false));
1011 }
1012
1013 self.enabled = true;
1014 } 1067 }
1015 1068
1016 async fn disable(&mut self) { 1069 async fn disable(&mut self) {
1017 trace!("disable"); 1070 trace!("disable");
1018 1071
1019 Bus::disable(self); 1072 // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
1020 1073 //Bus::disable(self);
1021 self.enabled = false;
1022 } 1074 }
1023 1075
1024 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { 1076 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
@@ -1066,8 +1118,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> {
1066 1118
1067 T::state().ep_in_wakers[ep_index].register(cx.waker()); 1119 T::state().ep_in_wakers[ep_index].register(cx.waker());
1068 1120
1069 // SAFETY: atomic read without side effects 1121 if T::regs().diepctl(ep_index).read().usbaep() {
1070 if unsafe { T::regs().diepctl(ep_index).read().usbaep() } {
1071 Poll::Ready(()) 1122 Poll::Ready(())
1072 } else { 1123 } else {
1073 Poll::Pending 1124 Poll::Pending
@@ -1088,8 +1139,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> {
1088 1139
1089 T::state().ep_out_wakers[ep_index].register(cx.waker()); 1140 T::state().ep_out_wakers[ep_index].register(cx.waker());
1090 1141
1091 // SAFETY: atomic read without side effects 1142 if T::regs().doepctl(ep_index).read().usbaep() {
1092 if unsafe { T::regs().doepctl(ep_index).read().usbaep() } {
1093 Poll::Ready(()) 1143 Poll::Ready(())
1094 } else { 1144 } else {
1095 Poll::Pending 1145 Poll::Pending
@@ -1124,8 +1174,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
1124 // Release buffer 1174 // Release buffer
1125 state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release); 1175 state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
1126 1176
1127 // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Bus` so a critical section is needed for RMW 1177 critical_section::with(|_| {
1128 critical_section::with(|_| unsafe {
1129 // Receive 1 packet 1178 // Receive 1 packet
1130 T::regs().doeptsiz(index).modify(|w| { 1179 T::regs().doeptsiz(index).modify(|w| {
1131 w.set_xfrsiz(self.info.max_packet_size as _); 1180 w.set_xfrsiz(self.info.max_packet_size as _);
@@ -1163,13 +1212,17 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1163 poll_fn(|cx| { 1212 poll_fn(|cx| {
1164 state.ep_in_wakers[index].register(cx.waker()); 1213 state.ep_in_wakers[index].register(cx.waker());
1165 1214
1166 // SAFETY: atomic read with no side effects 1215 let diepctl = r.diepctl(index).read();
1167 let diepctl = unsafe { r.diepctl(index).read() }; 1216 let dtxfsts = r.dtxfsts(index).read();
1217 info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0);
1168 if !diepctl.usbaep() { 1218 if !diepctl.usbaep() {
1219 trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
1169 Poll::Ready(Err(EndpointError::Disabled)) 1220 Poll::Ready(Err(EndpointError::Disabled))
1170 } else if !diepctl.epena() { 1221 } else if !diepctl.epena() {
1222 trace!("write ep={:?} wait for prev: ready", self.info.addr);
1171 Poll::Ready(Ok(())) 1223 Poll::Ready(Ok(()))
1172 } else { 1224 } else {
1225 trace!("write ep={:?} wait for prev: pending", self.info.addr);
1173 Poll::Pending 1226 Poll::Pending
1174 } 1227 }
1175 }) 1228 })
@@ -1181,12 +1234,10 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1181 1234
1182 let size_words = (buf.len() + 3) / 4; 1235 let size_words = (buf.len() + 3) / 4;
1183 1236
1184 // SAFETY: atomic read with no side effects 1237 let fifo_space = r.dtxfsts(index).read().ineptfsav() as usize;
1185 let fifo_space = unsafe { r.dtxfsts(index).read().ineptfsav() as usize };
1186 if size_words > fifo_space { 1238 if size_words > fifo_space {
1187 // Not enough space in fifo, enable tx fifo empty interrupt 1239 // Not enough space in fifo, enable tx fifo empty interrupt
1188 // SAFETY: DIEPEMPMSK is shared with IRQ so critical section is needed for RMW 1240 critical_section::with(|_| {
1189 critical_section::with(|_| unsafe {
1190 r.diepempmsk().modify(|w| { 1241 r.diepempmsk().modify(|w| {
1191 w.set_ineptxfem(w.ineptxfem() | (1 << index)); 1242 w.set_ineptxfem(w.ineptxfem() | (1 << index));
1192 }); 1243 });
@@ -1196,24 +1247,21 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1196 1247
1197 Poll::Pending 1248 Poll::Pending
1198 } else { 1249 } else {
1250 trace!("write ep={:?} wait for fifo: ready", self.info.addr);
1199 Poll::Ready(()) 1251 Poll::Ready(())
1200 } 1252 }
1201 }) 1253 })
1202 .await 1254 .await
1203 } 1255 }
1204 1256
1205 // SAFETY: DIEPTSIZ is exclusive to this endpoint under `&mut self` 1257 // Setup transfer size
1206 unsafe { 1258 r.dieptsiz(index).write(|w| {
1207 // Setup transfer size 1259 w.set_mcnt(1);
1208 r.dieptsiz(index).write(|w| { 1260 w.set_pktcnt(1);
1209 w.set_mcnt(1); 1261 w.set_xfrsiz(buf.len() as _);
1210 w.set_pktcnt(1); 1262 });
1211 w.set_xfrsiz(buf.len() as _);
1212 });
1213 }
1214 1263
1215 // SAFETY: DIEPCTL is shared with `Bus` so a critical section is needed for RMW 1264 critical_section::with(|_| {
1216 critical_section::with(|_| unsafe {
1217 // Enable endpoint 1265 // Enable endpoint
1218 r.diepctl(index).modify(|w| { 1266 r.diepctl(index).modify(|w| {
1219 w.set_cnak(true); 1267 w.set_cnak(true);
@@ -1225,8 +1273,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1225 for chunk in buf.chunks(4) { 1273 for chunk in buf.chunks(4) {
1226 let mut tmp = [0u8; 4]; 1274 let mut tmp = [0u8; 4];
1227 tmp[0..chunk.len()].copy_from_slice(chunk); 1275 tmp[0..chunk.len()].copy_from_slice(chunk);
1228 // SAFETY: FIFO is exclusive to this endpoint under `&mut self` 1276 r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
1229 unsafe { r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))) };
1230 } 1277 }
1231 1278
1232 trace!("write done ep={:?}", self.info.addr); 1279 trace!("write done ep={:?}", self.info.addr);
@@ -1258,17 +1305,15 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
1258 state.ep0_setup_ready.store(false, Ordering::Release); 1305 state.ep0_setup_ready.store(false, Ordering::Release);
1259 1306
1260 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section 1307 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1261 unsafe { 1308 // Receive 1 SETUP packet
1262 // Receive 1 SETUP packet 1309 T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
1263 T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| { 1310 w.set_rxdpid_stupcnt(1);
1264 w.set_rxdpid_stupcnt(1); 1311 });
1265 });
1266 1312
1267 // Clear NAK to indicate we are ready to receive more data 1313 // Clear NAK to indicate we are ready to receive more data
1268 T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| { 1314 T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| {
1269 w.set_cnak(true); 1315 w.set_cnak(true);
1270 }); 1316 });
1271 }
1272 1317
1273 trace!("SETUP received: {:?}", data); 1318 trace!("SETUP received: {:?}", data);
1274 Poll::Ready(data) 1319 Poll::Ready(data)
@@ -1313,20 +1358,18 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
1313 trace!("control: reject"); 1358 trace!("control: reject");
1314 1359
1315 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section 1360 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1316 unsafe { 1361 let regs = T::regs();
1317 let regs = T::regs(); 1362 regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
1318 regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { 1363 w.set_stall(true);
1319 w.set_stall(true); 1364 });
1320 }); 1365 regs.doepctl(self.ep_out.info.addr.index()).modify(|w| {
1321 regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { 1366 w.set_stall(true);
1322 w.set_stall(true); 1367 });
1323 });
1324 }
1325 } 1368 }
1326 1369
1327 async fn accept_set_address(&mut self, addr: u8) { 1370 async fn accept_set_address(&mut self, addr: u8) {
1328 trace!("setting addr: {}", addr); 1371 trace!("setting addr: {}", addr);
1329 critical_section::with(|_| unsafe { 1372 critical_section::with(|_| {
1330 T::regs().dcfg().modify(|w| { 1373 T::regs().dcfg().modify(|w| {
1331 w.set_dad(addr); 1374 w.set_dad(addr);
1332 }); 1375 });
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index 18ebf97d8..b03e81d6e 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -48,11 +48,9 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
48 let rl = reload_value(psc, timeout_us); 48 let rl = reload_value(psc, timeout_us);
49 49
50 let wdg = T::regs(); 50 let wdg = T::regs();
51 unsafe { 51 wdg.kr().write(|w| w.set_key(Key::ENABLE));
52 wdg.kr().write(|w| w.set_key(Key::ENABLE)); 52 wdg.pr().write(|w| w.set_pr(Pr::from_bits(pr)));
53 wdg.pr().write(|w| w.set_pr(Pr(pr))); 53 wdg.rlr().write(|w| w.set_rl(rl));
54 wdg.rlr().write(|w| w.set_rl(rl));
55 }
56 54
57 trace!( 55 trace!(
58 "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})", 56 "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})",
@@ -67,11 +65,11 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
67 } 65 }
68 } 66 }
69 67
70 pub unsafe fn unleash(&mut self) { 68 pub fn unleash(&mut self) {
71 T::regs().kr().write(|w| w.set_key(Key::START)); 69 T::regs().kr().write(|w| w.set_key(Key::START));
72 } 70 }
73 71
74 pub unsafe fn pet(&mut self) { 72 pub fn pet(&mut self) {
75 T::regs().kr().write(|w| w.set_key(Key::RESET)); 73 T::regs().kr().write(|w| w.set_key(Key::RESET));
76 } 74 }
77} 75}
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs
index f8bb0a035..066970813 100644
--- a/embassy-sync/src/fmt.rs
+++ b/embassy-sync/src/fmt.rs
@@ -195,9 +195,6 @@ macro_rules! unwrap {
195 } 195 }
196} 196}
197 197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)] 198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError; 199pub struct NoneError;
203 200
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index db6ebb08b..13bf4ef01 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -282,7 +282,7 @@ where
282 /// returns the amount of bytes written. 282 /// returns the amount of bytes written.
283 /// 283 ///
284 /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full, 284 /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full,
285 /// this method will wait until it is. See [`try_write`](Self::try_write) for a variant that 285 /// this method will wait until it isn't. See [`try_write`](Self::try_write) for a variant that
286 /// returns an error instead of waiting. 286 /// returns an error instead of waiting.
287 /// 287 ///
288 /// It is not guaranteed that all bytes in the buffer are written, even if there's enough 288 /// It is not guaranteed that all bytes in the buffer are written, even if there's enough
@@ -319,7 +319,7 @@ where
319 /// returns the amount of bytes read. 319 /// returns the amount of bytes read.
320 /// 320 ///
321 /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty, 321 /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty,
322 /// this method will wait until it is. See [`try_read`](Self::try_read) for a variant that 322 /// this method will wait until it isn't. See [`try_read`](Self::try_read) for a variant that
323 /// returns an error instead of waiting. 323 /// returns an error instead of waiting.
324 /// 324 ///
325 /// It is not guaranteed that all bytes in the buffer are read, even if there's enough 325 /// It is not guaranteed that all bytes in the buffer are read, even if there's enough
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
index 1d8dd13ce..6e50c40ba 100644
--- a/embassy-usb-logger/src/lib.rs
+++ b/embassy-usb-logger/src/lib.rs
@@ -138,7 +138,7 @@ macro_rules! run {
138 ( $x:expr, $l:expr, $p:ident ) => { 138 ( $x:expr, $l:expr, $p:ident ) => {
139 static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); 139 static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new();
140 unsafe { 140 unsafe {
141 let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level($l)); 141 let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l));
142 } 142 }
143 let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; 143 let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await;
144 }; 144 };
diff --git a/embassy-usb/src/class/cdc_ncm/embassy_net.rs b/embassy-usb/src/class/cdc_ncm/embassy_net.rs
index bc79b3671..670709021 100644
--- a/embassy-usb/src/class/cdc_ncm/embassy_net.rs
+++ b/embassy-usb/src/class/cdc_ncm/embassy_net.rs
@@ -1,4 +1,5 @@
1//! [`embassy-net`](crates.io/crates/embassy-net) driver for the CDC-NCM class. 1//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the CDC-NCM class.
2
2use embassy_futures::select::{select, Either}; 3use embassy_futures::select::{select, Either};
3use embassy_net_driver_channel as ch; 4use embassy_net_driver_channel as ch;
4use embassy_net_driver_channel::driver::LinkState; 5use embassy_net_driver_channel::driver::LinkState;
@@ -79,7 +80,7 @@ impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> {
79pub type Device<'d, const MTU: usize> = embassy_net_driver_channel::Device<'d, MTU>; 80pub type Device<'d, const MTU: usize> = embassy_net_driver_channel::Device<'d, MTU>;
80 81
81impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { 82impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
82 /// Obtain a driver for using the CDC-NCM class with [`embassy-net`](crates.io/crates/embassy-net). 83 /// Obtain a driver for using the CDC-NCM class with [`embassy-net`](https://crates.io/crates/embassy-net).
83 pub fn into_embassy_net_device<const MTU: usize, const N_RX: usize, const N_TX: usize>( 84 pub fn into_embassy_net_device<const MTU: usize, const N_RX: usize, const N_TX: usize>(
84 self, 85 self,
85 state: &'d mut State<MTU, N_RX, N_TX>, 86 state: &'d mut State<MTU, N_RX, N_TX>,
diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs
index d5556dd0b..fcfa0bfcd 100644
--- a/embassy-usb/src/class/cdc_ncm/mod.rs
+++ b/embassy-usb/src/class/cdc_ncm/mod.rs
@@ -11,8 +11,8 @@
11//! - On Pixel 4a, it refused to work on Android 11, worked on Android 12. 11//! - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
12//! - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), 12//! - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
13//! it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. 13//! it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
14//! This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417 14//! This is due to regex spaghetti: <https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417>
15//! and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 15//! and this nonsense in the linux kernel: <https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757>
16 16
17use core::intrinsics::copy_nonoverlapping; 17use core::intrinsics::copy_nonoverlapping;
18use core::mem::{size_of, MaybeUninit}; 18use core::mem::{size_of, MaybeUninit};
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index d8563d59a..1180b9b66 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -23,7 +23,7 @@ mod config {
23use embassy_futures::select::{select, Either}; 23use embassy_futures::select::{select, Either};
24use heapless::Vec; 24use heapless::Vec;
25 25
26pub use crate::builder::{Builder, Config}; 26pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder};
27use crate::config::*; 27use crate::config::*;
28use crate::control::*; 28use crate::control::*;
29use crate::descriptor::*; 29use crate::descriptor::*;
diff --git a/examples/boot/application/nrf/.cargo/config.toml b/examples/boot/application/nrf/.cargo/config.toml
index 3872e7189..17616a054 100644
--- a/examples/boot/application/nrf/.cargo/config.toml
+++ b/examples/boot/application/nrf/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 5939a43b1..b98f73f39 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -24,3 +24,4 @@ cortex-m-rt = "0.7.0"
24[features] 24[features]
25ed25519-dalek = ["embassy-boot/ed25519-dalek"] 25ed25519-dalek = ["embassy-boot/ed25519-dalek"]
26ed25519-salty = ["embassy-boot/ed25519-salty"] 26ed25519-salty = ["embassy-boot/ed25519-salty"]
27skip-include = []
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index 06c237781..021d77f3b 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -12,6 +12,9 @@ use embassy_nrf::wdt::{self, Watchdog};
12use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
13use panic_reset as _; 13use panic_reset as _;
14 14
15#[cfg(feature = "skip-include")]
16static APP_B: &[u8] = &[0, 1, 2, 3];
17#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 18static APP_B: &[u8] = include_bytes!("../../b.bin");
16 19
17#[embassy_executor::main] 20#[embassy_executor::main]
@@ -55,13 +58,13 @@ async fn main(_spawner: Spawner) {
55 button.wait_for_any_edge().await; 58 button.wait_for_any_edge().await;
56 if button.is_low() { 59 if button.is_low() {
57 let mut offset = 0; 60 let mut offset = 0;
61 let mut magic = [0; 4];
58 for chunk in APP_B.chunks(4096) { 62 for chunk in APP_B.chunks(4096) {
59 let mut buf: [u8; 4096] = [0; 4096]; 63 let mut buf: [u8; 4096] = [0; 4096];
60 buf[..chunk.len()].copy_from_slice(chunk); 64 buf[..chunk.len()].copy_from_slice(chunk);
61 updater.write_firmware(offset, &buf).await.unwrap(); 65 updater.write_firmware(&mut magic, offset, &buf).await.unwrap();
62 offset += chunk.len(); 66 offset += chunk.len();
63 } 67 }
64 let mut magic = [0; 4];
65 updater.mark_updated(&mut magic).await.unwrap(); 68 updater.mark_updated(&mut magic).await.unwrap();
66 led.set_high(); 69 led.set_high();
67 cortex_m::peripheral::SCB::sys_reset(); 70 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/application/rp/.cargo/config.toml b/examples/boot/application/rp/.cargo/config.toml
index 278c24a57..cd8d1ef02 100644
--- a/examples/boot/application/rp/.cargo/config.toml
+++ b/examples/boot/application/rp/.cargo/config.toml
@@ -3,7 +3,7 @@ build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "probe-rs-cli run --chip RP2040" 6runner = "probe-rs run --chip RP2040"
7 7
8[build] 8[build]
9target = "thumbv6m-none-eabi" 9target = "thumbv6m-none-eabi"
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
index 4a2c5dd8f..007b6839c 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -29,6 +29,7 @@ debug = [
29 "embassy-boot-rp/defmt", 29 "embassy-boot-rp/defmt",
30 "panic-probe" 30 "panic-probe"
31] 31]
32skip-include = []
32 33
33[profile.release] 34[profile.release]
34debug = true 35debug = true
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index 69850069b..c8497494c 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -18,7 +18,11 @@ use panic_probe as _;
18#[cfg(feature = "panic-reset")] 18#[cfg(feature = "panic-reset")]
19use panic_reset as _; 19use panic_reset as _;
20 20
21#[cfg(feature = "skip-include")]
22static APP_B: &[u8] = &[0, 1, 2, 3];
23#[cfg(not(feature = "skip-include"))]
21static APP_B: &[u8] = include_bytes!("../../b.bin"); 24static APP_B: &[u8] = include_bytes!("../../b.bin");
25
22const FLASH_SIZE: usize = 2 * 1024 * 1024; 26const FLASH_SIZE: usize = 2 * 1024 * 1024;
23 27
24#[embassy_executor::main] 28#[embassy_executor::main]
@@ -43,7 +47,7 @@ async fn main(_s: Spawner) {
43 let mut buf: AlignedBuffer<4096> = AlignedBuffer([0; 4096]); 47 let mut buf: AlignedBuffer<4096> = AlignedBuffer([0; 4096]);
44 defmt::info!("preparing update"); 48 defmt::info!("preparing update");
45 let writer = updater 49 let writer = updater
46 .prepare_update() 50 .prepare_update(&mut buf.0[..1])
47 .map_err(|e| defmt::warn!("E: {:?}", defmt::Debug2Format(&e))) 51 .map_err(|e| defmt::warn!("E: {:?}", defmt::Debug2Format(&e)))
48 .unwrap(); 52 .unwrap();
49 defmt::info!("writer created, starting write"); 53 defmt::info!("writer created, starting write");
diff --git a/examples/boot/application/stm32f3/.cargo/config.toml b/examples/boot/application/stm32f3/.cargo/config.toml
index 9fc2396e8..4a7ec0a5b 100644
--- a/examples/boot/application/stm32f3/.cargo/config.toml
+++ b/examples/boot/application/stm32f3/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F303VCTx" 3runner = "probe-rs run --chip STM32F303VCTx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 24abd90d4..5b3faf8f8 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -26,3 +26,4 @@ defmt = [
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index c94676f09..c0a11d699 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -13,6 +13,9 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex; 13use embassy_sync::mutex::Mutex;
14use panic_reset as _; 14use panic_reset as _;
15 15
16#[cfg(feature = "skip-include")]
17static APP_B: &[u8] = &[0, 1, 2, 3];
18#[cfg(not(feature = "skip-include"))]
16static APP_B: &[u8] = include_bytes!("../../b.bin"); 19static APP_B: &[u8] = include_bytes!("../../b.bin");
17 20
18#[embassy_executor::main] 21#[embassy_executor::main]
@@ -31,13 +34,13 @@ async fn main(_spawner: Spawner) {
31 let mut updater = FirmwareUpdater::new(config); 34 let mut updater = FirmwareUpdater::new(config);
32 button.wait_for_falling_edge().await; 35 button.wait_for_falling_edge().await;
33 let mut offset = 0; 36 let mut offset = 0;
37 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
34 for chunk in APP_B.chunks(2048) { 38 for chunk in APP_B.chunks(2048) {
35 let mut buf: [u8; 2048] = [0; 2048]; 39 let mut buf: [u8; 2048] = [0; 2048];
36 buf[..chunk.len()].copy_from_slice(chunk); 40 buf[..chunk.len()].copy_from_slice(chunk);
37 updater.write_firmware(offset, &buf).await.unwrap(); 41 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
38 offset += chunk.len(); 42 offset += chunk.len();
39 } 43 }
40 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
41 updater.mark_updated(magic.as_mut()).await.unwrap(); 44 updater.mark_updated(magic.as_mut()).await.unwrap();
42 led.set_low(); 45 led.set_low();
43 cortex_m::peripheral::SCB::sys_reset(); 46 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/application/stm32f7/.cargo/config.toml b/examples/boot/application/stm32f7/.cargo/config.toml
index 7d6c88a99..9088eea6e 100644
--- a/examples/boot/application/stm32f7/.cargo/config.toml
+++ b/examples/boot/application/stm32f7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F767ZITx" 3runner = "probe-rs run --chip STM32F767ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 529a01aad..b6a6f9cd8 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -16,6 +16,7 @@ defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19embedded-storage = "0.3.0"
19 20
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
@@ -26,3 +27,4 @@ defmt = [
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28] 29]
30skip-include = []
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index fc2702c91..dea682a96 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -2,6 +2,8 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::cell::RefCell;
6
5#[cfg(feature = "defmt-rtt")] 7#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 8use defmt_rtt::*;
7use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; 9use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
@@ -9,8 +11,13 @@ 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::{Input, Level, Output, Pull, Speed}; 13use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
14use embassy_sync::blocking_mutex::Mutex;
15use embedded_storage::nor_flash::NorFlash;
12use panic_reset as _; 16use panic_reset as _;
13 17
18#[cfg(feature = "skip-include")]
19static APP_B: &[u8] = &[0, 1, 2, 3];
20#[cfg(not(feature = "skip-include"))]
14static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
15 22
16#[embassy_executor::main] 23#[embassy_executor::main]
@@ -27,16 +34,16 @@ async fn main(_spawner: Spawner) {
27 34
28 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 35 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
29 let mut updater = BlockingFirmwareUpdater::new(config); 36 let mut updater = BlockingFirmwareUpdater::new(config);
30 let mut writer = updater.prepare_update().unwrap(); 37 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
38 let writer = updater.prepare_update(magic.as_mut()).unwrap();
31 button.wait_for_rising_edge().await; 39 button.wait_for_rising_edge().await;
32 let mut offset = 0; 40 let mut offset = 0;
33 let mut buf = AlignedBuffer([0; 4096]); 41 let mut buf = AlignedBuffer([0; 4096]);
34 for chunk in APP_B.chunks(4096) { 42 for chunk in APP_B.chunks(4096) {
35 buf.as_mut()[..chunk.len()].copy_from_slice(chunk); 43 buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
36 writer.write(offset, buf.as_ref()).unwrap(); 44 writer.write(offset, buf.as_ref()).unwrap();
37 offset += chunk.len(); 45 offset += chunk.len() as u32;
38 } 46 }
39 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
40 updater.mark_updated(magic.as_mut()).unwrap(); 47 updater.mark_updated(magic.as_mut()).unwrap();
41 led.set_low(); 48 led.set_low();
42 cortex_m::peripheral::SCB::sys_reset(); 49 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/application/stm32h7/.cargo/config.toml b/examples/boot/application/stm32h7/.cargo/config.toml
index 067a5c89b..caa0d3a93 100644
--- a/examples/boot/application/stm32h7/.cargo/config.toml
+++ b/examples/boot/application/stm32h7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32H743ZITx" 3runner = "probe-rs run --chip STM32H743ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index d7539a53f..0a7e19b1d 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -16,6 +16,7 @@ defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19embedded-storage = "0.3.0"
19 20
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
@@ -26,3 +27,4 @@ defmt = [
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28] 29]
30skip-include = []
diff --git a/examples/boot/application/stm32h7/flash-boot.sh b/examples/boot/application/stm32h7/flash-boot.sh
index a3003681a..4912a50b7 100755
--- a/examples/boot/application/stm32h7/flash-boot.sh
+++ b/examples/boot/application/stm32h7/flash-boot.sh
@@ -1,5 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2probe-rs-cli erase --chip STM32H743ZITx 2probe-rs erase --chip STM32H743ZITx
3mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x 3mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x
4cp memory-bl.x ../../bootloader/stm32/memory.x 4cp memory-bl.x ../../bootloader/stm32/memory.x
5 5
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index 1a54464d0..719176692 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -2,6 +2,8 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::cell::RefCell;
6
5#[cfg(feature = "defmt-rtt")] 7#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 8use defmt_rtt::*;
7use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; 9use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
@@ -9,8 +11,13 @@ 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::{Input, Level, Output, Pull, Speed}; 13use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
14use embassy_sync::blocking_mutex::Mutex;
15use embedded_storage::nor_flash::NorFlash;
12use panic_reset as _; 16use panic_reset as _;
13 17
18#[cfg(feature = "skip-include")]
19static APP_B: &[u8] = &[0, 1, 2, 3];
20#[cfg(not(feature = "skip-include"))]
14static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
15 22
16#[embassy_executor::main] 23#[embassy_executor::main]
@@ -26,17 +33,17 @@ async fn main(_spawner: Spawner) {
26 led.set_high(); 33 led.set_high();
27 34
28 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 35 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
36 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
29 let mut updater = BlockingFirmwareUpdater::new(config); 37 let mut updater = BlockingFirmwareUpdater::new(config);
30 let mut writer = updater.prepare_update().unwrap(); 38 let writer = updater.prepare_update(magic.as_mut()).unwrap();
31 button.wait_for_rising_edge().await; 39 button.wait_for_rising_edge().await;
32 let mut offset = 0; 40 let mut offset = 0;
33 let mut buf = AlignedBuffer([0; 4096]); 41 let mut buf = AlignedBuffer([0; 4096]);
34 for chunk in APP_B.chunks(4096) { 42 for chunk in APP_B.chunks(4096) {
35 buf.as_mut()[..chunk.len()].copy_from_slice(chunk); 43 buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
36 writer.write(offset, buf.as_ref()).unwrap(); 44 writer.write(offset, buf.as_ref()).unwrap();
37 offset += chunk.len(); 45 offset += chunk.len() as u32;
38 } 46 }
39 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
40 updater.mark_updated(magic.as_mut()).unwrap(); 47 updater.mark_updated(magic.as_mut()).unwrap();
41 led.set_low(); 48 led.set_low();
42 cortex_m::peripheral::SCB::sys_reset(); 49 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/application/stm32l0/.cargo/config.toml b/examples/boot/application/stm32l0/.cargo/config.toml
index ce0e460bd..6099f015c 100644
--- a/examples/boot/application/stm32l0/.cargo/config.toml
+++ b/examples/boot/application/stm32l0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L072CZTx" 3runner = "probe-rs run --chip STM32L072CZTx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index e90da259b..998df4dc0 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -26,3 +26,4 @@ defmt = [
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index 4033ac590..ce80056e6 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -4,22 +4,26 @@
4 4
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
14use panic_reset as _; 15use panic_reset as _;
15 16
17#[cfg(feature = "skip-include")]
18static APP_B: &[u8] = &[0, 1, 2, 3];
19#[cfg(not(feature = "skip-include"))]
16static APP_B: &[u8] = include_bytes!("../../b.bin"); 20static APP_B: &[u8] = include_bytes!("../../b.bin");
17 21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
20 let p = embassy_stm32::init(Default::default()); 24 let p = embassy_stm32::init(Default::default());
21 let flash = Flash::new_blocking(p.FLASH); 25 let flash = Flash::new_blocking(p.FLASH);
22 let mut flash = BlockingAsync::new(flash); 26 let flash = Mutex::new(BlockingAsync::new(flash));
23 27
24 let button = Input::new(p.PB2, Pull::Up); 28 let button = Input::new(p.PB2, Pull::Up);
25 let mut button = ExtiInput::new(button, p.EXTI2); 29 let mut button = ExtiInput::new(button, p.EXTI2);
@@ -28,18 +32,19 @@ async fn main(_spawner: Spawner) {
28 32
29 led.set_high(); 33 led.set_high();
30 34
31 let mut updater = FirmwareUpdater::default(); 35 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
36 let mut updater = FirmwareUpdater::new(config);
32 button.wait_for_falling_edge().await; 37 button.wait_for_falling_edge().await;
33 let mut offset = 0; 38 let mut offset = 0;
39 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
34 for chunk in APP_B.chunks(128) { 40 for chunk in APP_B.chunks(128) {
35 let mut buf: [u8; 128] = [0; 128]; 41 let mut buf: [u8; 128] = [0; 128];
36 buf[..chunk.len()].copy_from_slice(chunk); 42 buf[..chunk.len()].copy_from_slice(chunk);
37 updater.write_firmware(offset, &buf, &mut flash, 128).await.unwrap(); 43 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
38 offset += chunk.len(); 44 offset += chunk.len();
39 } 45 }
40 46
41 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 47 updater.mark_updated(magic.as_mut()).await.unwrap();
42 updater.mark_updated(&mut flash, magic.as_mut()).await.unwrap();
43 led.set_low(); 48 led.set_low();
44 Timer::after(Duration::from_secs(1)).await; 49 Timer::after(Duration::from_secs(1)).await;
45 cortex_m::peripheral::SCB::sys_reset(); 50 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/application/stm32l1/.cargo/config.toml b/examples/boot/application/stm32l1/.cargo/config.toml
index 1401500a0..9cabd14ba 100644
--- a/examples/boot/application/stm32l1/.cargo/config.toml
+++ b/examples/boot/application/stm32l1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L151CBxxA" 3runner = "probe-rs run --chip STM32L151CBxxA"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 8ac0fac85..10b58c172 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -26,3 +26,4 @@ defmt = [
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index 00ddda636..1e9bf3cb9 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -10,9 +10,13 @@ use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
14use panic_reset as _; 15use panic_reset as _;
15 16
17#[cfg(feature = "skip-include")]
18static APP_B: &[u8] = &[0, 1, 2, 3];
19#[cfg(not(feature = "skip-include"))]
16static APP_B: &[u8] = include_bytes!("../../b.bin"); 20static APP_B: &[u8] = include_bytes!("../../b.bin");
17 21
18#[embassy_executor::main] 22#[embassy_executor::main]
@@ -31,15 +35,15 @@ async fn main(_spawner: Spawner) {
31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 35 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
32 let mut updater = FirmwareUpdater::new(config); 36 let mut updater = FirmwareUpdater::new(config);
33 button.wait_for_falling_edge().await; 37 button.wait_for_falling_edge().await;
38 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
34 let mut offset = 0; 39 let mut offset = 0;
35 for chunk in APP_B.chunks(128) { 40 for chunk in APP_B.chunks(128) {
36 let mut buf: [u8; 128] = [0; 128]; 41 let mut buf: [u8; 128] = [0; 128];
37 buf[..chunk.len()].copy_from_slice(chunk); 42 buf[..chunk.len()].copy_from_slice(chunk);
38 updater.write_firmware(offset, &buf).await.unwrap(); 43 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
39 offset += chunk.len(); 44 offset += chunk.len();
40 } 45 }
41 46
42 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
43 updater.mark_updated(magic.as_mut()).await.unwrap(); 47 updater.mark_updated(magic.as_mut()).await.unwrap();
44 led.set_low(); 48 led.set_low();
45 Timer::after(Duration::from_secs(1)).await; 49 Timer::after(Duration::from_secs(1)).await;
diff --git a/examples/boot/application/stm32l4/.cargo/config.toml b/examples/boot/application/stm32l4/.cargo/config.toml
index 48ff3734b..c803215f6 100644
--- a/examples/boot/application/stm32l4/.cargo/config.toml
+++ b/examples/boot/application/stm32l4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L475VG" 3runner = "probe-rs run --chip STM32L475VG"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index ec79acdeb..713a6527e 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -26,3 +26,4 @@ defmt = [
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index 54579e4ac..a514ab5be 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -10,8 +10,12 @@ use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use panic_reset as _; 14use panic_reset as _;
14 15
16#[cfg(feature = "skip-include")]
17static APP_B: &[u8] = &[0, 1, 2, 3];
18#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 19static APP_B: &[u8] = include_bytes!("../../b.bin");
16 20
17#[embassy_executor::main] 21#[embassy_executor::main]
@@ -29,15 +33,15 @@ async fn main(_spawner: Spawner) {
29 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
30 let mut updater = FirmwareUpdater::new(config); 34 let mut updater = FirmwareUpdater::new(config);
31 button.wait_for_falling_edge().await; 35 button.wait_for_falling_edge().await;
36 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
32 let mut offset = 0; 37 let mut offset = 0;
33 for chunk in APP_B.chunks(2048) { 38 for chunk in APP_B.chunks(2048) {
34 let mut buf: [u8; 2048] = [0; 2048]; 39 let mut buf: [u8; 2048] = [0; 2048];
35 buf[..chunk.len()].copy_from_slice(chunk); 40 buf[..chunk.len()].copy_from_slice(chunk);
36 updater.write_firmware(offset, &buf).await.unwrap(); 41 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
37 offset += chunk.len(); 42 offset += chunk.len();
38 } 43 }
39 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 44 updater.mark_updated(magic.as_mut()).await.unwrap();
40 updater.mark_updated(&mut flash, magic.as_mut()).await.unwrap();
41 led.set_low(); 45 led.set_low();
42 cortex_m::peripheral::SCB::sys_reset(); 46 cortex_m::peripheral::SCB::sys_reset();
43} 47}
diff --git a/examples/boot/application/stm32wl/.cargo/config.toml b/examples/boot/application/stm32wl/.cargo/config.toml
index b49b582e0..4f8094ff2 100644
--- a/examples/boot/application/stm32wl/.cargo/config.toml
+++ b/examples/boot/application/stm32wl/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32WLE5JCIx" 3runner = "probe-rs run --chip STM32WLE5JCIx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index dfaece6cf..4c8bbd73f 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -26,3 +26,4 @@ defmt = [
26 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
28] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index 0c6fa05f9..52a197a5c 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -4,21 +4,25 @@
4 4
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use panic_reset as _; 14use panic_reset as _;
14 15
16#[cfg(feature = "skip-include")]
17static APP_B: &[u8] = &[0, 1, 2, 3];
18#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 19static APP_B: &[u8] = include_bytes!("../../b.bin");
16 20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 23 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::new_blocking(p.FLASH); 24 let flash = Flash::new_blocking(p.FLASH);
21 let mut flash = Mutex::new(BlockingAsync::new(flash)); 25 let flash = Mutex::new(BlockingAsync::new(flash));
22 26
23 let button = Input::new(p.PA0, Pull::Up); 27 let button = Input::new(p.PA0, Pull::Up);
24 let mut button = ExtiInput::new(button, p.EXTI0); 28 let mut button = ExtiInput::new(button, p.EXTI0);
@@ -30,15 +34,15 @@ async fn main(_spawner: Spawner) {
30 let mut updater = FirmwareUpdater::new(config); 34 let mut updater = FirmwareUpdater::new(config);
31 button.wait_for_falling_edge().await; 35 button.wait_for_falling_edge().await;
32 //defmt::info!("Starting update"); 36 //defmt::info!("Starting update");
37 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
33 let mut offset = 0; 38 let mut offset = 0;
34 for chunk in APP_B.chunks(2048) { 39 for chunk in APP_B.chunks(2048) {
35 let mut buf: [u8; 2048] = [0; 2048]; 40 let mut buf: [u8; 2048] = [0; 2048];
36 buf[..chunk.len()].copy_from_slice(chunk); 41 buf[..chunk.len()].copy_from_slice(chunk);
37 // defmt::info!("Writing chunk at 0x{:x}", offset); 42 // defmt::info!("Writing chunk at 0x{:x}", offset);
38 updater.write_firmware(offset, &buf).await.unwrap(); 43 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
39 offset += chunk.len(); 44 offset += chunk.len();
40 } 45 }
41 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
42 updater.mark_updated(magic.as_mut()).await.unwrap(); 46 updater.mark_updated(magic.as_mut()).await.unwrap();
43 //defmt::info!("Marked as updated"); 47 //defmt::info!("Marked as updated");
44 led.set_low(); 48 led.set_low();
diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml
index d636b1d23..c292846aa 100644
--- a/examples/boot/bootloader/nrf/.cargo/config.toml
+++ b/examples/boot/bootloader/nrf/.cargo/config.toml
@@ -4,7 +4,7 @@ build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6#runner = "./fruitrunner" 6#runner = "./fruitrunner"
7runner = "probe-rs-cli run --chip nrf52840_xxAA" 7runner = "probe-rs run --chip nrf52840_xxAA"
8 8
9rustflags = [ 9rustflags = [
10 # Code-size optimizations. 10 # Code-size optimizations.
diff --git a/examples/boot/bootloader/rp/.cargo/config.toml b/examples/boot/bootloader/rp/.cargo/config.toml
index 795ee043a..9d48ecdc9 100644
--- a/examples/boot/bootloader/rp/.cargo/config.toml
+++ b/examples/boot/bootloader/rp/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs-cli run --chip RP2040" 2runner = "probe-rs run --chip RP2040"
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" 5target = "thumbv6m-none-eabi"
diff --git a/examples/nrf-rtos-trace/.cargo/config.toml b/examples/nrf-rtos-trace/.cargo/config.toml
index 3872e7189..17616a054 100644
--- a/examples/nrf-rtos-trace/.cargo/config.toml
+++ b/examples/nrf-rtos-trace/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/nrf52840-rtic/.cargo/config.toml b/examples/nrf52840-rtic/.cargo/config.toml
new file mode 100644
index 000000000..17616a054
--- /dev/null
+++ b/examples/nrf52840-rtic/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF52840_xxAA"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
new file mode 100644
index 000000000..0f9048b0f
--- /dev/null
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-nrf52840-rtic-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8rtic = { version = "2", features = ["thumbv7-backend"] }
9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] }
13embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17
18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/nrf52840-rtic/build.rs b/examples/nrf52840-rtic/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf52840-rtic/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf52840-rtic/memory.x b/examples/nrf52840-rtic/memory.x
new file mode 100644
index 000000000..9b04edec0
--- /dev/null
+++ b/examples/nrf52840-rtic/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
5 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
6 RAM : ORIGIN = 0x20000000, LENGTH = 256K
7}
diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs
new file mode 100644
index 000000000..a682c1932
--- /dev/null
+++ b/examples/nrf52840-rtic/src/bin/blinky.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use {defmt_rtt as _, panic_probe as _};
6
7#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [SWI0_EGU0, SWI1_EGU1])]
8mod app {
9 use defmt::info;
10 use embassy_nrf::gpio::{Level, Output, OutputDrive};
11 use embassy_nrf::peripherals;
12 use embassy_time::{Duration, Timer};
13
14 #[shared]
15 struct Shared {}
16
17 #[local]
18 struct Local {}
19
20 #[init]
21 fn init(_: init::Context) -> (Shared, Local) {
22 info!("Hello World!");
23
24 let p = embassy_nrf::init(Default::default());
25 blink::spawn(p.P0_13).map_err(|_| ()).unwrap();
26
27 (Shared {}, Local {})
28 }
29
30 #[task(priority = 1)]
31 async fn blink(_cx: blink::Context, pin: peripherals::P0_13) {
32 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
33
34 loop {
35 info!("off!");
36 led.set_high();
37 Timer::after(Duration::from_millis(300)).await;
38 info!("on!");
39 led.set_low();
40 Timer::after(Duration::from_millis(300)).await;
41 }
42 }
43}
diff --git a/examples/nrf52840/.cargo/config.toml b/examples/nrf52840/.cargo/config.toml
index 3872e7189..17616a054 100644
--- a/examples/nrf52840/.cargo/config.toml
+++ b/examples/nrf52840/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 6627b7861..8c4175966 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -6,8 +6,24 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8default = ["nightly"] 8default = ["nightly"]
9nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-time/nightly", "embassy-time/unstable-traits", "static_cell/nightly", 9nightly = [
10 "embassy-usb", "embedded-io/async", "embassy-net", "embassy-lora", "lora-phy", "lorawan-device", "lorawan"] 10 "embedded-hal-async",
11 "embassy-executor/nightly",
12 "embassy-nrf/nightly",
13 "embassy-net/nightly",
14 "embassy-net-esp-hosted",
15 "embassy-nrf/unstable-traits",
16 "embassy-time/nightly",
17 "embassy-time/unstable-traits",
18 "static_cell/nightly",
19 "embassy-usb",
20 "embedded-io/async",
21 "embassy-net",
22 "embassy-lora",
23 "lora-phy",
24 "lorawan-device",
25 "lorawan",
26]
11 27
12[dependencies] 28[dependencies]
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 29embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -22,6 +38,7 @@ embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["ti
22lora-phy = { version = "1", optional = true } 38lora-phy = { version = "1", optional = true }
23lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } 39lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
24lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } 40lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
41embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true }
25 42
26defmt = "0.3" 43defmt = "0.3"
27defmt-rtt = "0.4" 44defmt-rtt = "0.4"
@@ -35,3 +52,4 @@ rand = { version = "0.8.4", default-features = false }
35embedded-storage = "0.3.0" 52embedded-storage = "0.3.0"
36usbd-hid = "0.6.0" 53usbd-hid = "0.6.0"
37serde = { version = "1.0.136", default-features = false } 54serde = { version = "1.0.136", default-features = false }
55embedded-hal-async = { version = "0.2.0-alpha.1", optional = true }
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index 851e189ea..aab819117 100644
--- a/examples/nrf52840/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::{info, unwrap}; 61use defmt::{info, unwrap};
65use embassy_nrf::executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_nrf::interrupt; 63use embassy_nrf::interrupt;
67use embassy_nrf::pac::Interrupt; 64use embassy_nrf::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,16 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_nrf::init(Default::default()); 129 let _p = embassy_nrf::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: SWI1_EGU1, priority level 6 131 // High-priority executor: SWI1_EGU1, priority level 6
136 unsafe { nvic.set_priority(Interrupt::SWI1_EGU1, 6 << 5) }; 132 interrupt::SWI1_EGU1.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(Interrupt::SWI1_EGU1); 133 let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1);
138 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
139 135
140 // Medium-priority executor: SWI0_EGU0, priority level 7 136 // Medium-priority executor: SWI0_EGU0, priority level 7
141 unsafe { nvic.set_priority(Interrupt::SWI0_EGU0, 7 << 5) }; 137 interrupt::SWI0_EGU0.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(Interrupt::SWI0_EGU0); 138 let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0);
143 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
144 140
145 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/nrf52840/src/bin/nvmc.rs b/examples/nrf52840/src/bin/nvmc.rs
index 33a44516d..31c6fe4b6 100644
--- a/examples/nrf52840/src/bin/nvmc.rs
+++ b/examples/nrf52840/src/bin/nvmc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default()); 14 let p = embassy_nrf::init(Default::default());
15 info!("Hello NVMC!"); 15 info!("Hello NVMC!");
16 16
17 // probe-rs-cli run breaks without this, I'm not sure why. 17 // probe-rs run breaks without this, I'm not sure why.
18 Timer::after(Duration::from_secs(1)).await; 18 Timer::after(Duration::from_secs(1)).await;
19 19
20 let mut f = Nvmc::new(p.NVMC); 20 let mut f = Nvmc::new(p.NVMC);
diff --git a/examples/nrf52840/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs
index 196255a52..31ea6c81e 100644
--- a/examples/nrf52840/src/bin/self_spawn.rs
+++ b/examples/nrf52840/src/bin/self_spawn.rs
@@ -7,7 +7,11 @@ use embassy_executor::Spawner;
7use embassy_time::{Duration, Timer}; 7use embassy_time::{Duration, Timer};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::task(pool_size = 2)] 10mod config {
11 pub const MY_TASK_POOL_SIZE: usize = 2;
12}
13
14#[embassy_executor::task(pool_size = config::MY_TASK_POOL_SIZE)]
11async fn my_task(spawner: Spawner, n: u32) { 15async fn my_task(spawner: Spawner, n: u32) {
12 Timer::after(Duration::from_secs(1)).await; 16 Timer::after(Duration::from_secs(1)).await;
13 info!("Spawning self! {}", n); 17 info!("Spawning self! {}", n);
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index 1065f5b5d..f527c0d7f 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -97,12 +97,12 @@ async fn main(spawner: Spawner) {
97 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 97 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
98 unwrap!(spawner.spawn(usb_ncm_task(runner))); 98 unwrap!(spawner.spawn(usb_ncm_task(runner)));
99 99
100 let config = embassy_net::Config::Dhcp(Default::default()); 100 let config = embassy_net::Config::dhcpv4(Default::default());
101 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 101 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
102 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 102 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
103 // dns_servers: Vec::new(), 103 // dns_servers: Vec::new(),
104 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 104 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
105 //}); 105 // });
106 106
107 // Generate random seed 107 // Generate random seed
108 let mut rng = Rng::new(p.RNG, Irqs); 108 let mut rng = Rng::new(p.RNG, Irqs);
diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
index ccfd0e439..058746518 100644
--- a/examples/nrf52840/src/bin/wdt.rs
+++ b/examples/nrf52840/src/bin/wdt.rs
@@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
16 let mut config = Config::default(); 16 let mut config = Config::default();
17 config.timeout_ticks = 32768 * 3; // 3 seconds 17 config.timeout_ticks = 32768 * 3; // 3 seconds
18 18
19 // This is needed for `probe-rs-cli run` to be able to catch the panic message 19 // This is needed for `probe-rs run` to be able to catch the panic message
20 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. 20 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
21 config.run_during_debug_halt = false; 21 config.run_during_debug_halt = false;
22 22
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
new file mode 100644
index 000000000..4eb31b105
--- /dev/null
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -0,0 +1,139 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap, warn};
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Stack, StackResources};
9use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
10use embassy_nrf::rng::Rng;
11use embassy_nrf::spim::{self, Spim};
12use embassy_nrf::{bind_interrupts, peripherals};
13use embedded_hal_async::spi::ExclusiveDevice;
14use embedded_io::asynch::Write;
15use static_cell::make_static;
16use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
20 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
21});
22
23#[embassy_executor::task]
24async fn wifi_task(
25 runner: hosted::Runner<
26 'static,
27 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>>,
28 Input<'static, AnyPin>,
29 Output<'static, peripherals::P1_05>,
30 >,
31) -> ! {
32 runner.run().await
33}
34
35#[embassy_executor::task]
36async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! {
37 stack.run().await
38}
39
40#[embassy_executor::main]
41async fn main(spawner: Spawner) {
42 info!("Hello World!");
43
44 let p = embassy_nrf::init(Default::default());
45
46 let miso = p.P0_28;
47 let sck = p.P0_29;
48 let mosi = p.P0_30;
49 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
50 let handshake = Input::new(p.P1_01.degrade(), Pull::Up);
51 let ready = Input::new(p.P1_04.degrade(), Pull::None);
52 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
53
54 let mut config = spim::Config::default();
55 config.frequency = spim::Frequency::M32;
56 config.mode = spim::MODE_2; // !!!
57 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
58 let spi = ExclusiveDevice::new(spi, cs);
59
60 let (device, mut control, runner) = embassy_net_esp_hosted::new(
61 make_static!(embassy_net_esp_hosted::State::new()),
62 spi,
63 handshake,
64 ready,
65 reset,
66 )
67 .await;
68
69 unwrap!(spawner.spawn(wifi_task(runner)));
70
71 control.init().await;
72 control.join(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await;
73
74 let config = embassy_net::Config::dhcpv4(Default::default());
75 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
76 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
77 // dns_servers: Vec::new(),
78 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
79 // });
80
81 // Generate random seed
82 let mut rng = Rng::new(p.RNG, Irqs);
83 let mut seed = [0; 8];
84 rng.blocking_fill_bytes(&mut seed);
85 let seed = u64::from_le_bytes(seed);
86
87 // Init network stack
88 let stack = &*make_static!(Stack::new(
89 device,
90 config,
91 make_static!(StackResources::<2>::new()),
92 seed
93 ));
94
95 unwrap!(spawner.spawn(net_task(stack)));
96
97 // And now we can use it!
98
99 let mut rx_buffer = [0; 4096];
100 let mut tx_buffer = [0; 4096];
101 let mut buf = [0; 4096];
102
103 loop {
104 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
105 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
106
107 info!("Listening on TCP:1234...");
108 if let Err(e) = socket.accept(1234).await {
109 warn!("accept error: {:?}", e);
110 continue;
111 }
112
113 info!("Received connection from {:?}", socket.remote_endpoint());
114
115 loop {
116 let n = match socket.read(&mut buf).await {
117 Ok(0) => {
118 warn!("read EOF");
119 break;
120 }
121 Ok(n) => n,
122 Err(e) => {
123 warn!("read error: {:?}", e);
124 break;
125 }
126 };
127
128 info!("rxd {:02x}", &buf[..n]);
129
130 match socket.write_all(&buf[..n]).await {
131 Ok(()) => {}
132 Err(e) => {
133 warn!("write error: {:?}", e);
134 break;
135 }
136 };
137 }
138 }
139}
diff --git a/examples/nrf5340/.cargo/config.toml b/examples/nrf5340/.cargo/config.toml
index d25355894..4c3cf3d32 100644
--- a/examples/nrf5340/.cargo/config.toml
+++ b/examples/nrf5340/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF5340_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF5340_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF5340_xxAA" 3runner = "probe-rs run --chip nRF5340_xxAA"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml
index 2ee6fcb00..3d7d61740 100644
--- a/examples/rp/.cargo/config.toml
+++ b/examples/rp/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs-cli run --chip RP2040" 2runner = "probe-rs run --chip RP2040"
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ 5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index e946b481d..48f3a26bb 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs
index c5422c616..0d246c093 100644
--- a/examples/rp/src/bin/button.rs
+++ b/examples/rp/src/bin/button.rs
@@ -9,9 +9,12 @@ use {defmt_rtt as _, panic_probe as _};
9#[embassy_executor::main] 9#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 10async fn main(_spawner: Spawner) {
11 let p = embassy_rp::init(Default::default()); 11 let p = embassy_rp::init(Default::default());
12 let button = Input::new(p.PIN_28, Pull::Up);
13 let mut led = Output::new(p.PIN_25, Level::Low); 12 let mut led = Output::new(p.PIN_25, Level::Low);
14 13
14 // Use PIN_28, Pin34 on J0 for RP Pico, as a input.
15 // You need to add your own button.
16 let button = Input::new(p.PIN_28, Pull::Up);
17
15 loop { 18 loop {
16 if button.is_high() { 19 if button.is_high() {
17 led.set_high(); 20 led.set_high();
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index 63e142e7d..82568254a 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -64,7 +64,7 @@ async fn main(spawner: Spawner) {
64 // Init network stack 64 // Init network stack
65 let stack = &*make_static!(Stack::new( 65 let stack = &*make_static!(Stack::new(
66 device, 66 device,
67 embassy_net::Config::Dhcp(Default::default()), 67 embassy_net::Config::dhcpv4(Default::default()),
68 make_static!(StackResources::<3>::new()), 68 make_static!(StackResources::<3>::new()),
69 seed 69 seed
70 )); 70 ));
@@ -120,9 +120,9 @@ async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16)
120 } 120 }
121} 121}
122 122
123async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 123async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
124 loop { 124 loop {
125 if let Some(config) = stack.config() { 125 if let Some(config) = stack.config_v4() {
126 return config.clone(); 126 return config.clone();
127 } 127 }
128 yield_now().await; 128 yield_now().await;
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index a532de00d..d562defad 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -67,7 +67,7 @@ async fn main(spawner: Spawner) {
67 // Init network stack 67 // Init network stack
68 let stack = &*make_static!(Stack::new( 68 let stack = &*make_static!(Stack::new(
69 device, 69 device,
70 embassy_net::Config::Dhcp(Default::default()), 70 embassy_net::Config::dhcpv4(Default::default()),
71 make_static!(StackResources::<2>::new()), 71 make_static!(StackResources::<2>::new()),
72 seed 72 seed
73 )); 73 ));
@@ -108,9 +108,9 @@ async fn main(spawner: Spawner) {
108 } 108 }
109} 109}
110 110
111async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 111async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
112 loop { 112 loop {
113 if let Some(config) = stack.config() { 113 if let Some(config) = stack.config_v4() {
114 return config.clone(); 114 return config.clone();
115 } 115 }
116 yield_now().await; 116 yield_now().await;
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 599f6b1e9..7f521cdb4 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -65,7 +65,7 @@ async fn main(spawner: Spawner) {
65 // Init network stack 65 // Init network stack
66 let stack = &*make_static!(Stack::new( 66 let stack = &*make_static!(Stack::new(
67 device, 67 device,
68 embassy_net::Config::Dhcp(Default::default()), 68 embassy_net::Config::dhcpv4(Default::default()),
69 make_static!(StackResources::<2>::new()), 69 make_static!(StackResources::<2>::new()),
70 seed 70 seed
71 )); 71 ));
@@ -116,9 +116,9 @@ async fn main(spawner: Spawner) {
116 } 116 }
117} 117}
118 118
119async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 119async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
120 loop { 120 loop {
121 if let Some(config) = stack.config() { 121 if let Some(config) = stack.config_v4() {
122 return config.clone(); 122 return config.clone();
123 } 123 }
124 yield_now().await; 124 yield_now().await;
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index ac5a65bb6..ada86ae55 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -62,7 +62,7 @@ async fn main(spawner: Spawner) {
62 // Init network stack 62 // Init network stack
63 let stack = &*make_static!(Stack::new( 63 let stack = &*make_static!(Stack::new(
64 device, 64 device,
65 embassy_net::Config::Dhcp(Default::default()), 65 embassy_net::Config::dhcpv4(Default::default()),
66 make_static!(StackResources::<2>::new()), 66 make_static!(StackResources::<2>::new()),
67 seed 67 seed
68 )); 68 ));
@@ -95,9 +95,9 @@ async fn main(spawner: Spawner) {
95 } 95 }
96} 96}
97 97
98async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { 98async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
99 loop { 99 loop {
100 if let Some(config) = stack.config() { 100 if let Some(config) = stack.config_v4() {
101 return config.clone(); 101 return config.clone();
102 } 102 }
103 yield_now().await; 103 yield_now().await;
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs
index 2f79ba49e..9ace4cd68 100644
--- a/examples/rp/src/bin/multiprio.rs
+++ b/examples/rp/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::{info, unwrap}; 61use defmt::{info, unwrap};
65use embassy_rp::executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_rp::interrupt; 63use embassy_rp::interrupt;
67use embassy_rp::pac::Interrupt; 64use embassy_rp::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer, TICK_HZ}; 65use embassy_time::{Duration, Instant, Timer, TICK_HZ};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,18 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_rp::init(Default::default()); 129 let _p = embassy_rp::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: SWI_IRQ_1, priority level 2 131 // High-priority executor: SWI_IRQ_1, priority level 2
136 unsafe { nvic.set_priority(Interrupt::SWI_IRQ_1, 2 << 6) }; 132 interrupt::SWI_IRQ_1.set_priority(Priority::P2);
137 info!("bla: {}", NVIC::get_priority(Interrupt::SWI_IRQ_1)); 133 let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1);
138 let spawner = EXECUTOR_HIGH.start(Interrupt::SWI_IRQ_1);
139 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
140 135
141 // Medium-priority executor: SWI_IRQ_0, priority level 3 136 // Medium-priority executor: SWI_IRQ_0, priority level 3
142 unsafe { nvic.set_priority(Interrupt::SWI_IRQ_0, 3 << 6) }; 137 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
143 info!("bla: {}", NVIC::get_priority(Interrupt::SWI_IRQ_0)); 138 let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0);
144 let spawner = EXECUTOR_MED.start(Interrupt::SWI_IRQ_0);
145 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
146 140
147 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 16fbf5e91..91d1ec8e7 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -86,8 +86,8 @@ async fn main(spawner: Spawner) {
86 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 86 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
87 unwrap!(spawner.spawn(usb_ncm_task(runner))); 87 unwrap!(spawner.spawn(usb_ncm_task(runner)));
88 88
89 let config = embassy_net::Config::Dhcp(Default::default()); 89 let config = embassy_net::Config::dhcpv4(Default::default());
90 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 90 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
91 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 91 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
92 // dns_servers: Vec::new(), 92 // dns_servers: Vec::new(),
93 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 93 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index b27d3c9f8..310e84d92 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -42,8 +42,8 @@ async fn main(spawner: Spawner) {
42 42
43 // To make flashing faster for development, you may want to flash the firmwares independently 43 // To make flashing faster for development, you may want to flash the firmwares independently
44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
45 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 45 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
46 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 46 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; 47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
49 49
@@ -62,7 +62,7 @@ async fn main(spawner: Spawner) {
62 .await; 62 .await;
63 63
64 // Use a link-local address for communication without DHCP server 64 // Use a link-local address for communication without DHCP server
65 let config = Config::Static(embassy_net::StaticConfig { 65 let config = Config::ipv4_static(embassy_net::StaticConfigV4 {
66 address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16), 66 address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16),
67 dns_servers: heapless::Vec::new(), 67 dns_servers: heapless::Vec::new(),
68 gateway: None, 68 gateway: None,
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
new file mode 100644
index 000000000..bbcb1b5ec
--- /dev/null
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -0,0 +1,59 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use cyw43_pio::PioSpi;
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::gpio::{Level, Output};
9use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
10use embassy_rp::pio::Pio;
11use embassy_time::{Duration, Timer};
12use static_cell::make_static;
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::task]
16async fn wifi_task(
17 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
18) -> ! {
19 runner.run().await
20}
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
26 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
27
28 // To make flashing faster for development, you may want to flash the firmwares independently
29 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
30 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
31 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
32 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
33 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
34
35 let pwr = Output::new(p.PIN_23, Level::Low);
36 let cs = Output::new(p.PIN_25, Level::High);
37 let mut pio = Pio::new(p.PIO0);
38 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
39
40 let state = make_static!(cyw43::State::new());
41 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
42 unwrap!(spawner.spawn(wifi_task(runner)));
43
44 control.init(clm).await;
45 control
46 .set_power_management(cyw43::PowerManagementMode::PowerSave)
47 .await;
48
49 let delay = Duration::from_secs(1);
50 loop {
51 info!("led on!");
52 control.gpio_set(0, true).await;
53 Timer::after(delay).await;
54
55 info!("led off!");
56 control.gpio_set(0, false).await;
57 Timer::after(delay).await;
58 }
59}
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index 79534f229..391e12282 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -39,8 +39,8 @@ async fn main(spawner: Spawner) {
39 39
40 // To make flashing faster for development, you may want to flash the firmwares independently 40 // To make flashing faster for development, you may want to flash the firmwares independently
41 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 41 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
42 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 42 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
43 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 43 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
44 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; 44 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
45 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 45 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
46 46
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index 1a00bca96..e9d1079a6 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -42,8 +42,8 @@ async fn main(spawner: Spawner) {
42 42
43 // To make flashing faster for development, you may want to flash the firmwares independently 43 // To make flashing faster for development, you may want to flash the firmwares independently
44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
45 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 45 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
46 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 46 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; 47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
49 49
@@ -61,8 +61,8 @@ async fn main(spawner: Spawner) {
61 .set_power_management(cyw43::PowerManagementMode::PowerSave) 61 .set_power_management(cyw43::PowerManagementMode::PowerSave)
62 .await; 62 .await;
63 63
64 let config = Config::Dhcp(Default::default()); 64 let config = Config::dhcpv4(Default::default());
65 //let config = embassy_net::Config::Static(embassy_net::Config { 65 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
66 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 66 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
67 // dns_servers: Vec::new(), 67 // dns_servers: Vec::new(),
68 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 68 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
diff --git a/examples/std/README.md b/examples/std/README.md
new file mode 100644
index 000000000..adc795928
--- /dev/null
+++ b/examples/std/README.md
@@ -0,0 +1,23 @@
1
2## Running the `embassy-net` examples
3
4First, create the tap0 interface. You only need to do this once.
5
6```sh
7sudo ip tuntap add name tap0 mode tap user $USER
8sudo ip link set tap0 up
9sudo ip addr add 192.168.69.100/24 dev tap0
10sudo ip -6 addr add fe80::100/64 dev tap0
11sudo ip -6 addr add fdaa::100/64 dev tap0
12sudo ip -6 route add fe80::/64 dev tap0
13sudo ip -6 route add fdaa::/64 dev tap0
14```
15
16Second, have something listening there. For example `nc -l 8000`
17
18Then run the example located in the `examples` folder:
19
20```sh
21cd $EMBASSY_ROOT/examples/std/
22cargo run --bin net -- --static-ip
23``` \ No newline at end of file
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index b42bfc13b..3aadb029d 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -42,13 +42,13 @@ async fn main_task(spawner: Spawner) {
42 42
43 // Choose between dhcp or static ip 43 // Choose between dhcp or static ip
44 let config = if opts.static_ip { 44 let config = if opts.static_ip {
45 Config::Static(embassy_net::StaticConfig { 45 Config::ipv4_static(embassy_net::StaticConfigV4 {
46 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 46 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
47 dns_servers: Vec::new(), 47 dns_servers: Vec::new(),
48 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 48 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
49 }) 49 })
50 } else { 50 } else {
51 Config::Dhcp(Default::default()) 51 Config::dhcpv4(Default::default())
52 }; 52 };
53 53
54 // Generate random seed 54 // Generate random seed
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index 932ac5831..65b5a2cd9 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -40,14 +40,14 @@ async fn main_task(spawner: Spawner) {
40 40
41 // Choose between dhcp or static ip 41 // Choose between dhcp or static ip
42 let config = if opts.static_ip { 42 let config = if opts.static_ip {
43 Config::Static(embassy_net::StaticConfig { 43 Config::ipv4_static(embassy_net::StaticConfigV4 {
44 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24), 44 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24),
45 dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()]) 45 dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()])
46 .unwrap(), 46 .unwrap(),
47 gateway: Some(Ipv4Address::new(192, 168, 69, 100)), 47 gateway: Some(Ipv4Address::new(192, 168, 69, 100)),
48 }) 48 })
49 } else { 49 } else {
50 Config::Dhcp(Default::default()) 50 Config::dhcpv4(Default::default())
51 }; 51 };
52 52
53 // Generate random seed 53 // Generate random seed
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index d89ec7643..3fc46156c 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -38,13 +38,13 @@ async fn main_task(spawner: Spawner) {
38 38
39 // Choose between dhcp or static ip 39 // Choose between dhcp or static ip
40 let config = if opts.static_ip { 40 let config = if opts.static_ip {
41 Config::Static(embassy_net::StaticConfig { 41 Config::ipv4_static(embassy_net::StaticConfigV4 {
42 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 42 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
43 dns_servers: Vec::new(), 43 dns_servers: Vec::new(),
44 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 44 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
45 }) 45 })
46 } else { 46 } else {
47 Config::Dhcp(Default::default()) 47 Config::dhcpv4(Default::default())
48 }; 48 };
49 49
50 // Generate random seed 50 // Generate random seed
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs
index 01695baea..df09986ac 100644
--- a/examples/std/src/bin/tcp_accept.rs
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -53,13 +53,13 @@ async fn main_task(spawner: Spawner) {
53 53
54 // Choose between dhcp or static ip 54 // Choose between dhcp or static ip
55 let config = if opts.static_ip { 55 let config = if opts.static_ip {
56 Config::Static(embassy_net::StaticConfig { 56 Config::ipv4_static(embassy_net::StaticConfigV4 {
57 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 57 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
58 dns_servers: Vec::new(), 58 dns_servers: Vec::new(),
59 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 59 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
60 }) 60 })
61 } else { 61 } else {
62 Config::Dhcp(Default::default()) 62 Config::dhcpv4(Default::default())
63 }; 63 };
64 64
65 // Generate random seed 65 // Generate random seed
diff --git a/examples/stm32c0/.cargo/config.toml b/examples/stm32c0/.cargo/config.toml
index 517101fae..29a8be7e1 100644
--- a/examples/stm32c0/.cargo/config.toml
+++ b/examples/stm32c0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --speed 100 --chip STM32c031c6tx" 3runner = "probe-rs run --speed 100 --chip STM32c031c6tx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index ad11fbd1c..43f432520 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
12 12
diff --git a/examples/stm32f0/.cargo/config.toml b/examples/stm32f0/.cargo/config.toml
index bd0c0cd97..def4c8c92 100644
--- a/examples/stm32f0/.cargo/config.toml
+++ b/examples/stm32f0/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv6m-none-eabi] 1[target.thumbv6m-none-eabi]
2runner = 'probe-rs-cli run --chip STM32F091RCTX' 2runner = 'probe-rs run --chip STM32F091RCTX'
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" 5target = "thumbv6m-none-eabi"
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index ff134bb0e..8d2248ed0 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -13,7 +13,7 @@ defmt = "0.3"
13defmt-rtt = "0.4" 13defmt-rtt = "0.4"
14panic-probe = "0.3" 14panic-probe = "0.3"
15embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 16embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } 18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] }
19static_cell = { version = "1.1", features = ["nightly"]} 19static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs
index 430a805fc..988ffeef1 100644
--- a/examples/stm32f0/src/bin/multiprio.rs
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::*; 61use defmt::*;
65use embassy_executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
67use embassy_stm32::pac::Interrupt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -129,16 +126,15 @@ unsafe fn USART2() {
129fn main() -> ! { 126fn main() -> ! {
130 // Initialize and create handle for devicer peripherals 127 // Initialize and create handle for devicer peripherals
131 let _p = embassy_stm32::init(Default::default()); 128 let _p = embassy_stm32::init(Default::default());
132 let mut nvic: NVIC = unsafe { mem::transmute(()) };
133 129
134 // High-priority executor: USART1, priority level 6 130 // High-priority executor: USART1, priority level 6
135 unsafe { nvic.set_priority(Interrupt::USART1, 6 << 4) }; 131 interrupt::USART1.set_priority(Priority::P6);
136 let spawner = EXECUTOR_HIGH.start(Interrupt::USART1); 132 let spawner = EXECUTOR_HIGH.start(interrupt::USART1);
137 unwrap!(spawner.spawn(run_high())); 133 unwrap!(spawner.spawn(run_high()));
138 134
139 // Medium-priority executor: USART2, priority level 7 135 // Medium-priority executor: USART2, priority level 7
140 unsafe { nvic.set_priority(Interrupt::USART2, 7 << 4) }; 136 interrupt::USART2.set_priority(Priority::P7);
141 let spawner = EXECUTOR_MED.start(Interrupt::USART2); 137 let spawner = EXECUTOR_MED.start(interrupt::USART2);
142 unwrap!(spawner.spawn(run_med())); 138 unwrap!(spawner.spawn(run_med()));
143 139
144 // Low priority executor: runs in thread mode, using WFE/SEV 140 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs
index 80e76f901..a44b17528 100644
--- a/examples/stm32f0/src/bin/wdg.rs
+++ b/examples/stm32f0/src/bin/wdg.rs
@@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) {
16 let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00); 16 let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00);
17 17
18 info!("Watchdog start"); 18 info!("Watchdog start");
19 unsafe { wdg.unleash() }; 19 wdg.unleash();
20 20
21 loop { 21 loop {
22 Timer::after(Duration::from_secs(1)).await; 22 Timer::after(Duration::from_secs(1)).await;
23 unsafe { wdg.pet() }; 23 wdg.pet();
24 } 24 }
25} 25}
diff --git a/examples/stm32f1/.cargo/config.toml b/examples/stm32f1/.cargo/config.toml
index 81199c5aa..ce6fef11b 100644
--- a/examples/stm32f1/.cargo/config.toml
+++ b/examples/stm32f1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F103C8 with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F103C8 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F103C8" 3runner = "probe-rs run --chip STM32F103C8"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 345e948a6..d34fd439a 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32f2/.cargo/config.toml b/examples/stm32f2/.cargo/config.toml
index 5532779c8..1198fcab8 100644
--- a/examples/stm32f2/.cargo/config.toml
+++ b/examples/stm32f2/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F207ZGTx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F207ZGTx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F207ZGTx" 3runner = "probe-rs run --chip STM32F207ZGTx"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index e4f97a589..5e3e0d0f7 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12 12
diff --git a/examples/stm32f3/.cargo/config.toml b/examples/stm32f3/.cargo/config.toml
index 7f3fda529..cb8a7c5af 100644
--- a/examples/stm32f3/.cargo/config.toml
+++ b/examples/stm32f3/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F303ZETx" 3runner = "probe-rs run --chip STM32F303ZETx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 0fe9cb122..29ab2009c 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 5d010f799..80bf59deb 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::*; 61use defmt::*;
65use embassy_executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
67use embassy_stm32::pac::Interrupt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,16 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_stm32::init(Default::default()); 129 let _p = embassy_stm32::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: UART4, priority level 6 131 // High-priority executor: UART4, priority level 6
136 unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) }; 132 interrupt::UART4.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(Interrupt::UART4); 133 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
138 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
139 135
140 // Medium-priority executor: UART5, priority level 7 136 // Medium-priority executor: UART5, priority level 7
141 unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) }; 137 interrupt::UART5.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(Interrupt::UART5); 138 let spawner = EXECUTOR_MED.start(interrupt::UART5);
143 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
144 140
145 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml
index bed04b68f..16efa8e6f 100644
--- a/examples/stm32f4/.cargo/config.toml
+++ b/examples/stm32f4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F429ZITx" 3runner = "probe-rs run --chip STM32F429ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 3a8efdd06..7ecb64fce 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index e8377b9a1..da8955053 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -4,12 +4,21 @@
4 4
5use cortex_m_rt::entry; 5use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::bind_interrupts;
7use embassy_stm32::can::bxcan::filter::Mask32; 8use embassy_stm32::can::bxcan::filter::Mask32;
8use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; 9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
9use embassy_stm32::can::Can; 10use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
10use embassy_stm32::gpio::{Input, Pull}; 11use embassy_stm32::gpio::{Input, Pull};
12use embassy_stm32::peripherals::CAN1;
11use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
12 14
15bind_interrupts!(struct Irqs {
16 CAN1_RX0 => Rx0InterruptHandler<CAN1>;
17 CAN1_RX1 => Rx1InterruptHandler<CAN1>;
18 CAN1_SCE => SceInterruptHandler<CAN1>;
19 CAN1_TX => TxInterruptHandler<CAN1>;
20});
21
13#[entry] 22#[entry]
14fn main() -> ! { 23fn main() -> ! {
15 info!("Hello World!"); 24 info!("Hello World!");
@@ -23,7 +32,7 @@ fn main() -> ! {
23 let rx_pin = Input::new(&mut p.PA11, Pull::Up); 32 let rx_pin = Input::new(&mut p.PA11, Pull::Up);
24 core::mem::forget(rx_pin); 33 core::mem::forget(rx_pin);
25 34
26 let mut can = Can::new(p.CAN1, p.PA11, p.PA12); 35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
27 36
28 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 37 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
29 38
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index d97ae7082..3a6216712 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -4,7 +4,8 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dac::{Channel, Dac, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
10#[embassy_executor::main] 11#[embassy_executor::main]
@@ -12,12 +13,12 @@ async fn main(_spawner: Spawner) -> ! {
12 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
13 info!("Hello World, dude!"); 14 info!("Hello World, dude!");
14 15
15 let mut dac = Dac::new_1ch(p.DAC, p.PA4); 16 let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4);
16 17
17 loop { 18 loop {
18 for v in 0..=255 { 19 for v in 0..=255 {
19 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 20 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
20 unwrap!(dac.trigger(Channel::Ch1)); 21 dac.trigger();
21 } 22 }
22 } 23 }
23} 24}
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 5d010f799..80bf59deb 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -57,14 +57,11 @@
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)] 58#![feature(type_alias_impl_trait)]
59 59
60use core::mem;
61
62use cortex_m::peripheral::NVIC;
63use cortex_m_rt::entry; 60use cortex_m_rt::entry;
64use defmt::*; 61use defmt::*;
65use embassy_executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
66use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
67use embassy_stm32::pac::Interrupt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
68use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
69use static_cell::StaticCell; 66use static_cell::StaticCell;
70use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -130,16 +127,15 @@ fn main() -> ! {
130 info!("Hello World!"); 127 info!("Hello World!");
131 128
132 let _p = embassy_stm32::init(Default::default()); 129 let _p = embassy_stm32::init(Default::default());
133 let mut nvic: NVIC = unsafe { mem::transmute(()) };
134 130
135 // High-priority executor: UART4, priority level 6 131 // High-priority executor: UART4, priority level 6
136 unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) }; 132 interrupt::UART4.set_priority(Priority::P6);
137 let spawner = EXECUTOR_HIGH.start(Interrupt::UART4); 133 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
138 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
139 135
140 // Medium-priority executor: UART5, priority level 7 136 // Medium-priority executor: UART5, priority level 7
141 unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) }; 137 interrupt::UART5.set_priority(Priority::P7);
142 let spawner = EXECUTOR_MED.start(Interrupt::UART5); 138 let spawner = EXECUTOR_MED.start(interrupt::UART5);
143 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
144 140
145 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index d229cc3ef..b1f01417c 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -52,7 +52,9 @@ async fn main(spawner: Spawner) {
52 52
53 // Create the driver, from the HAL. 53 // Create the driver, from the HAL.
54 let ep_out_buffer = &mut make_static!([0; 256])[..]; 54 let ep_out_buffer = &mut make_static!([0; 256])[..];
55 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); 55 let mut config = embassy_stm32::usb_otg::Config::default();
56 config.vbus_detection = true;
57 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
56 58
57 // Create embassy-usb Config 59 // Create embassy-usb Config
58 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 60 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
@@ -94,8 +96,8 @@ async fn main(spawner: Spawner) {
94 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 96 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
95 unwrap!(spawner.spawn(usb_ncm_task(runner))); 97 unwrap!(spawner.spawn(usb_ncm_task(runner)));
96 98
97 let config = embassy_net::Config::Dhcp(Default::default()); 99 let config = embassy_net::Config::dhcpv4(Default::default());
98 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 100 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
99 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 101 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
100 // dns_servers: Vec::new(), 102 // dns_servers: Vec::new(),
101 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 103 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index f8f5940a7..4ff6452ef 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
29 29
30 // Create the driver, from the HAL. 30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256]; 31 let mut ep_out_buffer = [0u8; 256];
32 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
33 35
34 // Create embassy-usb Config 36 // Create embassy-usb Config
35 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs
index b2c587fa1..e5d122af7 100644
--- a/examples/stm32f4/src/bin/wdt.rs
+++ b/examples/stm32f4/src/bin/wdt.rs
@@ -17,9 +17,7 @@ async fn main(_spawner: Spawner) {
17 let mut led = Output::new(p.PB7, Level::High, Speed::Low); 17 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
18 18
19 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); 19 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
20 unsafe { 20 wdt.unleash();
21 wdt.unleash();
22 }
23 21
24 let mut i = 0; 22 let mut i = 0;
25 23
@@ -36,9 +34,7 @@ async fn main(_spawner: Spawner) {
36 // MCU should restart in 1 second after the last pet. 34 // MCU should restart in 1 second after the last pet.
37 if i < 5 { 35 if i < 5 {
38 info!("Petting watchdog"); 36 info!("Petting watchdog");
39 unsafe { 37 wdt.pet();
40 wdt.pet();
41 }
42 } 38 }
43 39
44 i += 1; 40 i += 1;
diff --git a/examples/stm32f7/.cargo/config.toml b/examples/stm32f7/.cargo/config.toml
index 7d6c88a99..9088eea6e 100644
--- a/examples/stm32f7/.cargo/config.toml
+++ b/examples/stm32f7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F767ZITx" 3runner = "probe-rs run --chip STM32F767ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 7a650067c..657251c50 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
diff --git a/examples/stm32f7/build.rs b/examples/stm32f7/build.rs
index c4e15f19c..2b5d412a9 100644
--- a/examples/stm32f7/build.rs
+++ b/examples/stm32f7/build.rs
@@ -1,9 +1,8 @@
1//! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs 1//! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs
2use std::env;
3use std::fs::File; 2use std::fs::File;
4use std::io::prelude::*; 3use std::io::prelude::*;
5use std::io::{self};
6use std::path::PathBuf; 4use std::path::PathBuf;
5use std::{env, io};
7 6
8#[derive(Debug)] 7#[derive(Debug)]
9enum Error { 8enum Error {
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index d8438241c..fde6a7576 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -62,8 +62,8 @@ async fn main(spawner: Spawner) -> ! {
62 0, 62 0,
63 ); 63 );
64 64
65 let config = embassy_net::Config::Dhcp(Default::default()); 65 let config = embassy_net::Config::dhcpv4(Default::default());
66 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 66 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
67 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 67 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
68 // dns_servers: Vec::new(), 68 // dns_servers: Vec::new(),
69 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 69 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 763309ce2..a2c76178b 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
30 30
31 // Create the driver, from the HAL. 31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256]; 32 let mut ep_out_buffer = [0u8; 256];
33 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
34 36
35 // Create embassy-usb Config 37 // Create embassy-usb Config
36 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32g0/.cargo/config.toml b/examples/stm32g0/.cargo/config.toml
index a7a5fbd84..35cca5412 100644
--- a/examples/stm32g0/.cargo/config.toml
+++ b/examples/stm32g0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32G071RBTx" 3runner = "probe-rs run --chip STM32G071RBTx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 4d7fc4548..c5245757b 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
12 12
diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml
index 606d7d5a3..d28ad069e 100644
--- a/examples/stm32g4/.cargo/config.toml
+++ b/examples/stm32g4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32G484VETx" 3runner = "probe-rs run --chip STM32G484VETx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 00e2dae4c..fbfbc6408 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -6,10 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } 12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13 14
14defmt = "0.3" 15defmt = "0.3"
15defmt-rtt = "0.4" 16defmt-rtt = "0.4"
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
new file mode 100644
index 000000000..ef7d4800c
--- /dev/null
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSrc};
8use embassy_stm32::Config;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15
16 config.rcc.pll = Some(Pll {
17 source: PllSrc::HSI16,
18 prediv_m: PllM::Div4,
19 mul_n: PllN::Mul85,
20 div_p: None,
21 div_q: None,
22 // Main system clock at 170 MHz
23 div_r: Some(PllR::Div2),
24 });
25
26 config.rcc.mux = ClockSrc::PLL;
27
28 let _p = embassy_stm32::init(config);
29 info!("Hello World!");
30
31 loop {
32 Timer::after(Duration::from_millis(1000)).await;
33 info!("1s elapsed");
34 }
35}
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
new file mode 100644
index 000000000..77cfa67d3
--- /dev/null
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -0,0 +1,120 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{self, Driver, Instance};
10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 USB_LP => usb::InterruptHandler<peripherals::USB>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = Config::default();
24
25 // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
26 const USE_HSI48: bool = true;
27
28 let pllq_div = if USE_HSI48 { None } else { Some(PllQ::Div6) };
29
30 config.rcc.pll = Some(Pll {
31 source: PllSrc::HSE(Hertz(8_000_000)),
32 prediv_m: PllM::Div2,
33 mul_n: PllN::Mul72,
34 div_p: None,
35 div_q: pllq_div,
36 // Main system clock at 144 MHz
37 div_r: Some(PllR::Div2),
38 });
39
40 config.rcc.mux = ClockSrc::PLL;
41
42 if USE_HSI48 {
43 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
44 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig {
45 sync_src: CrsSyncSource::Usb,
46 })));
47 } else {
48 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
49 }
50
51 let p = embassy_stm32::init(config);
52
53 info!("Hello World!");
54
55 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
56
57 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
58 config.manufacturer = Some("Embassy");
59 config.product = Some("USB-Serial Example");
60 config.serial_number = Some("123456");
61
62 config.device_class = 0xEF;
63 config.device_sub_class = 0x02;
64 config.device_protocol = 0x01;
65 config.composite_with_iads = true;
66
67 let mut device_descriptor = [0; 256];
68 let mut config_descriptor = [0; 256];
69 let mut bos_descriptor = [0; 256];
70 let mut control_buf = [0; 64];
71
72 let mut state = State::new();
73
74 let mut builder = Builder::new(
75 driver,
76 config,
77 &mut device_descriptor,
78 &mut config_descriptor,
79 &mut bos_descriptor,
80 &mut control_buf,
81 );
82
83 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
84
85 let mut usb = builder.build();
86
87 let usb_fut = usb.run();
88
89 let echo_fut = async {
90 loop {
91 class.wait_connection().await;
92 info!("Connected");
93 let _ = echo(&mut class).await;
94 info!("Disconnected");
95 }
96 };
97
98 join(usb_fut, echo_fut).await;
99}
100
101struct Disconnected {}
102
103impl From<EndpointError> for Disconnected {
104 fn from(val: EndpointError) -> Self {
105 match val {
106 EndpointError::BufferOverflow => panic!("Buffer overflow"),
107 EndpointError::Disabled => Disconnected {},
108 }
109 }
110}
111
112async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
113 let mut buf = [0; 64];
114 loop {
115 let n = class.read_packet(&mut buf).await?;
116 let data = &buf[..n];
117 info!("data: {:x}", data);
118 class.write_packet(data).await?;
119 }
120}
diff --git a/examples/stm32h5/.cargo/config.toml b/examples/stm32h5/.cargo/config.toml
index c8b864b6c..478146142 100644
--- a/examples/stm32h5/.cargo/config.toml
+++ b/examples/stm32h5/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv8m.main-none-eabihf] 1[target.thumbv8m.main-none-eabihf]
2runner = 'probe-rs-cli run --chip STM32H563ZITx' 2runner = 'probe-rs run --chip STM32H563ZITx'
3 3
4[build] 4[build]
5target = "thumbv8m.main-none-eabihf" 5target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index d49a0dde7..ebe511347 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 5d1eadf4b..78c8282a6 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -81,8 +81,8 @@ async fn main(spawner: Spawner) -> ! {
81 0, 81 0,
82 ); 82 );
83 83
84 let config = embassy_net::Config::Dhcp(Default::default()); 84 let config = embassy_net::Config::dhcpv4(Default::default());
85 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 85 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
86 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 86 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
87 // dns_servers: Vec::new(), 87 // dns_servers: Vec::new(),
88 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 88 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 3912327e2..336eed644 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -45,11 +45,9 @@ async fn main(_spawner: Spawner) {
45 45
46 info!("Hello World!"); 46 info!("Hello World!");
47 47
48 unsafe { 48 pac::RCC.ccipr4().write(|w| {
49 pac::RCC.ccipr4().write(|w| { 49 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
50 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); 50 });
51 });
52 }
53 51
54 // Create the driver, from the HAL. 52 // Create the driver, from the HAL.
55 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 53 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
diff --git a/examples/stm32h7/.cargo/config.toml b/examples/stm32h7/.cargo/config.toml
index f08f57a54..5f680dbce 100644
--- a/examples/stm32h7/.cargo/config.toml
+++ b/examples/stm32h7/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv7em-none-eabihf] 1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs-cli run --chip STM32H743ZITx' 2runner = 'probe-rs run --chip STM32H743ZITx'
3 3
4[build] 4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) 5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 08b57f988..62ef5e9e4 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index f12716370..586b4154b 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -4,7 +4,8 @@
4 4
5use cortex_m_rt::entry; 5use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dac::{Channel, Dac, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma;
8use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
9use embassy_stm32::Config; 10use embassy_stm32::Config;
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -19,12 +20,12 @@ fn main() -> ! {
19 config.rcc.pll1.q_ck = Some(mhz(100)); 20 config.rcc.pll1.q_ck = Some(mhz(100));
20 let p = embassy_stm32::init(config); 21 let p = embassy_stm32::init(config);
21 22
22 let mut dac = Dac::new_1ch(p.DAC1, p.PA4); 23 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
23 24
24 loop { 25 loop {
25 for v in 0..=255 { 26 for v in 0..=255 {
26 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 27 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
27 unwrap!(dac.trigger(Channel::Ch1)); 28 dac.trigger();
28 } 29 }
29 } 30 }
30} 31}
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 3aa7b2271..12d37f7a4 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -63,8 +63,8 @@ async fn main(spawner: Spawner) -> ! {
63 0, 63 0,
64 ); 64 );
65 65
66 let config = embassy_net::Config::Dhcp(Default::default()); 66 let config = embassy_net::Config::dhcpv4(Default::default());
67 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 67 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
68 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 68 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
69 // dns_servers: Vec::new(), 69 // dns_servers: Vec::new(),
70 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 70 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 575c716b6..6078fc3fe 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -64,8 +64,8 @@ async fn main(spawner: Spawner) -> ! {
64 0, 64 0,
65 ); 65 );
66 66
67 let config = embassy_net::Config::Dhcp(Default::default()); 67 let config = embassy_net::Config::dhcpv4(Default::default());
68 //let config = embassy_net::Config::StaticConfig(embassy_net::Config { 68 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
69 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 69 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
70 // dns_servers: Vec::new(), 70 // dns_servers: Vec::new(),
71 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 71 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index 1972f8ff2..d360df085 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -62,49 +62,39 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
62 T::enable(); 62 T::enable();
63 <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset(); 63 <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset();
64 64
65 unsafe { 65 ch1.set_speed(Speed::VeryHigh);
66 ch1.set_speed(Speed::VeryHigh); 66 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull);
67 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); 67 ch2.set_speed(Speed::VeryHigh);
68 ch2.set_speed(Speed::VeryHigh); 68 ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull);
69 ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); 69 ch3.set_speed(Speed::VeryHigh);
70 ch3.set_speed(Speed::VeryHigh); 70 ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull);
71 ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); 71 ch4.set_speed(Speed::VeryHigh);
72 ch4.set_speed(Speed::VeryHigh); 72 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
73 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
74 }
75 73
76 let mut this = Self { inner: tim }; 74 let mut this = Self { inner: tim };
77 75
78 this.set_freq(freq); 76 this.set_freq(freq);
79 this.inner.start(); 77 this.inner.start();
80 78
81 unsafe { 79 let r = T::regs_gp32();
82 T::regs_gp32() 80 r.ccmr_output(0)
83 .ccmr_output(0) 81 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
84 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 82 r.ccmr_output(0)
85 T::regs_gp32() 83 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
86 .ccmr_output(0) 84 r.ccmr_output(1)
87 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); 85 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
88 T::regs_gp32() 86 r.ccmr_output(1)
89 .ccmr_output(1) 87 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
90 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 88
91 T::regs_gp32()
92 .ccmr_output(1)
93 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
94 }
95 this 89 this
96 } 90 }
97 91
98 pub fn enable(&mut self, channel: Channel) { 92 pub fn enable(&mut self, channel: Channel) {
99 unsafe { 93 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
100 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
101 }
102 } 94 }
103 95
104 pub fn disable(&mut self, channel: Channel) { 96 pub fn disable(&mut self, channel: Channel) {
105 unsafe { 97 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
106 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
107 }
108 } 98 }
109 99
110 pub fn set_freq(&mut self, freq: Hertz) { 100 pub fn set_freq(&mut self, freq: Hertz) {
@@ -112,11 +102,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
112 } 102 }
113 103
114 pub fn get_max_duty(&self) -> u32 { 104 pub fn get_max_duty(&self) -> u32 {
115 unsafe { T::regs_gp32().arr().read().arr() } 105 T::regs_gp32().arr().read().arr()
116 } 106 }
117 107
118 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 108 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
119 defmt::assert!(duty < self.get_max_duty()); 109 defmt::assert!(duty < self.get_max_duty());
120 unsafe { T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) } 110 T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty))
121 } 111 }
122} 112}
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index c622f19f7..97291f60c 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
29 29
30 // Create the driver, from the HAL. 30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256]; 31 let mut ep_out_buffer = [0u8; 256];
32 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
33 35
34 // Create embassy-usb Config 36 // Create embassy-usb Config
35 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs
index 2b0301aad..9181dfd67 100644
--- a/examples/stm32h7/src/bin/wdg.rs
+++ b/examples/stm32h7/src/bin/wdg.rs
@@ -15,10 +15,10 @@ async fn main(_spawner: Spawner) {
15 15
16 let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000); 16 let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000);
17 17
18 unsafe { wdg.unleash() }; 18 wdg.unleash();
19 19
20 loop { 20 loop {
21 Timer::after(Duration::from_secs(1)).await; 21 Timer::after(Duration::from_secs(1)).await;
22 unsafe { wdg.pet() }; 22 wdg.pet();
23 } 23 }
24} 24}
diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml
index 526f5a1f7..b050334b2 100644
--- a/examples/stm32l0/.cargo/config.toml
+++ b/examples/stm32l0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L053R8Tx" 3runner = "probe-rs run --chip STM32L053R8Tx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 235f1b0b3..2ead714e4 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8default = ["nightly"] 8default = ["nightly"]
9nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstable-traits", 9nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstable-traits", "embassy-executor/nightly",
10 "embassy-lora", "lora-phy", "lorawan-device", "lorawan", "embedded-io/async"] 10 "embassy-lora", "lora-phy", "lorawan-device", "lorawan", "embedded-io/async"]
11 11
12[dependencies] 12[dependencies]
diff --git a/examples/stm32l1/.cargo/config.toml b/examples/stm32l1/.cargo/config.toml
index 1401500a0..9cabd14ba 100644
--- a/examples/stm32l1/.cargo/config.toml
+++ b/examples/stm32l1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L151CBxxA" 3runner = "probe-rs run --chip STM32L151CBxxA"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 8b6508c87..93d48abeb 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12 12
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index abf55eb2e..36e74e5a5 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -1,8 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs-cli run --chip STM32L475VGT6" 3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs-cli run --chip STM32L475VG" 4#runner = "probe-rs run --chip STM32L475VG"
5runner = "probe-rs-cli run --chip STM32L4S5VI" 5runner = "probe-rs run --chip STM32L4S5VI"
6 6
7[build] 7[build]
8target = "thumbv7em-none-eabi" 8target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 29d091f94..780256cc2 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -6,10 +6,10 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } 12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits", "chrono"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 281346e5f..1771e5202 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -12,12 +12,10 @@ use {defmt_rtt as _, panic_probe as _};
12fn main() -> ! { 12fn main() -> ! {
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 unsafe { 15 pac::RCC.ccipr().modify(|w| {
16 pac::RCC.ccipr().modify(|w| { 16 w.set_adcsel(0b11);
17 w.set_adcsel(0b11); 17 });
18 }); 18 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
19 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
20 }
21 19
22 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
23 21
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index d6e744aa6..ade43eb35 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -3,28 +3,21 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dac::{Channel, Dac, Value}; 6use embassy_stm32::dac::{DacCh1, DacChannel, Value};
7use embassy_stm32::pac; 7use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[cortex_m_rt::entry] 10#[cortex_m_rt::entry]
11fn main() -> ! { 11fn main() -> ! {
12 info!("Hello World!");
13
14 unsafe {
15 pac::RCC.apb1enr1().modify(|w| {
16 w.set_dac1en(true);
17 });
18 }
19
20 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
21 14
22 let mut dac = Dac::new_1ch(p.DAC1, p.PA4); 15 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
23 16
24 loop { 17 loop {
25 for v in 0..=255 { 18 for v in 0..=255 {
26 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 19 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
27 unwrap!(dac.trigger(Channel::Ch1)); 20 dac.trigger();
28 } 21 }
29 } 22 }
30} 23}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
new file mode 100644
index 000000000..c27cc03e1
--- /dev/null
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -0,0 +1,137 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacChannel, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm};
9use embassy_stm32::peripherals::{TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::timer::low_level::Basic16bitInstance;
13use micromath::F32Ext;
14use {defmt_rtt as _, panic_probe as _};
15
16pub type Dac1Type =
17 embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
18
19pub type Dac2Type =
20 embassy_stm32::dac::DacCh2<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 let config = embassy_stm32::Config::default();
25
26 // Initialize the board and obtain a Peripherals instance
27 let p: embassy_stm32::Peripherals = embassy_stm32::init(config);
28
29 // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
30 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
31
32 spawner.spawn(dac_task1(dac_ch1)).ok();
33 spawner.spawn(dac_task2(dac_ch2)).ok();
34}
35
36#[embassy_executor::task]
37async fn dac_task1(mut dac: Dac1Type) {
38 let data: &[u8; 256] = &calculate_array::<256>();
39
40 info!("TIM6 frequency is {}", TIM6::frequency());
41 const FREQUENCY: Hertz = Hertz::hz(200);
42
43 // Compute the reload value such that we obtain the FREQUENCY for the sine
44 let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32;
45
46 // Depends on your clock and on the specific chip used, you may need higher or lower values here
47 if reload < 10 {
48 error!("Reload value {} below threshold!", reload);
49 }
50
51 dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap();
52 dac.enable_channel().unwrap();
53
54 TIM6::enable();
55 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
56 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
57 TIM6::regs().cr1().modify(|w| {
58 w.set_opm(Opm::DISABLED);
59 w.set_cen(true);
60 });
61
62 debug!(
63 "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
64 TIM6::frequency(),
65 FREQUENCY,
66 reload,
67 reload as u16,
68 data.len()
69 );
70
71 // Loop technically not necessary if DMA circular mode is enabled
72 loop {
73 info!("Loop DAC1");
74 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
75 error!("Could not write to dac: {}", e);
76 }
77 }
78}
79
80#[embassy_executor::task]
81async fn dac_task2(mut dac: Dac2Type) {
82 let data: &[u8; 256] = &calculate_array::<256>();
83
84 info!("TIM7 frequency is {}", TIM7::frequency());
85
86 const FREQUENCY: Hertz = Hertz::hz(600);
87 let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32;
88
89 if reload < 10 {
90 error!("Reload value {} below threshold!", reload);
91 }
92
93 TIM7::enable();
94 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
95 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
96 TIM7::regs().cr1().modify(|w| {
97 w.set_opm(Opm::DISABLED);
98 w.set_cen(true);
99 });
100
101 dac.select_trigger(embassy_stm32::dac::Ch2Trigger::Tim7).unwrap();
102
103 debug!(
104 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
105 TIM7::frequency(),
106 FREQUENCY,
107 reload,
108 reload as u16,
109 data.len()
110 );
111
112 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
113 error!("Could not write to dac: {}", e);
114 }
115}
116
117fn to_sine_wave(v: u8) -> u8 {
118 if v >= 128 {
119 // top half
120 let r = 3.14 * ((v - 128) as f32 / 128.0);
121 (r.sin() * 128.0 + 127.0) as u8
122 } else {
123 // bottom half
124 let r = 3.14 + 3.14 * (v as f32 / 128.0);
125 (r.sin() * 128.0 + 127.0) as u8
126 }
127}
128
129fn calculate_array<const N: usize>() -> [u8; N] {
130 let mut res = [0; N];
131 let mut i = 0;
132 while i < N {
133 res[i] = to_sine_wave(i as u8);
134 i += 1;
135 }
136 res
137}
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
index 0de708950..d72d5ddb6 100644
--- a/examples/stm32l4/src/bin/rtc.rs
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -46,5 +46,4 @@ async fn main(_spawner: Spawner) {
46 46
47 let then: NaiveDateTime = rtc.now().unwrap().into(); 47 let then: NaiveDateTime = rtc.now().unwrap().into();
48 info!("Got RTC! {:?}", then.timestamp()); 48 info!("Got RTC! {:?}", then.timestamp());
49
50} 49}
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 80811a43e..410d6891b 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
30 30
31 // Create the driver, from the HAL. 31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256]; 32 let mut ep_out_buffer = [0u8; 256];
33 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
34 36
35 // Create embassy-usb Config 37 // Create embassy-usb Config
36 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32l5/.cargo/config.toml b/examples/stm32l5/.cargo/config.toml
index 1dc3a6fb7..86a145a27 100644
--- a/examples/stm32l5/.cargo/config.toml
+++ b/examples/stm32l5/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32L552ZETxQ with your chip as listed in `probe-rs-cli chip list` 2# replace STM32L552ZETxQ with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L552ZETxQ" 3runner = "probe-rs run --chip STM32L552ZETxQ"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 2ac9c180d..6035c291f 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 6163e0709..32eba4277 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -91,8 +91,8 @@ async fn main(spawner: Spawner) {
91 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 91 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
92 unwrap!(spawner.spawn(usb_ncm_task(runner))); 92 unwrap!(spawner.spawn(usb_ncm_task(runner)));
93 93
94 let config = embassy_net::Config::Dhcp(Default::default()); 94 let config = embassy_net::Config::dhcpv4(Default::default());
95 //let config = embassy_net::Config::Static(embassy_net::StaticConfig { 95 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
96 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 96 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
97 // dns_servers: Vec::new(), 97 // dns_servers: Vec::new(),
98 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 98 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml
index cecd01938..36c5b63a6 100644
--- a/examples/stm32u5/.cargo/config.toml
+++ b/examples/stm32u5/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32U585AIIx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32U585AIIx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32U585AIIx" 3runner = "probe-rs run --chip STM32U585AIIx"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index be205f880..e2318c3d6 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index f36daf91b..9e47fb18a 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -31,7 +31,9 @@ async fn main(_spawner: Spawner) {
31 31
32 // Create the driver, from the HAL. 32 // Create the driver, from the HAL.
33 let mut ep_out_buffer = [0u8; 256]; 33 let mut ep_out_buffer = [0u8; 256];
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 34 let mut config = embassy_stm32::usb_otg::Config::default();
35 config.vbus_detection = true;
36 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
35 37
36 // Create embassy-usb Config 38 // Create embassy-usb Config
37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 39 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index d23fdc513..8b6d6d754 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3# runner = "probe-rs-cli run --chip STM32WB55CCUx --speed 1000 --connect-under-reset" 3# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf" 4runner = "teleprobe local run --chip STM32WB55RG --elf"
5 5
6[build] 6[build]
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 8cfac772a..fbb2d918b 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -6,9 +6,10 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
12embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
12 13
13defmt = "0.3" 14defmt = "0.3"
14defmt-rtt = "0.4" 15defmt-rtt = "0.4"
@@ -19,3 +20,24 @@ embedded-hal = "0.2.6"
19panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
20futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
21heapless = { version = "0.7.5", default-features = false } 22heapless = { version = "0.7.5", default-features = false }
23
24
25[features]
26default = ["ble"]
27mac = ["embassy-stm32-wpan/mac"]
28ble = ["embassy-stm32-wpan/ble"]
29
30[[bin]]
31name = "tl_mbox_ble"
32required-features = ["ble"]
33
34[[bin]]
35name = "tl_mbox_mac"
36required-features = ["mac"]
37
38[[bin]]
39name = "eddystone_beacon"
40required-features = ["ble"]
41
42[patch.crates-io]
43stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"} \ No newline at end of file
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
new file mode 100644
index 000000000..b99f8cb2e
--- /dev/null
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -0,0 +1,249 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::time::Duration;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_stm32::bind_interrupts;
10use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
11use embassy_stm32_wpan::hci::host::uart::UartHci;
12use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
13use embassy_stm32_wpan::hci::types::AdvertisingType;
14use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
15 AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
16};
17use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands;
18use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
19use embassy_stm32_wpan::hci::BdAddr;
20use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
21use embassy_stm32_wpan::TlMbox;
22use {defmt_rtt as _, panic_probe as _};
23
24bind_interrupts!(struct Irqs{
25 IPCC_C1_RX => ReceiveInterruptHandler;
26 IPCC_C1_TX => TransmitInterruptHandler;
27});
28
29const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 /*
34 How to make this work:
35
36 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
37 - Download and Install STM32CubeProgrammer.
38 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
39 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
40 - Open STM32CubeProgrammer
41 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
42 - Once complete, click connect to connect to the device.
43 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
44 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
45 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
46 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
47 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
48 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
49 - Select "Start Wireless Stack".
50 - Disconnect from the device.
51 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
52 - Run this example.
53
54 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
55 */
56
57 let p = embassy_stm32::init(Default::default());
58 info!("Hello World!");
59
60 let config = Config::default();
61 let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
62
63 let sys_event = mbox.sys_subsystem.read().await;
64 info!("sys event: {}", sys_event.payload());
65
66 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
67
68 info!("resetting BLE...");
69 mbox.ble_subsystem.reset().await;
70 let response = mbox.ble_subsystem.read().await.unwrap();
71 defmt::info!("{}", response);
72
73 info!("config public address...");
74 mbox.ble_subsystem
75 .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
76 .await;
77 let response = mbox.ble_subsystem.read().await.unwrap();
78 defmt::info!("{}", response);
79
80 info!("config random address...");
81 mbox.ble_subsystem
82 .write_config_data(&ConfigData::random_address(get_random_addr()).build())
83 .await;
84 let response = mbox.ble_subsystem.read().await.unwrap();
85 defmt::info!("{}", response);
86
87 info!("config identity root...");
88 mbox.ble_subsystem
89 .write_config_data(&ConfigData::identity_root(&get_irk()).build())
90 .await;
91 let response = mbox.ble_subsystem.read().await.unwrap();
92 defmt::info!("{}", response);
93
94 info!("config encryption root...");
95 mbox.ble_subsystem
96 .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
97 .await;
98 let response = mbox.ble_subsystem.read().await.unwrap();
99 defmt::info!("{}", response);
100
101 info!("config tx power level...");
102 mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
103 let response = mbox.ble_subsystem.read().await.unwrap();
104 defmt::info!("{}", response);
105
106 info!("GATT init...");
107 mbox.ble_subsystem.init_gatt().await;
108 let response = mbox.ble_subsystem.read().await.unwrap();
109 defmt::info!("{}", response);
110
111 info!("GAP init...");
112 mbox.ble_subsystem
113 .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
114 .await;
115 let response = mbox.ble_subsystem.read().await.unwrap();
116 defmt::info!("{}", response);
117
118 // info!("set scan response...");
119 // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap();
120 // let response = mbox.ble_subsystem.read().await.unwrap();
121 // defmt::info!("{}", response);
122
123 info!("set discoverable...");
124 mbox.ble_subsystem
125 .set_discoverable(&DiscoverableParameters {
126 advertising_type: AdvertisingType::NonConnectableUndirected,
127 advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))),
128 address_type: OwnAddressType::Public,
129 filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
130 local_name: None,
131 advertising_data: &[],
132 conn_interval: (None, None),
133 })
134 .await
135 .unwrap();
136
137 let response = mbox.ble_subsystem.read().await;
138 defmt::info!("{}", response);
139
140 // remove some advertisement to decrease the packet size
141 info!("delete tx power ad type...");
142 mbox.ble_subsystem
143 .delete_ad_type(AdvertisingDataType::TxPowerLevel)
144 .await;
145 let response = mbox.ble_subsystem.read().await.unwrap();
146 defmt::info!("{}", response);
147
148 info!("delete conn interval ad type...");
149 mbox.ble_subsystem
150 .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval)
151 .await;
152 let response = mbox.ble_subsystem.read().await.unwrap();
153 defmt::info!("{}", response);
154
155 info!("update advertising data...");
156 mbox.ble_subsystem
157 .update_advertising_data(&eddystone_advertising_data())
158 .await
159 .unwrap();
160 let response = mbox.ble_subsystem.read().await.unwrap();
161 defmt::info!("{}", response);
162
163 info!("update advertising data type...");
164 mbox.ble_subsystem
165 .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe])
166 .await
167 .unwrap();
168 let response = mbox.ble_subsystem.read().await.unwrap();
169 defmt::info!("{}", response);
170
171 info!("update advertising data flags...");
172 mbox.ble_subsystem
173 .update_advertising_data(&[
174 2,
175 AdvertisingDataType::Flags as u8,
176 (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support
177 ])
178 .await
179 .unwrap();
180 let response = mbox.ble_subsystem.read().await.unwrap();
181 defmt::info!("{}", response);
182
183 cortex_m::asm::wfi();
184}
185
186fn get_bd_addr() -> BdAddr {
187 let mut bytes = [0u8; 6];
188
189 let lhci_info = LhciC1DeviceInformationCcrp::new();
190 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
191 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
192 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
193 bytes[3] = lhci_info.device_type_id;
194 bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
195 bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
196
197 BdAddr(bytes)
198}
199
200fn get_random_addr() -> BdAddr {
201 let mut bytes = [0u8; 6];
202
203 let lhci_info = LhciC1DeviceInformationCcrp::new();
204 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
205 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
206 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
207 bytes[3] = 0;
208 bytes[4] = 0x6E;
209 bytes[5] = 0xED;
210
211 BdAddr(bytes)
212}
213
214const BLE_CFG_IRK: [u8; 16] = [
215 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
216];
217const BLE_CFG_ERK: [u8; 16] = [
218 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
219];
220
221fn get_irk() -> EncryptionKey {
222 EncryptionKey(BLE_CFG_IRK)
223}
224
225fn get_erk() -> EncryptionKey {
226 EncryptionKey(BLE_CFG_ERK)
227}
228
229fn eddystone_advertising_data() -> [u8; 24] {
230 const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com";
231
232 let mut service_data = [0u8; 24];
233 let url_len = EDDYSTONE_URL.len();
234
235 service_data[0] = 6 + url_len as u8;
236 service_data[1] = AdvertisingDataType::ServiceData as u8;
237
238 // 16-bit eddystone uuid
239 service_data[2] = 0xaa;
240 service_data[3] = 0xFE;
241
242 service_data[4] = 0x10; // URL frame type
243 service_data[5] = 22_i8 as u8; // calibrated TX power at 0m
244 service_data[6] = 0x03; // eddystone url prefix = https
245
246 service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL);
247
248 service_data
249}
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
index 8f4e70af0..9fc4b8aac 100644
--- a/examples/stm32wb/src/bin/tl_mbox.rs
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -4,14 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::tl_mbox::{Config, TlMbox}; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::{bind_interrupts, tl_mbox}; 8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::TlMbox;
9use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
11 12
12bind_interrupts!(struct Irqs{ 13bind_interrupts!(struct Irqs{
13 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 14 IPCC_C1_RX => ReceiveInterruptHandler;
14 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 15 IPCC_C1_TX => TransmitInterruptHandler;
15}); 16});
16 17
17#[embassy_executor::main] 18#[embassy_executor::main]
@@ -44,10 +45,10 @@ async fn main(_spawner: Spawner) {
44 info!("Hello World!"); 45 info!("Hello World!");
45 46
46 let config = Config::default(); 47 let config = Config::default();
47 let mbox = TlMbox::new(p.IPCC, Irqs, config); 48 let mbox = TlMbox::init(p.IPCC, Irqs, config);
48 49
49 loop { 50 loop {
50 let wireless_fw_info = mbox.wireless_fw_info(); 51 let wireless_fw_info = mbox.sys_subsystem.wireless_fw_info();
51 match wireless_fw_info { 52 match wireless_fw_info {
52 None => info!("not yet initialized"), 53 None => info!("not yet initialized"),
53 Some(fw_info) => { 54 Some(fw_info) => {
diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index 1724d946f..a511e89aa 100644
--- a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -4,13 +4,14 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::tl_mbox::{Config, TlMbox}; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::{bind_interrupts, tl_mbox}; 8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::TlMbox;
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
11bind_interrupts!(struct Irqs{ 12bind_interrupts!(struct Irqs{
12 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 13 IPCC_C1_RX => ReceiveInterruptHandler;
13 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 14 IPCC_C1_TX => TransmitInterruptHandler;
14}); 15});
15 16
16#[embassy_executor::main] 17#[embassy_executor::main]
@@ -43,55 +44,20 @@ async fn main(_spawner: Spawner) {
43 info!("Hello World!"); 44 info!("Hello World!");
44 45
45 let config = Config::default(); 46 let config = Config::default();
46 let mbox = TlMbox::new(p.IPCC, Irqs, config); 47 let mbox = TlMbox::init(p.IPCC, Irqs, config);
47 48
48 info!("waiting for coprocessor to boot"); 49 let sys_event = mbox.sys_subsystem.read().await;
49 let event_box = mbox.read().await; 50 info!("sys event: {}", sys_event.payload());
50 51
51 let mut payload = [0u8; 6]; 52 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
52 event_box.copy_into_slice(&mut payload).unwrap();
53 53
54 let event_packet = event_box.evt(); 54 info!("starting ble...");
55 let kind = event_packet.evt_serial.kind; 55 mbox.ble_subsystem.tl_write(0x0c, &[]).await;
56 56
57 // means recieved SYS event, which indicates in this case that the coprocessor is ready 57 info!("waiting for ble...");
58 if kind == 0x12 { 58 let ble_event = mbox.ble_subsystem.tl_read().await;
59 let code = event_packet.evt_serial.evt.evt_code;
60 let payload_len = event_packet.evt_serial.evt.payload_len;
61 59
62 info!( 60 info!("ble event: {}", ble_event.payload());
63 "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
64 kind,
65 code,
66 payload_len,
67 payload[3..]
68 );
69 }
70
71 // initialize ble stack, does not return a response
72 mbox.shci_ble_init(Default::default());
73
74 info!("resetting BLE");
75 mbox.send_ble_cmd(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
76
77 let event_box = mbox.read().await;
78
79 let mut payload = [0u8; 7];
80 event_box.copy_into_slice(&mut payload).unwrap();
81
82 let event_packet = event_box.evt();
83 let kind = event_packet.evt_serial.kind;
84
85 let code = event_packet.evt_serial.evt.evt_code;
86 let payload_len = event_packet.evt_serial.evt.payload_len;
87
88 info!(
89 "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
90 kind,
91 code,
92 payload_len,
93 payload[3..]
94 );
95 61
96 info!("Test OK"); 62 info!("Test OK");
97 cortex_m::asm::bkpt(); 63 cortex_m::asm::bkpt();
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
new file mode 100644
index 000000000..f67be4682
--- /dev/null
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -0,0 +1,66 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::TlMbox;
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs{
13 IPCC_C1_RX => ReceiveInterruptHandler;
14 IPCC_C1_TX => TransmitInterruptHandler;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 /*
20 How to make this work:
21
22 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
23 - Download and Install STM32CubeProgrammer.
24 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
25 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
26 - Open STM32CubeProgrammer
27 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
28 - Once complete, click connect to connect to the device.
29 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
30 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
31 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
32 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
33 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
34 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
35 - Select "Start Wireless Stack".
36 - Disconnect from the device.
37 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
38 - Run this example.
39
40 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
41 */
42
43 let p = embassy_stm32::init(Default::default());
44 info!("Hello World!");
45
46 let config = Config::default();
47 let mbox = TlMbox::init(p.IPCC, Irqs, config);
48
49 let sys_event = mbox.sys_subsystem.read().await;
50 info!("sys event: {}", sys_event.payload());
51
52 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
53 info!("initialized mac: {}", result);
54
55 //
56 // info!("starting ble...");
57 // mbox.ble_subsystem.t_write(0x0c, &[]).await;
58 //
59 // info!("waiting for ble...");
60 // let ble_event = mbox.ble_subsystem.tl_read().await;
61 //
62 // info!("ble event: {}", ble_event.payload());
63
64 info!("Test OK");
65 cortex_m::asm::bkpt();
66}
diff --git a/examples/stm32wl/.cargo/config.toml b/examples/stm32wl/.cargo/config.toml
index b49b582e0..4f8094ff2 100644
--- a/examples/stm32wl/.cargo/config.toml
+++ b/examples/stm32wl/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32WLE5JCIx" 3runner = "probe-rs run --chip STM32WLE5JCIx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 6191d01e9..260f9afa1 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] }
12embassy-embedded-hal = {version = "0.1.0", path = "../../embassy-embedded-hal" } 12embassy-embedded-hal = {version = "0.1.0", path = "../../embassy-embedded-hal" }
diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs
index e179c5ca1..805d21418 100644
--- a/examples/stm32wl/src/bin/lora_lorawan.rs
+++ b/examples/stm32wl/src/bin/lora_lorawan.rs
@@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) {
35 config.rcc.enable_lsi = true; // enable RNG 35 config.rcc.enable_lsi = true; // enable RNG
36 let p = embassy_stm32::init(config); 36 let p = embassy_stm32::init(config);
37 37
38 unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) } 38 pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01));
39 39
40 let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); 40 let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);
41 41
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index 182c607f9..d8562fca5 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -15,11 +15,9 @@ async fn main(_spawner: Spawner) {
15 config.rcc.enable_lsi = true; //Needed for RNG to work 15 config.rcc.enable_lsi = true; //Needed for RNG to work
16 16
17 let p = embassy_stm32::init(config); 17 let p = embassy_stm32::init(config);
18 unsafe { 18 pac::RCC.ccipr().modify(|w| {
19 pac::RCC.ccipr().modify(|w| { 19 w.set_rngsel(0b01);
20 w.set_rngsel(0b01); 20 });
21 });
22 }
23 21
24 info!("Hello World!"); 22 info!("Hello World!");
25 23
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 9735c87d9..4f9ecc47a 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -13,6 +13,10 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature
13embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] } 13embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] }
14embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 14embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
15embedded-io = { version = "0.4.0", features = ["async"] } 15embedded-io = { version = "0.4.0", features = ["async"] }
16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
18embedded-hal-async = { version = "0.2.0-alpha.1" }
19static_cell = { version = "1.1", features = [ "nightly" ] }
16 20
17defmt = "0.3" 21defmt = "0.3"
18defmt-rtt = "0.4" 22defmt-rtt = "0.4"
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
new file mode 100644
index 000000000..277b985c5
--- /dev/null
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -0,0 +1,270 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../common.rs"]
6mod common;
7
8use defmt::{error, info, unwrap};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{Config, Ipv4Address, Stack, StackResources};
13use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
14use embassy_nrf::rng::Rng;
15use embassy_nrf::spim::{self, Spim};
16use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{with_timeout, Duration, Timer};
18use embedded_hal_async::spi::ExclusiveDevice;
19use static_cell::make_static;
20use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
21
22teleprobe_meta::timeout!(120);
23
24bind_interrupts!(struct Irqs {
25 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
26 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
27});
28
29#[embassy_executor::task]
30async fn wifi_task(
31 runner: hosted::Runner<
32 'static,
33 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>>,
34 Input<'static, AnyPin>,
35 Output<'static, peripherals::P1_05>,
36 >,
37) -> ! {
38 runner.run().await
39}
40
41type MyDriver = hosted::NetDriver<'static>;
42
43#[embassy_executor::task]
44async fn net_task(stack: &'static Stack<MyDriver>) -> ! {
45 stack.run().await
46}
47
48#[embassy_executor::main]
49async fn main(spawner: Spawner) {
50 info!("Hello World!");
51
52 let p = embassy_nrf::init(Default::default());
53
54 let miso = p.P0_28;
55 let sck = p.P0_29;
56 let mosi = p.P0_30;
57 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
58 let handshake = Input::new(p.P1_01.degrade(), Pull::Up);
59 let ready = Input::new(p.P1_04.degrade(), Pull::None);
60 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
61
62 let mut config = spim::Config::default();
63 config.frequency = spim::Frequency::M32;
64 config.mode = spim::MODE_2; // !!!
65 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
66 let spi = ExclusiveDevice::new(spi, cs);
67
68 let (device, mut control, runner) = embassy_net_esp_hosted::new(
69 make_static!(embassy_net_esp_hosted::State::new()),
70 spi,
71 handshake,
72 ready,
73 reset,
74 )
75 .await;
76
77 unwrap!(spawner.spawn(wifi_task(runner)));
78
79 control.init().await;
80 control.join(WIFI_NETWORK, WIFI_PASSWORD).await;
81
82 // Generate random seed
83 let mut rng = Rng::new(p.RNG, Irqs);
84 let mut seed = [0; 8];
85 rng.blocking_fill_bytes(&mut seed);
86 let seed = u64::from_le_bytes(seed);
87
88 // Init network stack
89 let stack = &*make_static!(Stack::new(
90 device,
91 Config::dhcpv4(Default::default()),
92 make_static!(StackResources::<2>::new()),
93 seed
94 ));
95
96 unwrap!(spawner.spawn(net_task(stack)));
97
98 info!("Waiting for DHCP up...");
99 while stack.config_v4().is_none() {
100 Timer::after(Duration::from_millis(100)).await;
101 }
102 info!("IP addressing up!");
103
104 let down = test_download(stack).await;
105 let up = test_upload(stack).await;
106 let updown = test_upload_download(stack).await;
107
108 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
109 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
110 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
111
112 info!("Test OK");
113 cortex_m::asm::bkpt();
114}
115
116// Test-only wifi network, no internet access!
117const WIFI_NETWORK: &str = "EmbassyTest";
118const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
119
120const TEST_DURATION: usize = 10;
121const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 150;
122const TEST_EXPECTED_UPLOAD_KBPS: usize = 150;
123const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150;
124const RX_BUFFER_SIZE: usize = 4096;
125const TX_BUFFER_SIZE: usize = 4096;
126const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
127const DOWNLOAD_PORT: u16 = 4321;
128const UPLOAD_PORT: u16 = 4322;
129const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
130
131async fn test_download(stack: &'static Stack<MyDriver>) -> usize {
132 info!("Testing download...");
133
134 let mut rx_buffer = [0; RX_BUFFER_SIZE];
135 let mut tx_buffer = [0; TX_BUFFER_SIZE];
136 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
137 socket.set_timeout(Some(Duration::from_secs(10)));
138
139 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
140 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
141 error!("connect error: {:?}", e);
142 return 0;
143 }
144 info!("connected, testing...");
145
146 let mut rx_buf = [0; 4096];
147 let mut total: usize = 0;
148 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
149 loop {
150 match socket.read(&mut rx_buf).await {
151 Ok(0) => {
152 error!("read EOF");
153 return 0;
154 }
155 Ok(n) => total += n,
156 Err(e) => {
157 error!("read error: {:?}", e);
158 return 0;
159 }
160 }
161 }
162 })
163 .await
164 .ok();
165
166 let kbps = (total + 512) / 1024 / TEST_DURATION;
167 info!("download: {} kB/s", kbps);
168 kbps
169}
170
171async fn test_upload(stack: &'static Stack<MyDriver>) -> usize {
172 info!("Testing upload...");
173
174 let mut rx_buffer = [0; RX_BUFFER_SIZE];
175 let mut tx_buffer = [0; TX_BUFFER_SIZE];
176 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
177 socket.set_timeout(Some(Duration::from_secs(10)));
178
179 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
180 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
181 error!("connect error: {:?}", e);
182 return 0;
183 }
184 info!("connected, testing...");
185
186 let buf = [0; 4096];
187 let mut total: usize = 0;
188 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
189 loop {
190 match socket.write(&buf).await {
191 Ok(0) => {
192 error!("write zero?!??!?!");
193 return 0;
194 }
195 Ok(n) => total += n,
196 Err(e) => {
197 error!("write error: {:?}", e);
198 return 0;
199 }
200 }
201 }
202 })
203 .await
204 .ok();
205
206 let kbps = (total + 512) / 1024 / TEST_DURATION;
207 info!("upload: {} kB/s", kbps);
208 kbps
209}
210
211async fn test_upload_download(stack: &'static Stack<MyDriver>) -> usize {
212 info!("Testing upload+download...");
213
214 let mut rx_buffer = [0; RX_BUFFER_SIZE];
215 let mut tx_buffer = [0; TX_BUFFER_SIZE];
216 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
217 socket.set_timeout(Some(Duration::from_secs(10)));
218
219 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
220 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
221 error!("connect error: {:?}", e);
222 return 0;
223 }
224 info!("connected, testing...");
225
226 let (mut reader, mut writer) = socket.split();
227
228 let tx_buf = [0; 4096];
229 let mut rx_buf = [0; 4096];
230 let mut total: usize = 0;
231 let tx_fut = async {
232 loop {
233 match writer.write(&tx_buf).await {
234 Ok(0) => {
235 error!("write zero?!??!?!");
236 return 0;
237 }
238 Ok(_) => {}
239 Err(e) => {
240 error!("write error: {:?}", e);
241 return 0;
242 }
243 }
244 }
245 };
246
247 let rx_fut = async {
248 loop {
249 match reader.read(&mut rx_buf).await {
250 Ok(0) => {
251 error!("read EOF");
252 return 0;
253 }
254 Ok(n) => total += n,
255 Err(e) => {
256 error!("read error: {:?}", e);
257 return 0;
258 }
259 }
260 }
261 };
262
263 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
264 .await
265 .ok();
266
267 let kbps = (total + 512) / 1024 / TEST_DURATION;
268 info!("upload+download: {} kB/s", kbps);
269 kbps
270}
diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml
new file mode 100644
index 000000000..532039050
--- /dev/null
+++ b/tests/perf-server/Cargo.toml
@@ -0,0 +1,8 @@
1[package]
2name = "perf-server"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7log = "0.4.17"
8pretty_env_logger = "0.4.0"
diff --git a/tests/perf-server/deploy.sh b/tests/perf-server/deploy.sh
new file mode 100755
index 000000000..032e99c30
--- /dev/null
+++ b/tests/perf-server/deploy.sh
@@ -0,0 +1,11 @@
1#!/bin/bash
2
3set -euxo pipefail
4
5[email protected]
6
7cargo build --release
8ssh $HOST -- systemctl stop perf-server
9scp target/release/perf-server $HOST:/root
10scp perf-server.service $HOST:/etc/systemd/system/
11ssh $HOST -- 'systemctl daemon-reload; systemctl restart perf-server' \ No newline at end of file
diff --git a/tests/perf-server/perf-server.service b/tests/perf-server/perf-server.service
new file mode 100644
index 000000000..c14c5d16f
--- /dev/null
+++ b/tests/perf-server/perf-server.service
@@ -0,0 +1,16 @@
1[Unit]
2Description=perf-server
3After=network.target
4StartLimitIntervalSec=0
5
6[Service]
7Type=simple
8Restart=always
9RestartSec=1
10User=root
11ExecStart=/root/perf-server
12Environment=RUST_BACKTRACE=1
13Environment=RUST_LOG=info
14
15[Install]
16WantedBy=multi-user.target
diff --git a/tests/perf-server/src/main.rs b/tests/perf-server/src/main.rs
new file mode 100644
index 000000000..f6e7efc59
--- /dev/null
+++ b/tests/perf-server/src/main.rs
@@ -0,0 +1,90 @@
1use std::io::{Read, Write};
2use std::net::{TcpListener, TcpStream};
3use std::thread::spawn;
4use std::time::Duration;
5
6use log::info;
7
8fn main() {
9 pretty_env_logger::init();
10 spawn(|| rx_listen());
11 spawn(|| rxtx_listen());
12 tx_listen();
13}
14
15fn tx_listen() {
16 info!("tx: listening on 0.0.0.0:4321");
17 let listener = TcpListener::bind("0.0.0.0:4321").unwrap();
18 loop {
19 let (socket, addr) = listener.accept().unwrap();
20 info!("tx: received connection from: {}", addr);
21 spawn(|| tx_conn(socket));
22 }
23}
24
25fn tx_conn(mut socket: TcpStream) {
26 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
27 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
28
29 let buf = [0; 1024];
30 loop {
31 if let Err(e) = socket.write_all(&buf) {
32 info!("tx: failed to write to socket; err = {:?}", e);
33 return;
34 }
35 }
36}
37
38fn rx_listen() {
39 info!("rx: listening on 0.0.0.0:4322");
40 let listener = TcpListener::bind("0.0.0.0:4322").unwrap();
41 loop {
42 let (socket, addr) = listener.accept().unwrap();
43 info!("rx: received connection from: {}", addr);
44 spawn(|| rx_conn(socket));
45 }
46}
47
48fn rx_conn(mut socket: TcpStream) {
49 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
50 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
51
52 let mut buf = [0; 1024];
53 loop {
54 if let Err(e) = socket.read_exact(&mut buf) {
55 info!("rx: failed to read from socket; err = {:?}", e);
56 return;
57 }
58 }
59}
60
61fn rxtx_listen() {
62 info!("rxtx: listening on 0.0.0.0:4323");
63 let listener = TcpListener::bind("0.0.0.0:4323").unwrap();
64 loop {
65 let (socket, addr) = listener.accept().unwrap();
66 info!("rxtx: received connection from: {}", addr);
67 spawn(|| rxtx_conn(socket));
68 }
69}
70
71fn rxtx_conn(mut socket: TcpStream) {
72 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
73 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
74
75 let mut buf = [0; 1024];
76 loop {
77 match socket.read(&mut buf) {
78 Ok(n) => {
79 if let Err(e) = socket.write_all(&buf[..n]) {
80 info!("rxtx: failed to write to socket; err = {:?}", e);
81 return;
82 }
83 }
84 Err(e) => {
85 info!("rxtx: failed to read from socket; err = {:?}", e);
86 return;
87 }
88 }
89 }
90}
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 1786baee3..180d0ebbe 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -5,13 +5,16 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8teleprobe-meta = "1" 8teleprobe-meta = "1.1"
9 9
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
17cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
15 18
16defmt = "0.3.0" 19defmt = "0.3.0"
17defmt-rtt = "0.4" 20defmt-rtt = "0.4"
@@ -25,6 +28,7 @@ panic-probe = { version = "0.3.0", features = ["print-defmt"] }
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 28futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
26embedded-io = { version = "0.4.0", features = ["async"] } 29embedded-io = { version = "0.4.0", features = ["async"] }
27embedded-storage = { version = "0.3" } 30embedded-storage = { version = "0.3" }
31static_cell = { version = "1.1", features = ["nightly"]}
28 32
29[profile.dev] 33[profile.dev]
30debug = 2 34debug = 2
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
new file mode 100644
index 000000000..1ecaab266
--- /dev/null
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -0,0 +1,260 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use cyw43_pio::PioSpi;
8use defmt::{assert, panic, *};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{Config, Ipv4Address, Stack, StackResources};
13use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::Pio;
16use embassy_rp::rom_data;
17use embassy_time::{with_timeout, Duration, Timer};
18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _};
20
21teleprobe_meta::timeout!(120);
22
23#[embassy_executor::task]
24async fn wifi_task(
25 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
26) -> ! {
27 runner.run().await
28}
29
30#[embassy_executor::task]
31async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
32 stack.run().await
33}
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 info!("Hello World!");
38 let p = embassy_rp::init(Default::default());
39
40 // needed for reading the firmware from flash via XIP.
41 unsafe {
42 rom_data::flash_exit_xip();
43 rom_data::flash_enter_cmd_xip();
44 }
45
46 // cyw43 firmware needs to be flashed manually:
47 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000
48 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000
49 let fw = unsafe { core::slice::from_raw_parts(0x101c0000 as *const u8, 224190) };
50 let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) };
51
52 let pwr = Output::new(p.PIN_23, Level::Low);
53 let cs = Output::new(p.PIN_25, Level::High);
54 let mut pio = Pio::new(p.PIO0);
55 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
56
57 let state = make_static!(cyw43::State::new());
58 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
59 unwrap!(spawner.spawn(wifi_task(runner)));
60
61 control.init(clm).await;
62 control
63 .set_power_management(cyw43::PowerManagementMode::PowerSave)
64 .await;
65
66 // Generate random seed
67 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
68
69 // Init network stack
70 let stack = &*make_static!(Stack::new(
71 net_device,
72 Config::dhcpv4(Default::default()),
73 make_static!(StackResources::<2>::new()),
74 seed
75 ));
76
77 unwrap!(spawner.spawn(net_task(stack)));
78
79 loop {
80 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await {
81 Ok(_) => break,
82 Err(err) => {
83 panic!("join failed with status={}", err.status);
84 }
85 }
86 }
87
88 info!("Waiting for DHCP up...");
89 while stack.config_v4().is_none() {
90 Timer::after(Duration::from_millis(100)).await;
91 }
92 info!("IP addressing up!");
93
94 let down = test_download(stack).await;
95 let up = test_upload(stack).await;
96 let updown = test_upload_download(stack).await;
97
98 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
99 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
100 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
101
102 info!("Test OK");
103 cortex_m::asm::bkpt();
104}
105
106// Test-only wifi network, no internet access!
107const WIFI_NETWORK: &str = "EmbassyTest";
108const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
109
110const TEST_DURATION: usize = 10;
111const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 300;
112const TEST_EXPECTED_UPLOAD_KBPS: usize = 300;
113const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300;
114const RX_BUFFER_SIZE: usize = 4096;
115const TX_BUFFER_SIZE: usize = 4096;
116const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
117const DOWNLOAD_PORT: u16 = 4321;
118const UPLOAD_PORT: u16 = 4322;
119const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
120
121async fn test_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
122 info!("Testing download...");
123
124 let mut rx_buffer = [0; RX_BUFFER_SIZE];
125 let mut tx_buffer = [0; TX_BUFFER_SIZE];
126 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
127 socket.set_timeout(Some(Duration::from_secs(10)));
128
129 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
130 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
131 error!("connect error: {:?}", e);
132 return 0;
133 }
134 info!("connected, testing...");
135
136 let mut rx_buf = [0; 4096];
137 let mut total: usize = 0;
138 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
139 loop {
140 match socket.read(&mut rx_buf).await {
141 Ok(0) => {
142 error!("read EOF");
143 return 0;
144 }
145 Ok(n) => total += n,
146 Err(e) => {
147 error!("read error: {:?}", e);
148 return 0;
149 }
150 }
151 }
152 })
153 .await
154 .ok();
155
156 let kbps = (total + 512) / 1024 / TEST_DURATION;
157 info!("download: {} kB/s", kbps);
158 kbps
159}
160
161async fn test_upload(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
162 info!("Testing upload...");
163
164 let mut rx_buffer = [0; RX_BUFFER_SIZE];
165 let mut tx_buffer = [0; TX_BUFFER_SIZE];
166 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
167 socket.set_timeout(Some(Duration::from_secs(10)));
168
169 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
170 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
171 error!("connect error: {:?}", e);
172 return 0;
173 }
174 info!("connected, testing...");
175
176 let buf = [0; 4096];
177 let mut total: usize = 0;
178 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
179 loop {
180 match socket.write(&buf).await {
181 Ok(0) => {
182 error!("write zero?!??!?!");
183 return 0;
184 }
185 Ok(n) => total += n,
186 Err(e) => {
187 error!("write error: {:?}", e);
188 return 0;
189 }
190 }
191 }
192 })
193 .await
194 .ok();
195
196 let kbps = (total + 512) / 1024 / TEST_DURATION;
197 info!("upload: {} kB/s", kbps);
198 kbps
199}
200
201async fn test_upload_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize {
202 info!("Testing upload+download...");
203
204 let mut rx_buffer = [0; RX_BUFFER_SIZE];
205 let mut tx_buffer = [0; TX_BUFFER_SIZE];
206 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
207 socket.set_timeout(Some(Duration::from_secs(10)));
208
209 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
210 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
211 error!("connect error: {:?}", e);
212 return 0;
213 }
214 info!("connected, testing...");
215
216 let (mut reader, mut writer) = socket.split();
217
218 let tx_buf = [0; 4096];
219 let mut rx_buf = [0; 4096];
220 let mut total: usize = 0;
221 let tx_fut = async {
222 loop {
223 match writer.write(&tx_buf).await {
224 Ok(0) => {
225 error!("write zero?!??!?!");
226 return 0;
227 }
228 Ok(_) => {}
229 Err(e) => {
230 error!("write error: {:?}", e);
231 return 0;
232 }
233 }
234 }
235 };
236
237 let rx_fut = async {
238 loop {
239 match reader.read(&mut rx_buf).await {
240 Ok(0) => {
241 error!("read EOF");
242 return 0;
243 }
244 Ok(n) => total += n,
245 Err(e) => {
246 error!("read error: {:?}", e);
247 return 0;
248 }
249 }
250 }
251 };
252
253 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
254 .await
255 .ok();
256
257 let kbps = (total + 512) / 1024 / TEST_DURATION;
258 info!("upload+download: {} kB/s", kbps);
259 kbps
260}
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs
index 6a982507a..0e0de85fa 100644
--- a/tests/rp/src/bin/float.rs
+++ b/tests/rp/src/bin/float.rs
@@ -18,11 +18,9 @@ async fn main(_spawner: Spawner) {
18 const PI_F: f32 = 3.1415926535f32; 18 const PI_F: f32 = 3.1415926535f32;
19 const PI_D: f64 = 3.14159265358979323846f64; 19 const PI_D: f64 = 3.14159265358979323846f64;
20 20
21 unsafe { 21 pac::BUSCTRL
22 pac::BUSCTRL 22 .perfsel(0)
23 .perfsel(0) 23 .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
24 .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM));
25 }
26 24
27 for i in 0..=360 { 25 for i in 0..=360 {
28 let rad_f = (i as f32) * PI_F / 180.0; 26 let rad_f = (i as f32) * PI_F / 180.0;
@@ -46,7 +44,7 @@ async fn main(_spawner: Spawner) {
46 Timer::after(Duration::from_millis(10)).await; 44 Timer::after(Duration::from_millis(10)).await;
47 } 45 }
48 46
49 let rom_accesses = unsafe { pac::BUSCTRL.perfctr(0).read().perfctr() }; 47 let rom_accesses = pac::BUSCTRL.perfctr(0).read().perfctr();
50 // every float operation used here uses at least 10 cycles 48 // every float operation used here uses at least 10 cycles
51 defmt::assert!(rom_accesses >= 360 * 12 * 10); 49 defmt::assert!(rom_accesses >= 360 * 12 * 10);
52 50
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index f1b0ba121..c2422f7bc 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -7,28 +7,30 @@ autobins = false
7 7
8[features] 8[features]
9stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill 9stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill
10stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "not-gpdma"] # Nucleo "sdmmc" 10stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "can", "not-gpdma"] # Nucleo "sdmmc"
11stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo 11stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo
12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo 12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo 13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo 14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble"] # Nucleo 15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble" ] # Nucleo
16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo 16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board 17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
18 18
19sdmmc = [] 19sdmmc = []
20chrono = ["embassy-stm32/chrono", "dep:chrono"] 20chrono = ["embassy-stm32/chrono", "dep:chrono"]
21ble = [] 21can = []
22ble = ["dep:embassy-stm32-wpan"]
22not-gpdma = [] 23not-gpdma = []
23 24
24[dependencies] 25[dependencies]
25teleprobe-meta = "1" 26teleprobe-meta = "1"
26 27
27embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 28embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
28embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 29embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
29embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } 30embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] }
30embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } 31embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
31embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 32embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
33embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] }
32 34
33defmt = "0.3.0" 35defmt = "0.3.0"
34defmt-rtt = "0.4" 36defmt-rtt = "0.4"
@@ -44,6 +46,9 @@ rand_chacha = { version = "0.3", default-features = false }
44 46
45chrono = { version = "^0.4", default-features = false, optional = true} 47chrono = { version = "^0.4", default-features = false, optional = true}
46 48
49[patch.crates-io]
50stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"}
51
47# BEGIN TESTS 52# BEGIN TESTS
48# Generated by gen_test.py. DO NOT EDIT. 53# Generated by gen_test.py. DO NOT EDIT.
49[[bin]] 54[[bin]]
@@ -52,6 +57,11 @@ path = "src/bin/tl_mbox.rs"
52required-features = [ "ble",] 57required-features = [ "ble",]
53 58
54[[bin]] 59[[bin]]
60name = "can"
61path = "src/bin/can.rs"
62required-features = [ "can",]
63
64[[bin]]
55name = "gpio" 65name = "gpio"
56path = "src/bin/gpio.rs" 66path = "src/bin/gpio.rs"
57required-features = [] 67required-features = []
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
new file mode 100644
index 000000000..33d63d546
--- /dev/null
+++ b/tests/stm32/src/bin/can.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5// required-features: can
6
7#[path = "../common.rs"]
8mod common;
9use common::*;
10use embassy_executor::Spawner;
11use embassy_stm32::bind_interrupts;
12use embassy_stm32::can::bxcan::filter::Mask32;
13use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
14use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
15use embassy_stm32::gpio::{Input, Pull};
16use embassy_stm32::peripherals::CAN1;
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 CAN1_RX0 => Rx0InterruptHandler<CAN1>;
21 CAN1_RX1 => Rx1InterruptHandler<CAN1>;
22 CAN1_SCE => SceInterruptHandler<CAN1>;
23 CAN1_TX => TxInterruptHandler<CAN1>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let mut p = embassy_stm32::init(config());
29 info!("Hello World!");
30
31 // HW is connected as follows:
32 // PB13 -> PD0
33 // PB12 -> PD1
34
35 // The next two lines are a workaround for testing without transceiver.
36 // To synchronise to the bus the RX input needs to see a high level.
37 // Use `mem::forget()` to release the borrow on the pin but keep the
38 // pull-up resistor enabled.
39 let rx_pin = Input::new(&mut p.PD0, Pull::Up);
40 core::mem::forget(rx_pin);
41
42 let mut can = Can::new(p.CAN1, p.PD0, p.PD1, Irqs);
43
44 info!("Configuring can...");
45
46 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
47
48 can.set_bitrate(1_000_000);
49 can.modify_config()
50 .set_loopback(true) // Receive own frames
51 .set_silent(true)
52 // .set_bit_timing(0x001c0003)
53 .enable();
54
55 info!("Can configured");
56
57 let mut i: u8 = 0;
58 loop {
59 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
60
61 info!("Transmitting frame...");
62 can.write(&tx_frame).await;
63
64 info!("Receiving frame...");
65 let (time, rx_frame) = can.read().await.unwrap();
66
67 info!("loopback time {}", time);
68 info!("loopback frame {=u8}", rx_frame.data().unwrap()[0]);
69
70 i += 1;
71 if i > 10 {
72 break;
73 }
74 }
75
76 info!("Test OK");
77 cortex_m::asm::bkpt();
78}
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index 32d35c42c..582df5753 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -24,10 +24,8 @@ async fn main(_spawner: Spawner) {
24 24
25 info!("Starting LSI"); 25 info!("Starting LSI");
26 26
27 unsafe { 27 pac::RCC.csr().modify(|w| w.set_lsion(true));
28 pac::RCC.csr().modify(|w| w.set_lsion(true)); 28 while !pac::RCC.csr().read().lsirdy() {}
29 while !pac::RCC.csr().read().lsirdy() {}
30 }
31 29
32 info!("Started LSI"); 30 info!("Started LSI");
33 31
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index fab9f0e1b..af3832709 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -6,49 +6,246 @@
6#[path = "../common.rs"] 6#[path = "../common.rs"]
7mod common; 7mod common;
8 8
9use core::time::Duration;
10
9use common::*; 11use common::*;
10use embassy_executor::Spawner; 12use embassy_executor::Spawner;
11use embassy_stm32::tl_mbox::{Config, TlMbox}; 13use embassy_stm32::bind_interrupts;
12use embassy_stm32::{bind_interrupts, tl_mbox}; 14use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
13use embassy_time::{Duration, Timer}; 15use embassy_stm32_wpan::hci::host::uart::UartHci;
16use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
17use embassy_stm32_wpan::hci::types::AdvertisingType;
18use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
19 AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
20};
21use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands;
22use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
23use embassy_stm32_wpan::hci::BdAddr;
24use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
25use embassy_stm32_wpan::sub::mm;
26use embassy_stm32_wpan::TlMbox;
27use {defmt_rtt as _, panic_probe as _};
14 28
15bind_interrupts!(struct Irqs{ 29bind_interrupts!(struct Irqs{
16 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 30 IPCC_C1_RX => ReceiveInterruptHandler;
17 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 31 IPCC_C1_TX => TransmitInterruptHandler;
18}); 32});
19 33
34const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
35
36#[embassy_executor::task]
37async fn run_mm_queue(memory_manager: mm::MemoryManager) {
38 memory_manager.run_queue().await;
39}
40
20#[embassy_executor::main] 41#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 42async fn main(spawner: Spawner) {
22 let p = embassy_stm32::init(config()); 43 let p = embassy_stm32::init(config());
23 info!("Hello World!"); 44 info!("Hello World!");
24 45
25 let config = Config::default(); 46 let config = Config::default();
26 let mbox = TlMbox::new(p.IPCC, Irqs, config); 47 let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
48
49 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
50
51 let sys_event = mbox.sys_subsystem.read().await;
52 info!("sys event: {}", sys_event.payload());
53
54 let fw_info = mbox.sys_subsystem.wireless_fw_info().unwrap();
55 let version_major = fw_info.version_major();
56 let version_minor = fw_info.version_minor();
57 let subversion = fw_info.subversion();
58
59 let sram2a_size = fw_info.sram2a_size();
60 let sram2b_size = fw_info.sram2b_size();
61
62 info!(
63 "version {}.{}.{} - SRAM2a {} - SRAM2b {}",
64 version_major, version_minor, subversion, sram2a_size, sram2b_size
65 );
66
67 mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
68
69 info!("resetting BLE...");
70 mbox.ble_subsystem.reset().await;
71 let response = mbox.ble_subsystem.read().await.unwrap();
72 info!("{}", response);
73
74 info!("config public address...");
75 mbox.ble_subsystem
76 .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
77 .await;
78 let response = mbox.ble_subsystem.read().await.unwrap();
79 info!("{}", response);
80
81 info!("config random address...");
82 mbox.ble_subsystem
83 .write_config_data(&ConfigData::random_address(get_random_addr()).build())
84 .await;
85 let response = mbox.ble_subsystem.read().await.unwrap();
86 info!("{}", response);
87
88 info!("config identity root...");
89 mbox.ble_subsystem
90 .write_config_data(&ConfigData::identity_root(&get_irk()).build())
91 .await;
92 let response = mbox.ble_subsystem.read().await.unwrap();
93 info!("{}", response);
94
95 info!("config encryption root...");
96 mbox.ble_subsystem
97 .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
98 .await;
99 let response = mbox.ble_subsystem.read().await.unwrap();
100 info!("{}", response);
101
102 info!("config tx power level...");
103 mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
104 let response = mbox.ble_subsystem.read().await.unwrap();
105 info!("{}", response);
106
107 info!("GATT init...");
108 mbox.ble_subsystem.init_gatt().await;
109 let response = mbox.ble_subsystem.read().await.unwrap();
110 info!("{}", response);
111
112 info!("GAP init...");
113 mbox.ble_subsystem
114 .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
115 .await;
116 let response = mbox.ble_subsystem.read().await.unwrap();
117 info!("{}", response);
118
119 // info!("set scan response...");
120 // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap();
121 // let response = mbox.ble_subsystem.read().await.unwrap();
122 // info!("{}", response);
123
124 info!("set discoverable...");
125 mbox.ble_subsystem
126 .set_discoverable(&DiscoverableParameters {
127 advertising_type: AdvertisingType::NonConnectableUndirected,
128 advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))),
129 address_type: OwnAddressType::Public,
130 filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
131 local_name: None,
132 advertising_data: &[],
133 conn_interval: (None, None),
134 })
135 .await
136 .unwrap();
137
138 let response = mbox.ble_subsystem.read().await;
139 info!("{}", response);
27 140
28 loop { 141 // remove some advertisement to decrease the packet size
29 let wireless_fw_info = mbox.wireless_fw_info(); 142 info!("delete tx power ad type...");
30 match wireless_fw_info { 143 mbox.ble_subsystem
31 None => {} 144 .delete_ad_type(AdvertisingDataType::TxPowerLevel)
32 Some(fw_info) => { 145 .await;
33 let version_major = fw_info.version_major(); 146 let response = mbox.ble_subsystem.read().await.unwrap();
34 let version_minor = fw_info.version_minor(); 147 info!("{}", response);
35 let subversion = fw_info.subversion();
36 148
37 let sram2a_size = fw_info.sram2a_size(); 149 info!("delete conn interval ad type...");
38 let sram2b_size = fw_info.sram2b_size(); 150 mbox.ble_subsystem
151 .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval)
152 .await;
153 let response = mbox.ble_subsystem.read().await.unwrap();
154 info!("{}", response);
39 155
40 info!( 156 info!("update advertising data...");
41 "version {}.{}.{} - SRAM2a {} - SRAM2b {}", 157 mbox.ble_subsystem
42 version_major, version_minor, subversion, sram2a_size, sram2b_size 158 .update_advertising_data(&eddystone_advertising_data())
43 ); 159 .await
160 .unwrap();
161 let response = mbox.ble_subsystem.read().await.unwrap();
162 info!("{}", response);
44 163
45 break; 164 info!("update advertising data type...");
46 } 165 mbox.ble_subsystem
47 } 166 .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe])
167 .await
168 .unwrap();
169 let response = mbox.ble_subsystem.read().await.unwrap();
170 info!("{}", response);
48 171
49 Timer::after(Duration::from_millis(50)).await; 172 info!("update advertising data flags...");
50 } 173 mbox.ble_subsystem
174 .update_advertising_data(&[
175 2,
176 AdvertisingDataType::Flags as u8,
177 (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support
178 ])
179 .await
180 .unwrap();
181 let response = mbox.ble_subsystem.read().await.unwrap();
182 info!("{}", response);
51 183
52 info!("Test OK"); 184 info!("Test OK");
53 cortex_m::asm::bkpt(); 185 cortex_m::asm::bkpt();
54} 186}
187
188fn get_bd_addr() -> BdAddr {
189 let mut bytes = [0u8; 6];
190
191 let lhci_info = LhciC1DeviceInformationCcrp::new();
192 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
193 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
194 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
195 bytes[3] = lhci_info.device_type_id;
196 bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
197 bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
198
199 BdAddr(bytes)
200}
201
202fn get_random_addr() -> BdAddr {
203 let mut bytes = [0u8; 6];
204
205 let lhci_info = LhciC1DeviceInformationCcrp::new();
206 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
207 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
208 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
209 bytes[3] = 0;
210 bytes[4] = 0x6E;
211 bytes[5] = 0xED;
212
213 BdAddr(bytes)
214}
215
216const BLE_CFG_IRK: [u8; 16] = [
217 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
218];
219const BLE_CFG_ERK: [u8; 16] = [
220 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
221];
222
223fn get_irk() -> EncryptionKey {
224 EncryptionKey(BLE_CFG_IRK)
225}
226
227fn get_erk() -> EncryptionKey {
228 EncryptionKey(BLE_CFG_ERK)
229}
230
231fn eddystone_advertising_data() -> [u8; 24] {
232 const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com";
233
234 let mut service_data = [0u8; 24];
235 let url_len = EDDYSTONE_URL.len();
236
237 service_data[0] = 6 + url_len as u8;
238 service_data[1] = AdvertisingDataType::ServiceData as u8;
239
240 // 16-bit eddystone uuid
241 service_data[2] = 0xaa;
242 service_data[3] = 0xFE;
243
244 service_data[4] = 0x10; // URL frame type
245 service_data[5] = 22_i8 as u8; // calibrated TX power at 0m
246 service_data[6] = 0x03; // eddystone url prefix = https
247
248 service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL);
249
250 service_data
251}
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs
index 50dd2893e..c34d9574b 100644
--- a/tests/stm32/src/bin/usart_dma.rs
+++ b/tests/stm32/src/bin/usart_dma.rs
@@ -69,24 +69,27 @@ async fn main(_spawner: Spawner) {
69 const LEN: usize = 128; 69 const LEN: usize = 128;
70 let mut tx_buf = [0; LEN]; 70 let mut tx_buf = [0; LEN];
71 let mut rx_buf = [0; LEN]; 71 let mut rx_buf = [0; LEN];
72 for i in 0..LEN {
73 tx_buf[i] = i as u8;
74 }
75 72
76 let (mut tx, mut rx) = usart.split(); 73 let (mut tx, mut rx) = usart.split();
77 74
78 let tx_fut = async { 75 for n in 0..42 {
79 tx.write(&tx_buf).await.unwrap(); 76 for i in 0..LEN {
80 }; 77 tx_buf[i] = (i ^ n) as u8;
81 let rx_fut = async { 78 }
82 rx.read(&mut rx_buf).await.unwrap(); 79
83 }; 80 let tx_fut = async {
81 tx.write(&tx_buf).await.unwrap();
82 };
83 let rx_fut = async {
84 rx.read(&mut rx_buf).await.unwrap();
85 };
84 86
85 // note: rx needs to be polled first, to workaround this bug: 87 // note: rx needs to be polled first, to workaround this bug:
86 // https://github.com/embassy-rs/embassy/issues/1426 88 // https://github.com/embassy-rs/embassy/issues/1426
87 join(rx_fut, tx_fut).await; 89 join(rx_fut, tx_fut).await;
88 90
89 assert_eq!(tx_buf, rx_buf); 91 assert_eq!(tx_buf, rx_buf);
92 }
90 93
91 info!("Test OK"); 94 info!("Test OK");
92 cortex_m::asm::bkpt(); 95 cortex_m::asm::bkpt();