aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/build-nightly.sh (renamed from .github/ci/build-stable.sh)7
-rwxr-xr-x.github/ci/build.sh2
-rwxr-xr-x.github/ci/crlf.sh2
-rwxr-xr-x.github/ci/doc.sh1
-rwxr-xr-x.github/ci/rustfmt.sh12
-rwxr-xr-x.github/ci/test-nightly.sh13
-rwxr-xr-x.github/ci/test.sh5
-rw-r--r--.vscode/settings.json8
-rwxr-xr-xci-nightly.sh30
-rwxr-xr-xci.sh48
-rwxr-xr-xci_stable.sh77
-rw-r--r--cyw43-pio/README.md17
-rw-r--r--cyw43-pio/src/lib.rs26
-rw-r--r--cyw43/Cargo.toml2
-rw-r--r--cyw43/README.md4
-rw-r--r--cyw43/src/control.rs16
-rw-r--r--cyw43/src/lib.rs10
-rw-r--r--cyw43/src/runner.rs2
-rw-r--r--cyw43/src/structs.rs14
-rw-r--r--docs/modules/ROOT/examples/basic/src/main.rs1
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml2
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs1
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs2
-rw-r--r--docs/modules/ROOT/pages/bootloader.adoc4
-rw-r--r--docs/modules/ROOT/pages/faq.adoc2
-rw-r--r--embassy-boot/boot/Cargo.toml13
-rw-r--r--embassy-boot/boot/README.md19
-rw-r--r--embassy-boot/boot/src/boot_loader.rs42
-rw-r--r--embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs4
-rw-r--r--embassy-boot/boot/src/firmware_updater/asynch.rs40
-rw-r--r--embassy-boot/boot/src/firmware_updater/blocking.rs44
-rw-r--r--embassy-boot/boot/src/lib.rs11
-rw-r--r--embassy-boot/nrf/Cargo.toml8
-rw-r--r--embassy-boot/rp/Cargo.toml6
-rw-r--r--embassy-boot/stm32/Cargo.toml6
-rw-r--r--embassy-boot/stm32/src/lib.rs9
-rw-r--r--embassy-embedded-hal/Cargo.toml4
-rw-r--r--embassy-executor-macros/src/macros/task.rs19
-rw-r--r--embassy-executor/Cargo.toml88
-rw-r--r--embassy-executor/README.md2
-rw-r--r--embassy-executor/gen_config.py6
-rw-r--r--embassy-executor/src/lib.rs3
-rw-r--r--embassy-executor/tests/test.rs14
-rw-r--r--embassy-net-adin1110/Cargo.toml11
-rw-r--r--embassy-net-adin1110/src/crc32.rs8
-rw-r--r--embassy-net-adin1110/src/lib.rs7
-rw-r--r--embassy-net-adin1110/src/mdio.rs1
-rw-r--r--embassy-net-adin1110/src/regs.rs1
-rw-r--r--embassy-net-driver-channel/src/lib.rs58
-rw-r--r--embassy-net-enc28j60/Cargo.toml4
-rw-r--r--embassy-net-esp-hosted/Cargo.toml11
-rw-r--r--embassy-net-esp-hosted/README.md27
-rw-r--r--embassy-net-esp-hosted/src/control.rs20
-rw-r--r--embassy-net-esp-hosted/src/lib.rs11
-rw-r--r--embassy-net-esp-hosted/src/proto.rs108
-rw-r--r--embassy-net-tuntap/Cargo.toml3
-rw-r--r--embassy-net-tuntap/src/lib.rs13
-rw-r--r--embassy-net-wiznet/Cargo.toml5
-rw-r--r--embassy-net-wiznet/src/chip/mod.rs2
-rw-r--r--embassy-net-wiznet/src/chip/w5100s.rs1
-rw-r--r--embassy-net-wiznet/src/chip/w5500.rs1
-rw-r--r--embassy-net-wiznet/src/lib.rs2
-rw-r--r--embassy-net/Cargo.toml19
-rw-r--r--embassy-net/src/lib.rs9
-rw-r--r--embassy-net/src/udp.rs30
-rw-r--r--embassy-nrf/Cargo.toml55
-rw-r--r--embassy-nrf/README.md2
-rw-r--r--embassy-nrf/src/buffered_uarte.rs1
-rw-r--r--embassy-nrf/src/gpio.rs124
-rw-r--r--embassy-nrf/src/gpiote.rs10
-rw-r--r--embassy-nrf/src/lib.rs9
-rwxr-xr-xembassy-nrf/src/qspi.rs3
-rw-r--r--embassy-rp/Cargo.toml53
-rw-r--r--embassy-rp/README.md23
-rw-r--r--embassy-rp/src/adc.rs24
-rw-r--r--embassy-rp/src/clocks.rs119
-rw-r--r--embassy-rp/src/dma.rs20
-rw-r--r--embassy-rp/src/flash.rs42
-rw-r--r--embassy-rp/src/gpio.rs169
-rw-r--r--embassy-rp/src/i2c.rs22
-rw-r--r--embassy-rp/src/i2c_slave.rs3
-rw-r--r--embassy-rp/src/lib.rs17
-rw-r--r--embassy-rp/src/multicore.rs1
-rw-r--r--embassy-rp/src/pio/instr.rs (renamed from embassy-rp/src/pio_instr_util.rs)11
-rw-r--r--embassy-rp/src/pio/mod.rs (renamed from embassy-rp/src/pio.rs)152
-rw-r--r--embassy-rp/src/pwm.rs25
-rw-r--r--embassy-rp/src/rtc/mod.rs2
-rw-r--r--embassy-rp/src/spi.rs31
-rw-r--r--embassy-rp/src/timer.rs1
-rw-r--r--embassy-rp/src/uart/buffered.rs21
-rw-r--r--embassy-rp/src/uart/mod.rs61
-rw-r--r--embassy-rp/src/usb.rs13
-rw-r--r--embassy-stm32-wpan/Cargo.toml2
-rw-r--r--embassy-stm32/Cargo.toml15
-rw-r--r--embassy-stm32/build.rs28
-rw-r--r--embassy-stm32/src/adc/mod.rs8
-rw-r--r--embassy-stm32/src/adc/resolution.rs7
-rw-r--r--embassy-stm32/src/adc/v4.rs11
-rw-r--r--embassy-stm32/src/can/bxcan.rs118
-rw-r--r--embassy-stm32/src/can/fdcan.rs15
-rw-r--r--embassy-stm32/src/can/mod.rs1
-rw-r--r--embassy-stm32/src/crc/mod.rs1
-rw-r--r--embassy-stm32/src/crc/v1.rs4
-rw-r--r--embassy-stm32/src/crc/v2v3.rs13
-rw-r--r--embassy-stm32/src/dac/mod.rs23
-rw-r--r--embassy-stm32/src/dac/tsel.rs2
-rw-r--r--embassy-stm32/src/dcmi.rs25
-rw-r--r--embassy-stm32/src/dma/bdma.rs86
-rw-r--r--embassy-stm32/src/dma/dma.rs110
-rw-r--r--embassy-stm32/src/dma/dmamux.rs4
-rw-r--r--embassy-stm32/src/dma/gpdma.rs18
-rw-r--r--embassy-stm32/src/dma/mod.rs9
-rw-r--r--embassy-stm32/src/dma/word.rs10
-rw-r--r--embassy-stm32/src/eth/generic_smi.rs1
-rw-r--r--embassy-stm32/src/eth/mod.rs26
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs3
-rw-r--r--embassy-stm32/src/exti.rs65
-rw-r--r--embassy-stm32/src/flash/asynch.rs19
-rw-r--r--embassy-stm32/src/flash/common.rs33
-rw-r--r--embassy-stm32/src/flash/f0.rs6
-rw-r--r--embassy-stm32/src/flash/f3.rs6
-rw-r--r--embassy-stm32/src/flash/f4.rs4
-rw-r--r--embassy-stm32/src/flash/f7.rs6
-rw-r--r--embassy-stm32/src/flash/g.rs (renamed from embassy-stm32/src/flash/g0.rs)6
-rw-r--r--embassy-stm32/src/flash/h7.rs6
-rw-r--r--embassy-stm32/src/flash/l.rs6
-rw-r--r--embassy-stm32/src/flash/mod.rs69
-rw-r--r--embassy-stm32/src/flash/other.rs4
-rw-r--r--embassy-stm32/src/fmc.rs5
-rw-r--r--embassy-stm32/src/gpio.rs177
-rw-r--r--embassy-stm32/src/hrtim/mod.rs77
-rw-r--r--embassy-stm32/src/hrtim/traits.rs6
-rw-r--r--embassy-stm32/src/i2c/mod.rs170
-rw-r--r--embassy-stm32/src/i2c/v1.rs171
-rw-r--r--embassy-stm32/src/i2c/v2.rs460
-rw-r--r--embassy-stm32/src/i2s.rs36
-rw-r--r--embassy-stm32/src/ipcc.rs8
-rw-r--r--embassy-stm32/src/lib.rs76
-rw-r--r--embassy-stm32/src/low_power.rs107
-rw-r--r--embassy-stm32/src/opamp.rs9
-rw-r--r--embassy-stm32/src/qspi/enums.rs43
-rw-r--r--embassy-stm32/src/qspi/mod.rs19
-rw-r--r--embassy-stm32/src/rcc/h.rs44
-rw-r--r--embassy-stm32/src/rcc/mod.rs3
-rw-r--r--embassy-stm32/src/rng.rs17
-rw-r--r--embassy-stm32/src/rtc/datetime.rs12
-rw-r--r--embassy-stm32/src/rtc/mod.rs37
-rw-r--r--embassy-stm32/src/rtc/v2.rs8
-rw-r--r--embassy-stm32/src/rtc/v3.rs14
-rw-r--r--embassy-stm32/src/sai/mod.rs540
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs92
-rw-r--r--embassy-stm32/src/spi/mod.rs49
-rw-r--r--embassy-stm32/src/time.rs3
-rw-r--r--embassy-stm32/src/time_driver.rs40
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs33
-rw-r--r--embassy-stm32/src/timer/mod.rs163
-rw-r--r--embassy-stm32/src/timer/qei.rs25
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs47
-rw-r--r--embassy-stm32/src/traits.rs30
-rw-r--r--embassy-stm32/src/uid.rs2
-rw-r--r--embassy-stm32/src/usart/buffered.rs12
-rw-r--r--embassy-stm32/src/usart/mod.rs73
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs9
-rw-r--r--embassy-stm32/src/usb/mod.rs4
-rw-r--r--embassy-stm32/src/usb/usb.rs13
-rw-r--r--embassy-stm32/src/usb_otg/mod.rs4
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs13
-rw-r--r--embassy-stm32/src/wdg/mod.rs5
-rw-r--r--embassy-sync/src/signal.rs14
-rw-r--r--embassy-time/CHANGELOG.md4
-rw-r--r--embassy-time/Cargo.toml356
-rw-r--r--embassy-time/README.md36
-rw-r--r--embassy-time/gen_tick.py23
-rw-r--r--embassy-time/src/driver.rs17
-rw-r--r--embassy-time/src/lib.rs8
-rw-r--r--embassy-time/src/tick.rs390
-rw-r--r--embassy-time/src/timer.rs7
-rw-r--r--embassy-usb-dfu/Cargo.toml32
-rw-r--r--embassy-usb-dfu/README.md20
-rw-r--r--embassy-usb-dfu/src/application.rs136
-rw-r--r--embassy-usb-dfu/src/consts.rs101
-rw-r--r--embassy-usb-dfu/src/dfu.rs190
-rw-r--r--embassy-usb-dfu/src/fmt.rs258
-rw-r--r--embassy-usb-dfu/src/lib.rs56
-rw-r--r--embassy-usb-logger/README.md14
-rw-r--r--examples/boot/application/nrf/Cargo.toml2
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs1
-rw-r--r--examples/boot/application/nrf/src/bin/b.rs1
-rw-r--r--examples/boot/application/rp/Cargo.toml2
-rw-r--r--examples/boot/application/rp/src/bin/a.rs1
-rw-r--r--examples/boot/application/rp/src/bin/b.rs1
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f3/src/bin/a.rs1
-rw-r--r--examples/boot/application/stm32f3/src/bin/b.rs1
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs1
-rw-r--r--examples/boot/application/stm32f7/src/bin/b.rs1
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs1
-rw-r--r--examples/boot/application/stm32h7/src/bin/b.rs1
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l0/src/bin/a.rs1
-rw-r--r--examples/boot/application/stm32l0/src/bin/b.rs1
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l1/src/bin/a.rs1
-rw-r--r--examples/boot/application/stm32l1/src/bin/b.rs1
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l4/src/bin/a.rs1
-rw-r--r--examples/boot/application/stm32l4/src/bin/b.rs1
-rw-r--r--examples/boot/application/stm32wb-dfu/.cargo/config.toml9
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml32
-rw-r--r--examples/boot/application/stm32wb-dfu/README.md29
-rw-r--r--examples/boot/application/stm32wb-dfu/build.rs37
-rw-r--r--examples/boot/application/stm32wb-dfu/memory.x15
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs63
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs1
-rw-r--r--examples/boot/application/stm32wl/src/bin/b.rs1
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml63
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/README.md11
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/build.rs27
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/memory.x18
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs93
-rw-r--r--examples/nrf-rtos-trace/src/bin/rtos_trace.rs1
-rw-r--r--examples/nrf52840/Cargo.toml12
-rw-r--r--examples/nrf52840/src/bin/blinky.rs1
-rw-r--r--examples/nrf52840/src/bin/buffered_uart.rs1
-rw-r--r--examples/nrf52840/src/bin/channel.rs1
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs1
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs18
-rw-r--r--examples/nrf52840/src/bin/executor_fairness_test.rs1
-rw-r--r--examples/nrf52840/src/bin/gpiote_channel.rs1
-rw-r--r--examples/nrf52840/src/bin/gpiote_port.rs1
-rw-r--r--examples/nrf52840/src/bin/i2s_effect.rs1
-rw-r--r--examples/nrf52840/src/bin/i2s_monitor.rs1
-rw-r--r--examples/nrf52840/src/bin/i2s_waveform.rs1
-rw-r--r--examples/nrf52840/src/bin/manually_create_executor.rs1
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs1
-rw-r--r--examples/nrf52840/src/bin/mutex.rs1
-rw-r--r--examples/nrf52840/src/bin/nvmc.rs1
-rw-r--r--examples/nrf52840/src/bin/pdm.rs1
-rw-r--r--examples/nrf52840/src/bin/pdm_continuous.rs1
-rw-r--r--examples/nrf52840/src/bin/ppi.rs1
-rw-r--r--examples/nrf52840/src/bin/pubsub.rs1
-rw-r--r--examples/nrf52840/src/bin/pwm.rs1
-rw-r--r--examples/nrf52840/src/bin/pwm_double_sequence.rs1
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence.rs1
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ppi.rs1
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs1
-rw-r--r--examples/nrf52840/src/bin/pwm_servo.rs1
-rw-r--r--examples/nrf52840/src/bin/qdec.rs1
-rw-r--r--examples/nrf52840/src/bin/qspi.rs1
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs1
-rw-r--r--examples/nrf52840/src/bin/rng.rs1
-rw-r--r--examples/nrf52840/src/bin/saadc.rs1
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs1
-rw-r--r--examples/nrf52840/src/bin/self_spawn.rs1
-rw-r--r--examples/nrf52840/src/bin/self_spawn_current_executor.rs1
-rw-r--r--examples/nrf52840/src/bin/spim.rs1
-rw-r--r--examples/nrf52840/src/bin/spis.rs1
-rw-r--r--examples/nrf52840/src/bin/temp.rs1
-rw-r--r--examples/nrf52840/src/bin/timer.rs1
-rw-r--r--examples/nrf52840/src/bin/twim.rs1
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs1
-rw-r--r--examples/nrf52840/src/bin/twis.rs1
-rw-r--r--examples/nrf52840/src/bin/uart.rs1
-rw-r--r--examples/nrf52840/src/bin/uart_idle.rs1
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs33
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs21
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs1
-rw-r--r--examples/nrf52840/src/bin/wdt.rs1
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs14
-rw-r--r--examples/nrf5340/Cargo.toml4
-rw-r--r--examples/nrf5340/src/bin/blinky.rs1
-rw-r--r--examples/nrf5340/src/bin/gpiote_channel.rs1
-rw-r--r--examples/nrf5340/src/bin/uart.rs1
-rw-r--r--examples/rp/Cargo.toml10
-rw-r--r--examples/rp/src/bin/adc.rs1
-rw-r--r--examples/rp/src/bin/blinky.rs1
-rw-r--r--examples/rp/src/bin/button.rs3
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs14
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs14
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs14
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs14
-rw-r--r--examples/rp/src/bin/flash.rs1
-rw-r--r--examples/rp/src/bin/gpio_async.rs1
-rw-r--r--examples/rp/src/bin/gpout.rs1
-rw-r--r--examples/rp/src/bin/i2c_async.rs1
-rw-r--r--examples/rp/src/bin/i2c_blocking.rs1
-rw-r--r--examples/rp/src/bin/i2c_slave.rs1
-rw-r--r--examples/rp/src/bin/multicore.rs1
-rw-r--r--examples/rp/src/bin/multiprio.rs1
-rw-r--r--examples/rp/src/bin/pio_async.rs1
-rw-r--r--examples/rp/src/bin/pio_dma.rs1
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs1
-rw-r--r--examples/rp/src/bin/pio_rotary_encoder.rs1
-rw-r--r--examples/rp/src/bin/pio_stepper.rs1
-rw-r--r--examples/rp/src/bin/pio_uart.rs1
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs1
-rw-r--r--examples/rp/src/bin/pwm.rs1
-rw-r--r--examples/rp/src/bin/pwm_input.rs1
-rw-r--r--examples/rp/src/bin/rosc.rs1
-rw-r--r--examples/rp/src/bin/rtc.rs1
-rw-r--r--examples/rp/src/bin/spi.rs1
-rw-r--r--examples/rp/src/bin/spi_async.rs1
-rw-r--r--examples/rp/src/bin/spi_display.rs1
-rw-r--r--examples/rp/src/bin/uart.rs1
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs9
-rw-r--r--examples/rp/src/bin/uart_unidir.rs1
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs29
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs1
-rw-r--r--examples/rp/src/bin/usb_logger.rs1
-rw-r--r--examples/rp/src/bin/usb_midi.rs1
-rw-r--r--examples/rp/src/bin/usb_raw.rs1
-rw-r--r--examples/rp/src/bin/usb_raw_bulk.rs1
-rw-r--r--examples/rp/src/bin/usb_serial.rs1
-rw-r--r--examples/rp/src/bin/watchdog.rs1
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs14
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs6
-rw-r--r--examples/rp/src/bin/wifi_scan.rs6
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs14
-rw-r--r--examples/std/Cargo.toml4
-rw-r--r--examples/std/src/bin/net.rs12
-rw-r--r--examples/std/src/bin/net_dns.rs12
-rw-r--r--examples/std/src/bin/net_ppp.rs14
-rw-r--r--examples/std/src/bin/net_udp.rs12
-rw-r--r--examples/std/src/bin/serial.rs2
-rw-r--r--examples/std/src/bin/tcp_accept.rs12
-rw-r--r--examples/std/src/bin/tick.rs2
-rw-r--r--examples/stm32c0/Cargo.toml2
-rw-r--r--examples/stm32c0/src/bin/blinky.rs1
-rw-r--r--examples/stm32c0/src/bin/button.rs3
-rw-r--r--examples/stm32c0/src/bin/button_exti.rs1
-rw-r--r--examples/stm32f0/Cargo.toml4
-rw-r--r--examples/stm32f0/src/bin/adc.rs1
-rw-r--r--examples/stm32f0/src/bin/blinky.rs1
-rw-r--r--examples/stm32f0/src/bin/button_controlled_blink.rs1
-rw-r--r--examples/stm32f0/src/bin/button_exti.rs1
-rw-r--r--examples/stm32f0/src/bin/hello.rs1
-rw-r--r--examples/stm32f0/src/bin/multiprio.rs1
-rw-r--r--examples/stm32f0/src/bin/wdg.rs1
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f1/src/bin/adc.rs1
-rw-r--r--examples/stm32f1/src/bin/blinky.rs1
-rw-r--r--examples/stm32f1/src/bin/can.rs66
-rw-r--r--examples/stm32f1/src/bin/hello.rs1
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f2/Cargo.toml2
-rw-r--r--examples/stm32f2/src/bin/blinky.rs1
-rw-r--r--examples/stm32f2/src/bin/pll.rs1
-rw-r--r--examples/stm32f3/Cargo.toml4
-rw-r--r--examples/stm32f3/src/bin/blinky.rs1
-rw-r--r--examples/stm32f3/src/bin/button.rs3
-rw-r--r--examples/stm32f3/src/bin/button_events.rs1
-rw-r--r--examples/stm32f3/src/bin/button_exti.rs1
-rw-r--r--examples/stm32f3/src/bin/flash.rs1
-rw-r--r--examples/stm32f3/src/bin/hello.rs1
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs1
-rw-r--r--examples/stm32f3/src/bin/spi_dma.rs1
-rw-r--r--examples/stm32f3/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f334/Cargo.toml4
-rw-r--r--examples/stm32f334/src/bin/adc.rs1
-rw-r--r--examples/stm32f334/src/bin/button.rs1
-rw-r--r--examples/stm32f334/src/bin/hello.rs1
-rw-r--r--examples/stm32f334/src/bin/opamp.rs1
-rw-r--r--examples/stm32f334/src/bin/pwm.rs1
-rw-r--r--examples/stm32f4/Cargo.toml6
-rw-r--r--examples/stm32f4/src/bin/adc.rs1
-rw-r--r--examples/stm32f4/src/bin/blinky.rs1
-rw-r--r--examples/stm32f4/src/bin/button.rs3
-rw-r--r--examples/stm32f4/src/bin/button_exti.rs1
-rw-r--r--examples/stm32f4/src/bin/can.rs1
-rw-r--r--examples/stm32f4/src/bin/dac.rs1
-rw-r--r--examples/stm32f4/src/bin/eth.rs14
-rw-r--r--examples/stm32f4/src/bin/flash.rs7
-rw-r--r--examples/stm32f4/src/bin/flash_async.rs7
-rw-r--r--examples/stm32f4/src/bin/hello.rs1
-rw-r--r--examples/stm32f4/src/bin/i2c.rs1
-rw-r--r--examples/stm32f4/src/bin/i2c_async.rs1
-rw-r--r--examples/stm32f4/src/bin/i2c_comparison.rs1
-rw-r--r--examples/stm32f4/src/bin/i2s_dma.rs1
-rw-r--r--examples/stm32f4/src/bin/mco.rs1
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs1
-rw-r--r--examples/stm32f4/src/bin/pwm.rs1
-rw-r--r--examples/stm32f4/src/bin/pwm_complementary.rs1
-rw-r--r--examples/stm32f4/src/bin/rtc.rs1
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs1
-rw-r--r--examples/stm32f4/src/bin/spi.rs1
-rw-r--r--examples/stm32f4/src/bin/spi_dma.rs1
-rw-r--r--examples/stm32f4/src/bin/usart.rs1
-rw-r--r--examples/stm32f4/src/bin/usart_buffered.rs1
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs32
-rw-r--r--examples/stm32f4/src/bin/usb_raw.rs1
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f4/src/bin/wdt.rs1
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm_dma.rs150
-rw-r--r--examples/stm32f4/src/bin/ws2812_spi.rs95
-rw-r--r--examples/stm32f7/Cargo.toml4
-rw-r--r--examples/stm32f7/src/bin/adc.rs1
-rw-r--r--examples/stm32f7/src/bin/blinky.rs1
-rw-r--r--examples/stm32f7/src/bin/button.rs3
-rw-r--r--examples/stm32f7/src/bin/button_exti.rs1
-rw-r--r--examples/stm32f7/src/bin/can.rs8
-rw-r--r--examples/stm32f7/src/bin/eth.rs14
-rw-r--r--examples/stm32f7/src/bin/flash.rs1
-rw-r--r--examples/stm32f7/src/bin/hello.rs1
-rw-r--r--examples/stm32f7/src/bin/sdmmc.rs1
-rw-r--r--examples/stm32f7/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32g0/src/bin/blinky.rs1
-rw-r--r--examples/stm32g0/src/bin/button.rs3
-rw-r--r--examples/stm32g0/src/bin/button_exti.rs1
-rw-r--r--examples/stm32g0/src/bin/flash.rs1
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs1
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32g4/src/bin/adc.rs1
-rw-r--r--examples/stm32g4/src/bin/blinky.rs1
-rw-r--r--examples/stm32g4/src/bin/button.rs3
-rw-r--r--examples/stm32g4/src/bin/button_exti.rs1
-rw-r--r--examples/stm32g4/src/bin/pll.rs1
-rw-r--r--examples/stm32g4/src/bin/pwm.rs1
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32h5/Cargo.toml8
-rw-r--r--examples/stm32h5/src/bin/blinky.rs1
-rw-r--r--examples/stm32h5/src/bin/button_exti.rs1
-rw-r--r--examples/stm32h5/src/bin/eth.rs14
-rw-r--r--examples/stm32h5/src/bin/i2c.rs1
-rw-r--r--examples/stm32h5/src/bin/rng.rs1
-rw-r--r--examples/stm32h5/src/bin/usart.rs1
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs1
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32h7/Cargo.toml8
-rw-r--r--examples/stm32h7/src/bin/adc.rs1
-rw-r--r--examples/stm32h7/src/bin/blinky.rs1
-rw-r--r--examples/stm32h7/src/bin/button_exti.rs1
-rw-r--r--examples/stm32h7/src/bin/camera.rs1
-rw-r--r--examples/stm32h7/src/bin/dac.rs1
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs7
-rw-r--r--examples/stm32h7/src/bin/eth.rs14
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs14
-rw-r--r--examples/stm32h7/src/bin/flash.rs1
-rw-r--r--examples/stm32h7/src/bin/fmc.rs1
-rw-r--r--examples/stm32h7/src/bin/i2c.rs1
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs11
-rw-r--r--examples/stm32h7/src/bin/mco.rs1
-rw-r--r--examples/stm32h7/src/bin/pwm.rs1
-rw-r--r--examples/stm32h7/src/bin/rng.rs1
-rw-r--r--examples/stm32h7/src/bin/rtc.rs1
-rw-r--r--examples/stm32h7/src/bin/sdmmc.rs1
-rw-r--r--examples/stm32h7/src/bin/signal.rs1
-rw-r--r--examples/stm32h7/src/bin/spi.rs1
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs1
-rw-r--r--examples/stm32h7/src/bin/usart.rs1
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs1
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32h7/src/bin/wdg.rs1
-rw-r--r--examples/stm32l0/Cargo.toml4
-rw-r--r--examples/stm32l0/src/bin/blinky.rs1
-rw-r--r--examples/stm32l0/src/bin/button.rs3
-rw-r--r--examples/stm32l0/src/bin/button_exti.rs1
-rw-r--r--examples/stm32l0/src/bin/flash.rs1
-rw-r--r--examples/stm32l0/src/bin/spi.rs1
-rw-r--r--examples/stm32l0/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32l0/src/bin/usart_irq.rs1
-rw-r--r--examples/stm32l1/Cargo.toml2
-rw-r--r--examples/stm32l1/src/bin/blinky.rs1
-rw-r--r--examples/stm32l1/src/bin/flash.rs1
-rw-r--r--examples/stm32l1/src/bin/spi.rs1
-rw-r--r--examples/stm32l4/Cargo.toml10
-rw-r--r--examples/stm32l4/src/bin/adc.rs1
-rw-r--r--examples/stm32l4/src/bin/blinky.rs1
-rw-r--r--examples/stm32l4/src/bin/button.rs3
-rw-r--r--examples/stm32l4/src/bin/button_exti.rs1
-rw-r--r--examples/stm32l4/src/bin/dac.rs1
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs7
-rw-r--r--examples/stm32l4/src/bin/i2c.rs1
-rw-r--r--examples/stm32l4/src/bin/i2c_blocking_async.rs1
-rw-r--r--examples/stm32l4/src/bin/i2c_dma.rs1
-rw-r--r--examples/stm32l4/src/bin/mco.rs1
-rw-r--r--examples/stm32l4/src/bin/rng.rs1
-rw-r--r--examples/stm32l4/src/bin/rtc.rs1
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs28
-rw-r--r--examples/stm32l4/src/bin/spi.rs1
-rw-r--r--examples/stm32l4/src/bin/spi_blocking_async.rs3
-rw-r--r--examples/stm32l4/src/bin/spi_dma.rs3
-rw-r--r--examples/stm32l4/src/bin/usart.rs1
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32l5/Cargo.toml4
-rw-r--r--examples/stm32l5/src/bin/button_exti.rs1
-rw-r--r--examples/stm32l5/src/bin/rng.rs1
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs29
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs1
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32u5/Cargo.toml2
-rw-r--r--examples/stm32u5/src/bin/blinky.rs1
-rw-r--r--examples/stm32u5/src/bin/boot.rs1
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32wb/Cargo.toml4
-rw-r--r--examples/stm32wb/src/bin/blinky.rs1
-rw-r--r--examples/stm32wb/src/bin/button_exti.rs1
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs1
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs1
-rw-r--r--examples/stm32wb/src/bin/mac_ffd.rs1
-rw-r--r--examples/stm32wb/src/bin/mac_ffd_net.rs21
-rw-r--r--examples/stm32wb/src/bin/mac_rfd.rs1
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs1
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs1
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_mac.rs1
-rw-r--r--examples/stm32wba/Cargo.toml4
-rw-r--r--examples/stm32wba/src/bin/blinky.rs1
-rw-r--r--examples/stm32wba/src/bin/button_exti.rs1
-rw-r--r--examples/stm32wl/Cargo.toml2
-rw-r--r--examples/stm32wl/src/bin/blinky.rs1
-rw-r--r--examples/stm32wl/src/bin/button.rs3
-rw-r--r--examples/stm32wl/src/bin/button_exti.rs1
-rw-r--r--examples/stm32wl/src/bin/flash.rs1
-rw-r--r--examples/stm32wl/src/bin/random.rs1
-rw-r--r--examples/stm32wl/src/bin/rtc.rs1
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs1
-rw-r--r--examples/wasm/Cargo.toml2
-rw-r--r--examples/wasm/src/lib.rs2
-rw-r--r--rust-toolchain-nightly.toml12
-rw-r--r--rust-toolchain.toml8
-rw-r--r--tests/nrf/Cargo.toml6
-rw-r--r--tests/nrf/src/bin/ethernet_enc28j60_perf.rs11
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs14
-rw-r--r--tests/rp/Cargo.toml8
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs14
-rw-r--r--tests/rp/src/bin/ethernet_w5100s_perf.rs14
-rw-r--r--tests/rp/src/bin/gpio.rs10
-rw-r--r--tests/rp/src/bin/pwm.rs8
-rw-r--r--tests/stm32/Cargo.toml6
-rw-r--r--tests/stm32/src/bin/eth.rs14
-rw-r--r--tests/stm32/src/bin/gpio.rs12
-rw-r--r--tests/stm32/src/bin/stop.rs6
546 files changed, 6096 insertions, 2787 deletions
diff --git a/.github/ci/build-stable.sh b/.github/ci/build-nightly.sh
index 9160a2be2..95cb4100c 100755
--- a/.github/ci/build-stable.sh
+++ b/.github/ci/build-nightly.sh
@@ -7,6 +7,7 @@ set -euo pipefail
7export RUSTUP_HOME=/ci/cache/rustup 7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10mv rust-toolchain-nightly.toml rust-toolchain.toml
10 11
11# needed for "dumb HTTP" transport support 12# needed for "dumb HTTP" transport support
12# used when pointing stm32-metapac to a CI-built one. 13# used when pointing stm32-metapac to a CI-built one.
@@ -21,10 +22,8 @@ fi
21hashtime restore /ci/cache/filetime.json || true 22hashtime restore /ci/cache/filetime.json || true
22hashtime save /ci/cache/filetime.json 23hashtime save /ci/cache/filetime.json
23 24
24sed -i 's/channel.*/channel = "beta"/g' rust-toolchain.toml 25./ci-nightly.sh
25
26./ci_stable.sh
27 26
28# Save lockfiles 27# Save lockfiles
29echo Saving lockfiles... 28echo Saving lockfiles...
30find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+ \ No newline at end of file 29find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+
diff --git a/.github/ci/build.sh b/.github/ci/build.sh
index e7a6c0d86..77d2b3cab 100755
--- a/.github/ci/build.sh
+++ b/.github/ci/build.sh
@@ -31,4 +31,4 @@ hashtime save /ci/cache/filetime.json
31 31
32# Save lockfiles 32# Save lockfiles
33echo Saving lockfiles... 33echo Saving lockfiles...
34find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+ \ No newline at end of file 34find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+
diff --git a/.github/ci/crlf.sh b/.github/ci/crlf.sh
index 457510407..69838ce88 100755
--- a/.github/ci/crlf.sh
+++ b/.github/ci/crlf.sh
@@ -14,4 +14,4 @@ else
14 echo -e "ERROR: Found ${NR_FILES} files with CRLF endings." 14 echo -e "ERROR: Found ${NR_FILES} files with CRLF endings."
15 echo "$FILES_WITH_CRLF" 15 echo "$FILES_WITH_CRLF"
16 exit "$NR_FILES" 16 exit "$NR_FILES"
17fi \ No newline at end of file 17fi
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index ed3036f2f..fbed2752a 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -8,6 +8,7 @@ export CARGO_HOME=/ci/cache/cargo
8export CARGO_TARGET_DIR=/ci/cache/target 8export CARGO_TARGET_DIR=/ci/cache/target
9export BUILDER_THREADS=4 9export BUILDER_THREADS=4
10export BUILDER_COMPRESS=true 10export BUILDER_COMPRESS=true
11mv rust-toolchain-nightly.toml rust-toolchain.toml
11 12
12# force rustup to download the toolchain before starting building. 13# force rustup to download the toolchain before starting building.
13# Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently. 14# Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently.
diff --git a/.github/ci/rustfmt.sh b/.github/ci/rustfmt.sh
new file mode 100755
index 000000000..369239cfe
--- /dev/null
+++ b/.github/ci/rustfmt.sh
@@ -0,0 +1,12 @@
1#!/bin/bash
2## on push branch~=gh-readonly-queue/main/.*
3## on pull_request
4
5set -euo pipefail
6
7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target
10mv rust-toolchain-nightly.toml rust-toolchain.toml
11
12find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
diff --git a/.github/ci/test-nightly.sh b/.github/ci/test-nightly.sh
new file mode 100755
index 000000000..d6e5dc574
--- /dev/null
+++ b/.github/ci/test-nightly.sh
@@ -0,0 +1,13 @@
1#!/bin/bash
2## on push branch~=gh-readonly-queue/main/.*
3## on pull_request
4
5set -euo pipefail
6
7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target
10mv rust-toolchain-nightly.toml rust-toolchain.toml
11
12MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml
13MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index 1ee760d31..369f6d221 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -4,8 +4,9 @@
4 4
5set -euo pipefail 5set -euo pipefail
6 6
7MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml 7export RUSTUP_HOME=/ci/cache/rustup
8MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target
9 10
10cargo test --manifest-path ./embassy-sync/Cargo.toml 11cargo test --manifest-path ./embassy-sync/Cargo.toml
11cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml 12cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
diff --git a/.vscode/settings.json b/.vscode/settings.json
index d46ce603b..a5b23175a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -15,14 +15,10 @@
15 //"rust-analyzer.cargo.target": "thumbv7m-none-eabi", 15 //"rust-analyzer.cargo.target": "thumbv7m-none-eabi",
16 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 16 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
17 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 17 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
18 "rust-analyzer.cargo.features": [
19 // Uncomment if the example has a "nightly" feature.
20 "nightly",
21 ],
22 "rust-analyzer.linkedProjects": [ 18 "rust-analyzer.linkedProjects": [
23 // Uncomment ONE line for the chip you want to work on. 19 // Uncomment ONE line for the chip you want to work on.
24 // This makes rust-analyzer work on the example crate and all its dependencies. 20 // This makes rust-analyzer work on the example crate and all its dependencies.
25 "examples/nrf52840/Cargo.toml", 21 "examples/stm32l4/Cargo.toml",
26 // "examples/nrf52840-rtic/Cargo.toml", 22 // "examples/nrf52840-rtic/Cargo.toml",
27 // "examples/nrf5340/Cargo.toml", 23 // "examples/nrf5340/Cargo.toml",
28 // "examples/nrf-rtos-trace/Cargo.toml", 24 // "examples/nrf-rtos-trace/Cargo.toml",
@@ -49,4 +45,4 @@
49 // "examples/stm32wl/Cargo.toml", 45 // "examples/stm32wl/Cargo.toml",
50 // "examples/wasm/Cargo.toml", 46 // "examples/wasm/Cargo.toml",
51 ], 47 ],
52} \ No newline at end of file 48}
diff --git a/ci-nightly.sh b/ci-nightly.sh
new file mode 100755
index 000000000..1fc9692b5
--- /dev/null
+++ b/ci-nightly.sh
@@ -0,0 +1,30 @@
1#!/bin/bash
2
3set -eo pipefail
4
5export RUSTFLAGS=-Dwarnings
6export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
7if [[ -z "${CARGO_TARGET_DIR}" ]]; then
8 export CARGO_TARGET_DIR=target_ci
9fi
10
11cargo batch \
12 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \
13 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
14 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
15 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
16 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
17 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \
18 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \
19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \
21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
22 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \
23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
26 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \
27 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \
29 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
30
diff --git a/ci.sh b/ci.sh
index a804647e1..75640e384 100755
--- a/ci.sh
+++ b/ci.sh
@@ -15,26 +15,24 @@ if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then
15 BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std" 15 BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std"
16fi 16fi
17 17
18find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
19
20cargo batch \ 18cargo batch \
21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \ 19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \
22 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ 20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ 21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 22 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ 23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
26 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \ 24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \
27 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \ 25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \ 26 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
29 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \ 27 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \
30 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \ 28 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \
31 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \ 29 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,integrated-timers \
32 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ 30 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \
33 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ 31 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
34 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ 32 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \
35 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \ 33 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,integrated-timers \
36 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ 34 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \
37 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ 35 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \
38 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ 36 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
39 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ 37 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
40 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ 38 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
@@ -91,12 +89,12 @@ cargo batch \
91 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \ 89 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \
92 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \ 90 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \
93 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \ 91 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \
94 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embedded-sdmmc,time \ 92 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
95 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \ 93 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \
96 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \ 94 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \
97 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \ 95 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \
98 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \ 96 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \
99 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,embedded-sdmmc,time \ 97 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,time \
100 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \ 98 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \
101 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \ 99 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \
102 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \ 100 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \
@@ -140,7 +138,6 @@ cargo batch \
140 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ 138 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
141 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ 139 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
142 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ 140 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
143 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
144 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ 141 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
145 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ 142 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
146 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ 143 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
@@ -173,10 +170,12 @@ cargo batch \
173 --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \ 170 --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \
174 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \ 171 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \
175 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \ 172 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \
173 --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wb-dfu \
176 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 174 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
177 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 175 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
178 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ 176 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
179 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 177 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
178 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf \
180 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ 179 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
181 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ 180 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
182 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ 181 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
@@ -207,10 +206,9 @@ cargo batch \
207 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ 206 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
208 $BUILD_EXTRA 207 $BUILD_EXTRA
209 208
210# walkaround: "-Z" option not working on cargo batch
211cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p
212cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,integrated-timers,avr-device/atmega328p
213 209
210# failed, a wire must've come loose, will check asap.
211rm out/tests/rpi-pico/i2c
214 212
215rm out/tests/stm32wb55rg/wpan_mac 213rm out/tests/stm32wb55rg/wpan_mac
216rm out/tests/stm32wb55rg/wpan_ble 214rm out/tests/stm32wb55rg/wpan_ble
diff --git a/ci_stable.sh b/ci_stable.sh
deleted file mode 100755
index 66ed8f79d..000000000
--- a/ci_stable.sh
+++ /dev/null
@@ -1,77 +0,0 @@
1#!/bin/bash
2
3set -euo pipefail
4
5export RUSTFLAGS=-Dwarnings
6export DEFMT_LOG=trace
7
8cargo batch \
9 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
10 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
11 --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \
12 --- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
13 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \
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 \
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,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 \
19 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
20 --- 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 \
22 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
23 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time-driver-rtc1 \
24 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time-driver-rtc1 \
25 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time-driver-rtc1 \
26 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time-driver-rtc1 \
27 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time-driver-rtc1 \
28 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time-driver-rtc1 \
29 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time-driver-rtc1 \
30 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time-driver-rtc1 \
31 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \
32 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,log,gpiote,time-driver-rtc1 \
33 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,defmt,gpiote,time-driver-rtc1 \
34 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features defmt \
35 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features log \
36 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi \
37 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features qspi-as-gpio \
38 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any \
39 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any \
40 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any \
41 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any \
42 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any \
43 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,time \
44 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,time \
45 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,time \
46 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,time \
47 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,time \
48 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,time \
49 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,time \
50 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \
51 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \
52 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \
53 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \
54 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \
55 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \
56 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \
57 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \
58 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \
59 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \
60 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \
61 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \
62 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
63 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
64 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
65 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
66 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
67 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
68 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
69 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
70 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
71 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
72 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
73 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
74 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
75 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
76 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf52840 --bin raw_spawn \
77 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \
diff --git a/cyw43-pio/README.md b/cyw43-pio/README.md
new file mode 100644
index 000000000..2b22db360
--- /dev/null
+++ b/cyw43-pio/README.md
@@ -0,0 +1,17 @@
1# cyw43-pio
2
3RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. The PIO driver offloads SPI communication with the WiFi chip and improves throughput.
4
5## Minimum supported Rust version (MSRV)
6
7Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
8
9## License
10
11This work is licensed under either of
12
13- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
14 <http://www.apache.org/licenses/LICENSE-2.0>)
15- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
16
17at your option.
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
index 41b670324..5efab10e4 100644
--- a/cyw43-pio/src/lib.rs
+++ b/cyw43-pio/src/lib.rs
@@ -1,16 +1,19 @@
1#![no_std] 1#![no_std]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
3 5
4use core::slice; 6use core::slice;
5 7
6use cyw43::SpiBusCyw43; 8use cyw43::SpiBusCyw43;
7use embassy_rp::dma::Channel; 9use embassy_rp::dma::Channel;
8use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate}; 10use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate};
9use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; 11use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine};
10use embassy_rp::{pio_instr_util, Peripheral, PeripheralRef}; 12use embassy_rp::{Peripheral, PeripheralRef};
11use fixed::FixedU32; 13use fixed::FixedU32;
12use pio_proc::pio_asm; 14use pio_proc::pio_asm;
13 15
16/// SPI comms driven by PIO.
14pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> { 17pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> {
15 cs: Output<'d, CS>, 18 cs: Output<'d, CS>,
16 sm: StateMachine<'d, PIO, SM>, 19 sm: StateMachine<'d, PIO, SM>,
@@ -25,6 +28,7 @@ where
25 CS: Pin, 28 CS: Pin,
26 PIO: Instance, 29 PIO: Instance,
27{ 30{
31 /// Create a new instance of PioSpi.
28 pub fn new<DIO, CLK>( 32 pub fn new<DIO, CLK>(
29 common: &mut Common<'d, PIO>, 33 common: &mut Common<'d, PIO>,
30 mut sm: StateMachine<'d, PIO, SM>, 34 mut sm: StateMachine<'d, PIO, SM>,
@@ -143,6 +147,7 @@ where
143 } 147 }
144 } 148 }
145 149
150 /// Write data to peripheral and return status.
146 pub async fn write(&mut self, write: &[u32]) -> u32 { 151 pub async fn write(&mut self, write: &[u32]) -> u32 {
147 self.sm.set_enable(false); 152 self.sm.set_enable(false);
148 let write_bits = write.len() * 32 - 1; 153 let write_bits = write.len() * 32 - 1;
@@ -152,10 +157,10 @@ where
152 defmt::trace!("write={} read={}", write_bits, read_bits); 157 defmt::trace!("write={} read={}", write_bits, read_bits);
153 158
154 unsafe { 159 unsafe {
155 pio_instr_util::set_x(&mut self.sm, write_bits as u32); 160 instr::set_x(&mut self.sm, write_bits as u32);
156 pio_instr_util::set_y(&mut self.sm, read_bits as u32); 161 instr::set_y(&mut self.sm, read_bits as u32);
157 pio_instr_util::set_pindir(&mut self.sm, 0b1); 162 instr::set_pindir(&mut self.sm, 0b1);
158 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); 163 instr::exec_jmp(&mut self.sm, self.wrap_target);
159 } 164 }
160 165
161 self.sm.set_enable(true); 166 self.sm.set_enable(true);
@@ -170,6 +175,7 @@ where
170 status 175 status
171 } 176 }
172 177
178 /// Send command and read response into buffer.
173 pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 { 179 pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 {
174 self.sm.set_enable(false); 180 self.sm.set_enable(false);
175 let write_bits = 31; 181 let write_bits = 31;
@@ -179,10 +185,10 @@ where
179 defmt::trace!("write={} read={}", write_bits, read_bits); 185 defmt::trace!("write={} read={}", write_bits, read_bits);
180 186
181 unsafe { 187 unsafe {
182 pio_instr_util::set_y(&mut self.sm, read_bits as u32); 188 instr::set_y(&mut self.sm, read_bits as u32);
183 pio_instr_util::set_x(&mut self.sm, write_bits as u32); 189 instr::set_x(&mut self.sm, write_bits as u32);
184 pio_instr_util::set_pindir(&mut self.sm, 0b1); 190 instr::set_pindir(&mut self.sm, 0b1);
185 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); 191 instr::exec_jmp(&mut self.sm, self.wrap_target);
186 } 192 }
187 193
188 // self.cs.set_low(); 194 // self.cs.set_low();
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index 293c00982..72faad805 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -23,7 +23,7 @@ cortex-m = "0.7.6"
23cortex-m-rt = "0.7.0" 23cortex-m-rt = "0.7.0"
24futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 24futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
25 25
26embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.2" } 26embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.3" }
27num_enum = { version = "0.5.7", default-features = false } 27num_enum = { version = "0.5.7", default-features = false }
28 28
29[package.metadata.embassy_docs] 29[package.metadata.embassy_docs]
diff --git a/cyw43/README.md b/cyw43/README.md
index 5b8f3cf40..2c24c7d36 100644
--- a/cyw43/README.md
+++ b/cyw43/README.md
@@ -45,6 +45,10 @@ nc 192.168.0.250 1234
45``` 45```
46Send it some data, you should see it echoed back and printed in the firmware's logs. 46Send it some data, you should see it echoed back and printed in the firmware's logs.
47 47
48## Minimum supported Rust version (MSRV)
49
50Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
51
48## License 52## License
49 53
50This work is licensed under either of 54This work is licensed under either of
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 826edfe1a..311fcb08c 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -12,17 +12,23 @@ use crate::ioctl::{IoctlState, IoctlType};
12use crate::structs::*; 12use crate::structs::*;
13use crate::{countries, events, PowerManagementMode}; 13use crate::{countries, events, PowerManagementMode};
14 14
15/// Control errors.
15#[derive(Debug)] 16#[derive(Debug)]
16pub struct Error { 17pub struct Error {
18 /// Status code.
17 pub status: u32, 19 pub status: u32,
18} 20}
19 21
22/// Multicast errors.
20#[derive(Debug)] 23#[derive(Debug)]
21pub enum AddMulticastAddressError { 24pub enum AddMulticastAddressError {
25 /// Not a multicast address.
22 NotMulticast, 26 NotMulticast,
27 /// No free address slots.
23 NoFreeSlots, 28 NoFreeSlots,
24} 29}
25 30
31/// Control driver.
26pub struct Control<'a> { 32pub struct Control<'a> {
27 state_ch: ch::StateRunner<'a>, 33 state_ch: ch::StateRunner<'a>,
28 events: &'a Events, 34 events: &'a Events,
@@ -38,6 +44,7 @@ impl<'a> Control<'a> {
38 } 44 }
39 } 45 }
40 46
47 /// Initialize WiFi controller.
41 pub async fn init(&mut self, clm: &[u8]) { 48 pub async fn init(&mut self, clm: &[u8]) {
42 const CHUNK_SIZE: usize = 1024; 49 const CHUNK_SIZE: usize = 1024;
43 50
@@ -154,6 +161,7 @@ impl<'a> Control<'a> {
154 self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; 161 self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await;
155 } 162 }
156 163
164 /// Set power management mode.
157 pub async fn set_power_management(&mut self, mode: PowerManagementMode) { 165 pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
158 // power save mode 166 // power save mode
159 let mode_num = mode.mode(); 167 let mode_num = mode.mode();
@@ -166,6 +174,7 @@ impl<'a> Control<'a> {
166 self.ioctl_set_u32(86, 0, mode_num).await; 174 self.ioctl_set_u32(86, 0, mode_num).await;
167 } 175 }
168 176
177 /// Join an unprotected network with the provided ssid.
169 pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { 178 pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> {
170 self.set_iovar_u32("ampdu_ba_wsize", 8).await; 179 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
171 180
@@ -183,6 +192,7 @@ impl<'a> Control<'a> {
183 self.wait_for_join(i).await 192 self.wait_for_join(i).await
184 } 193 }
185 194
195 /// Join an protected network with the provided ssid and passphrase.
186 pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { 196 pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> {
187 self.set_iovar_u32("ampdu_ba_wsize", 8).await; 197 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
188 198
@@ -250,16 +260,19 @@ impl<'a> Control<'a> {
250 } 260 }
251 } 261 }
252 262
263 /// Set GPIO pin on WiFi chip.
253 pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) { 264 pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) {
254 assert!(gpio_n < 3); 265 assert!(gpio_n < 3);
255 self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 }) 266 self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 })
256 .await 267 .await
257 } 268 }
258 269
270 /// Start open access point.
259 pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) { 271 pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) {
260 self.start_ap(ssid, "", Security::OPEN, channel).await; 272 self.start_ap(ssid, "", Security::OPEN, channel).await;
261 } 273 }
262 274
275 /// Start WPA2 protected access point.
263 pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) { 276 pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) {
264 self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await; 277 self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await;
265 } 278 }
@@ -494,13 +507,14 @@ impl<'a> Control<'a> {
494 } 507 }
495} 508}
496 509
510/// WiFi network scanner.
497pub struct Scanner<'a> { 511pub struct Scanner<'a> {
498 subscriber: EventSubscriber<'a>, 512 subscriber: EventSubscriber<'a>,
499 events: &'a Events, 513 events: &'a Events,
500} 514}
501 515
502impl Scanner<'_> { 516impl Scanner<'_> {
503 /// wait for the next found network 517 /// Wait for the next found network.
504 pub async fn next(&mut self) -> Option<BssInfo> { 518 pub async fn next(&mut self) -> Option<BssInfo> {
505 let event = self.subscriber.next_message_pure().await; 519 let event = self.subscriber.next_message_pure().await;
506 if event.header.status != EStatus::PARTIAL { 520 if event.header.status != EStatus::PARTIAL {
diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs
index 300465e36..19b0cb194 100644
--- a/cyw43/src/lib.rs
+++ b/cyw43/src/lib.rs
@@ -2,6 +2,8 @@
2#![no_main] 2#![no_main]
3#![allow(async_fn_in_trait)] 3#![allow(async_fn_in_trait)]
4#![deny(unused_must_use)] 4#![deny(unused_must_use)]
5#![doc = include_str!("../README.md")]
6#![warn(missing_docs)]
5 7
6// This mod MUST go first, so that the others see its macros. 8// This mod MUST go first, so that the others see its macros.
7pub(crate) mod fmt; 9pub(crate) mod fmt;
@@ -102,6 +104,7 @@ const CHIP: Chip = Chip {
102 chanspec_ctl_sb_mask: 0x0700, 104 chanspec_ctl_sb_mask: 0x0700,
103}; 105};
104 106
107/// Driver state.
105pub struct State { 108pub struct State {
106 ioctl_state: IoctlState, 109 ioctl_state: IoctlState,
107 ch: ch::State<MTU, 4, 4>, 110 ch: ch::State<MTU, 4, 4>,
@@ -109,6 +112,7 @@ pub struct State {
109} 112}
110 113
111impl State { 114impl State {
115 /// Create new driver state holder.
112 pub fn new() -> Self { 116 pub fn new() -> Self {
113 Self { 117 Self {
114 ioctl_state: IoctlState::new(), 118 ioctl_state: IoctlState::new(),
@@ -118,6 +122,7 @@ impl State {
118 } 122 }
119} 123}
120 124
125/// Power management modes.
121#[derive(Debug, Clone, Copy, PartialEq, Eq)] 126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum PowerManagementMode { 127pub enum PowerManagementMode {
123 /// Custom, officially unsupported mode. Use at your own risk. 128 /// Custom, officially unsupported mode. Use at your own risk.
@@ -203,8 +208,13 @@ impl PowerManagementMode {
203 } 208 }
204} 209}
205 210
211/// Embassy-net driver.
206pub type NetDriver<'a> = ch::Device<'a, MTU>; 212pub type NetDriver<'a> = ch::Device<'a, MTU>;
207 213
214/// Create a new instance of the CYW43 driver.
215///
216/// Returns a handle to the network device, control handle and a runner for driving the low level
217/// stack.
208pub async fn new<'a, PWR, SPI>( 218pub async fn new<'a, PWR, SPI>(
209 state: &'a mut State, 219 state: &'a mut State,
210 pwr: PWR, 220 pwr: PWR,
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs
index 83aee6b40..b2a9e3e80 100644
--- a/cyw43/src/runner.rs
+++ b/cyw43/src/runner.rs
@@ -34,6 +34,7 @@ impl Default for LogState {
34 } 34 }
35} 35}
36 36
37/// Driver communicating with the WiFi chip.
37pub struct Runner<'a, PWR, SPI> { 38pub struct Runner<'a, PWR, SPI> {
38 ch: ch::Runner<'a, MTU>, 39 ch: ch::Runner<'a, MTU>,
39 bus: Bus<PWR, SPI>, 40 bus: Bus<PWR, SPI>,
@@ -222,6 +223,7 @@ where
222 } 223 }
223 } 224 }
224 225
226 /// Run the
225 pub async fn run(mut self) -> ! { 227 pub async fn run(mut self) -> ! {
226 let mut buf = [0; 512]; 228 let mut buf = [0; 512];
227 loop { 229 loop {
diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs
index 5ba633c74..5ea62d95b 100644
--- a/cyw43/src/structs.rs
+++ b/cyw43/src/structs.rs
@@ -4,13 +4,16 @@ use crate::fmt::Bytes;
4macro_rules! impl_bytes { 4macro_rules! impl_bytes {
5 ($t:ident) => { 5 ($t:ident) => {
6 impl $t { 6 impl $t {
7 /// Bytes consumed by this type.
7 pub const SIZE: usize = core::mem::size_of::<Self>(); 8 pub const SIZE: usize = core::mem::size_of::<Self>();
8 9
10 /// Convert to byte array.
9 #[allow(unused)] 11 #[allow(unused)]
10 pub fn to_bytes(&self) -> [u8; Self::SIZE] { 12 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
11 unsafe { core::mem::transmute(*self) } 13 unsafe { core::mem::transmute(*self) }
12 } 14 }
13 15
16 /// Create from byte array.
14 #[allow(unused)] 17 #[allow(unused)]
15 pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self { 18 pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self {
16 let alignment = core::mem::align_of::<Self>(); 19 let alignment = core::mem::align_of::<Self>();
@@ -23,6 +26,7 @@ macro_rules! impl_bytes {
23 unsafe { core::mem::transmute(bytes) } 26 unsafe { core::mem::transmute(bytes) }
24 } 27 }
25 28
29 /// Create from mutable byte array.
26 #[allow(unused)] 30 #[allow(unused)]
27 pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self { 31 pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self {
28 let alignment = core::mem::align_of::<Self>(); 32 let alignment = core::mem::align_of::<Self>();
@@ -204,6 +208,7 @@ pub struct EthernetHeader {
204} 208}
205 209
206impl EthernetHeader { 210impl EthernetHeader {
211 /// Swap endianness.
207 pub fn byteswap(&mut self) { 212 pub fn byteswap(&mut self) {
208 self.ether_type = self.ether_type.to_be(); 213 self.ether_type = self.ether_type.to_be();
209 } 214 }
@@ -472,19 +477,26 @@ impl ScanResults {
472#[repr(C, packed(2))] 477#[repr(C, packed(2))]
473#[non_exhaustive] 478#[non_exhaustive]
474pub struct BssInfo { 479pub struct BssInfo {
480 /// Version.
475 pub version: u32, 481 pub version: u32,
482 /// Length.
476 pub length: u32, 483 pub length: u32,
484 /// BSSID.
477 pub bssid: [u8; 6], 485 pub bssid: [u8; 6],
486 /// Beacon period.
478 pub beacon_period: u16, 487 pub beacon_period: u16,
488 /// Capability.
479 pub capability: u16, 489 pub capability: u16,
490 /// SSID length.
480 pub ssid_len: u8, 491 pub ssid_len: u8,
492 /// SSID.
481 pub ssid: [u8; 32], 493 pub ssid: [u8; 32],
482 // there will be more stuff here 494 // there will be more stuff here
483} 495}
484impl_bytes!(BssInfo); 496impl_bytes!(BssInfo);
485 497
486impl BssInfo { 498impl BssInfo {
487 pub fn parse(packet: &mut [u8]) -> Option<&mut Self> { 499 pub(crate) fn parse(packet: &mut [u8]) -> Option<&mut Self> {
488 if packet.len() < BssInfo::SIZE { 500 if packet.len() < BssInfo::SIZE {
489 return None; 501 return None;
490 } 502 }
diff --git a/docs/modules/ROOT/examples/basic/src/main.rs b/docs/modules/ROOT/examples/basic/src/main.rs
index 04170db55..2a4ee5968 100644
--- a/docs/modules/ROOT/examples/basic/src/main.rs
+++ b/docs/modules/ROOT/examples/basic/src/main.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml
index dcdb71e7b..2d47dccf4 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8cortex-m = "0.7" 8cortex-m = "0.7"
9cortex-m-rt = "0.7" 9cortex-m-rt = "0.7"
10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } 10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
11embassy-executor = { version = "0.4.0", features = ["nightly", "arch-cortex-m", "executor-thread"] } 11embassy-executor = { version = "0.4.0", features = ["arch-cortex-m", "executor-thread"] }
12 12
13defmt = "0.3.0" 13defmt = "0.3.0"
14defmt-rtt = "0.3.0" 14defmt-rtt = "0.3.0"
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs
index 8df632240..e6753be28 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use embassy_executor::Spawner; 4use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 5use embassy_stm32::exti::ExtiInput;
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs
index d0c9f4907..54b87662e 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-hal/src/main.rs
@@ -9,7 +9,7 @@ use {defmt_rtt as _, panic_probe as _};
9fn main() -> ! { 9fn main() -> ! {
10 let p = embassy_stm32::init(Default::default()); 10 let p = embassy_stm32::init(Default::default());
11 let mut led = Output::new(p.PB14, Level::High, Speed::VeryHigh); 11 let mut led = Output::new(p.PB14, Level::High, Speed::VeryHigh);
12 let button = Input::new(p.PC13, Pull::Up); 12 let mut button = Input::new(p.PC13, Pull::Up);
13 13
14 loop { 14 loop {
15 if button.is_low() { 15 if button.is_low() {
diff --git a/docs/modules/ROOT/pages/bootloader.adoc b/docs/modules/ROOT/pages/bootloader.adoc
index b7215e52a..3b0cdb182 100644
--- a/docs/modules/ROOT/pages/bootloader.adoc
+++ b/docs/modules/ROOT/pages/bootloader.adoc
@@ -45,6 +45,8 @@ The BOOTLOADER_STATE partition must be big enough to store one word per page in
45 45
46The bootloader has a platform-agnostic part, which implements the power fail safe swapping algorithm given the boundaries set by the partitions. The platform-specific part is a minimal shim that provides additional functionality such as watchdogs or supporting the nRF52 softdevice. 46The bootloader has a platform-agnostic part, which implements the power fail safe swapping algorithm given the boundaries set by the partitions. The platform-specific part is a minimal shim that provides additional functionality such as watchdogs or supporting the nRF52 softdevice.
47 47
48NOTE: The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application.
49
48=== FirmwareUpdater 50=== FirmwareUpdater
49 51
50The `FirmwareUpdater` is an object for conveniently flashing firmware to the DFU partition and subsequently marking it as being ready for swapping with the active partition on the next reset. Its principle methods are `write_firmware`, which is called once per the size of the flash "write block" (typically 4KiB), and `mark_updated`, which is the final call. 52The `FirmwareUpdater` is an object for conveniently flashing firmware to the DFU partition and subsequently marking it as being ready for swapping with the active partition on the next reset. Its principle methods are `write_firmware`, which is called once per the size of the flash "write block" (typically 4KiB), and `mark_updated`, which is the final call.
@@ -91,4 +93,4 @@ cp $FIRMWARE_DIR/myfirmware $FIRMWARE_DIR/myfirmware+signed
91tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed 93tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed
92---- 94----
93 95
94Remember, guard the `$SECRETS_DIR/key.sec` key as compromising it means that another party can sign your firmware. \ No newline at end of file 96Remember, guard the `$SECRETS_DIR/key.sec` key as compromising it means that another party can sign your firmware.
diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc
index d1a012978..1fe9bde37 100644
--- a/docs/modules/ROOT/pages/faq.adoc
+++ b/docs/modules/ROOT/pages/faq.adoc
@@ -35,7 +35,7 @@ For Cortex-M targets, consider making sure that ALL of the following features ar
35* `executor-thread` 35* `executor-thread`
36* `nightly` 36* `nightly`
37 37
38For Xtensa ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. 38For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate].
39 39
40== Why is my binary so big? 40== Why is my binary so big?
41 41
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index dd2ff8158..3c84ffcd3 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -26,25 +26,22 @@ features = ["defmt"]
26defmt = { version = "0.3", optional = true } 26defmt = { version = "0.3", optional = true }
27digest = "0.10" 27digest = "0.10"
28log = { version = "0.4", optional = true } 28log = { version = "0.4", optional = true }
29ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } 29ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true }
30embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 30embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
31embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } 31embassy-sync = { version = "0.5.0", path = "../../embassy-sync" }
32embedded-storage = "0.3.1" 32embedded-storage = "0.3.1"
33embedded-storage-async = { version = "0.4.1" } 33embedded-storage-async = { version = "0.4.1" }
34salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true } 34salty = { version = "0.3", optional = true }
35signature = { version = "1.6.4", default-features = false } 35signature = { version = "2.0", default-features = false }
36 36
37[dev-dependencies] 37[dev-dependencies]
38log = "0.4" 38log = "0.4"
39env_logger = "0.9" 39env_logger = "0.9"
40rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version 40rand = "0.8"
41futures = { version = "0.3", features = ["executor"] } 41futures = { version = "0.3", features = ["executor"] }
42sha1 = "0.10.5" 42sha1 = "0.10.5"
43critical-section = { version = "1.1.1", features = ["std"] } 43critical-section = { version = "1.1.1", features = ["std"] }
44 44ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] }
45[dev-dependencies.ed25519-dalek]
46default_features = false
47features = ["rand", "std", "u32_backend"]
48 45
49[features] 46[features]
50ed25519-dalek = ["dep:ed25519-dalek", "_verify"] 47ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
diff --git a/embassy-boot/boot/README.md b/embassy-boot/boot/README.md
index 07755bc6c..3fc81f24b 100644
--- a/embassy-boot/boot/README.md
+++ b/embassy-boot/boot/README.md
@@ -8,6 +8,24 @@ The bootloader can be used either as a library or be flashed directly with the d
8 8
9By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself. 9By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself.
10 10
11## Overview
12
13The bootloader divides the storage into 4 main partitions, configurable when creating the bootloader instance or via linker scripts:
14
15* BOOTLOADER - Where the bootloader is placed. The bootloader itself consumes about 8kB of flash, but if you need to debug it and have space available, increasing this to 24kB will allow you to run the bootloader with probe-rs.
16* ACTIVE - Where the main application is placed. The bootloader will attempt to load the application at the start of this partition. The minimum size required for this partition is the size of your application.
17* DFU - Where the application-to-be-swapped is placed. This partition is written to by the application. This partition must be at least 1 page bigger than the ACTIVE partition.
18* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped.
19
20For any partition, the following preconditions are required:
21
22* Partitions must be aligned on the page size.
23* Partitions must be a multiple of the page size.
24
25The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application.
26
27For more details on the bootloader, see [the documentation](https://embassy.dev/book/dev/bootloader.html).
28
11## Hardware support 29## Hardware support
12 30
13The bootloader supports different hardware in separate crates: 31The bootloader supports different hardware in separate crates:
@@ -16,6 +34,7 @@ The bootloader supports different hardware in separate crates:
16* `embassy-boot-rp` - for the RP2040 microcontrollers. 34* `embassy-boot-rp` - for the RP2040 microcontrollers.
17* `embassy-boot-stm32` - for the STM32 microcontrollers. 35* `embassy-boot-stm32` - for the STM32 microcontrollers.
18 36
37
19## Minimum supported Rust version (MSRV) 38## Minimum supported Rust version (MSRV)
20 39
21`embassy-boot` is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release. 40`embassy-boot` is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index a8c19197b..e568001bc 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
5use embassy_sync::blocking_mutex::Mutex; 5use embassy_sync::blocking_mutex::Mutex;
6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; 6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
7 7
8use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 8use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
9 9
10/// Errors returned by bootloader 10/// Errors returned by bootloader
11#[derive(PartialEq, Eq, Debug)] 11#[derive(PartialEq, Eq, Debug)]
@@ -135,51 +135,44 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
135 /// The provided aligned_buf argument must satisfy any alignment requirements 135 /// The provided aligned_buf argument must satisfy any alignment requirements
136 /// given by the partition flashes. All flash operations will use this buffer. 136 /// given by the partition flashes. All flash operations will use this buffer.
137 /// 137 ///
138 /// SWAPPING 138 /// ## SWAPPING
139 /// 139 ///
140 /// Assume a flash size of 3 pages for the active partition, and 4 pages for the DFU partition. 140 /// Assume a flash size of 3 pages for the active partition, and 4 pages for the DFU partition.
141 /// The swap index contains the copy progress, as to allow continuation of the copy process on 141 /// The swap index contains the copy progress, as to allow continuation of the copy process on
142 /// power failure. The index counter is represented within 1 or more pages (depending on total 142 /// power failure. The index counter is represented within 1 or more pages (depending on total
143 /// flash size), where a page X is considered swapped if index at location (X + WRITE_SIZE) 143 /// flash size), where a page X is considered swapped if index at location (`X + WRITE_SIZE`)
144 /// contains a zero value. This ensures that index updates can be performed atomically and 144 /// contains a zero value. This ensures that index updates can be performed atomically and
145 /// avoid a situation where the wrong index value is set (page write size is "atomic"). 145 /// avoid a situation where the wrong index value is set (page write size is "atomic").
146 /// 146 ///
147 /// +-----------+------------+--------+--------+--------+--------+ 147 ///
148 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | 148 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 |
149 /// +-----------+------------+--------+--------+--------+--------+ 149 /// |-----------|------------|--------|--------|--------|--------|
150 /// | Active | 0 | 1 | 2 | 3 | - | 150 /// | Active | 0 | 1 | 2 | 3 | - |
151 /// | DFU | 0 | 3 | 2 | 1 | X | 151 /// | DFU | 0 | 3 | 2 | 1 | X |
152 /// +-----------+------------+--------+--------+--------+--------+
153 /// 152 ///
154 /// The algorithm starts by copying 'backwards', and after the first step, the layout is 153 /// The algorithm starts by copying 'backwards', and after the first step, the layout is
155 /// as follows: 154 /// as follows:
156 /// 155 ///
157 /// +-----------+------------+--------+--------+--------+--------+
158 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | 156 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 |
159 /// +-----------+------------+--------+--------+--------+--------+ 157 /// |-----------|------------|--------|--------|--------|--------|
160 /// | Active | 1 | 1 | 2 | 1 | - | 158 /// | Active | 1 | 1 | 2 | 1 | - |
161 /// | DFU | 1 | 3 | 2 | 1 | 3 | 159 /// | DFU | 1 | 3 | 2 | 1 | 3 |
162 /// +-----------+------------+--------+--------+--------+--------+
163 /// 160 ///
164 /// The next iteration performs the same steps 161 /// The next iteration performs the same steps
165 /// 162 ///
166 /// +-----------+------------+--------+--------+--------+--------+
167 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | 163 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 |
168 /// +-----------+------------+--------+--------+--------+--------+ 164 /// |-----------|------------|--------|--------|--------|--------|
169 /// | Active | 2 | 1 | 2 | 1 | - | 165 /// | Active | 2 | 1 | 2 | 1 | - |
170 /// | DFU | 2 | 3 | 2 | 2 | 3 | 166 /// | DFU | 2 | 3 | 2 | 2 | 3 |
171 /// +-----------+------------+--------+--------+--------+--------+
172 /// 167 ///
173 /// And again until we're done 168 /// And again until we're done
174 /// 169 ///
175 /// +-----------+------------+--------+--------+--------+--------+
176 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 | 170 /// | Partition | Swap Index | Page 0 | Page 1 | Page 3 | Page 4 |
177 /// +-----------+------------+--------+--------+--------+--------+ 171 /// |-----------|------------|--------|--------|--------|--------|
178 /// | Active | 3 | 3 | 2 | 1 | - | 172 /// | Active | 3 | 3 | 2 | 1 | - |
179 /// | DFU | 3 | 3 | 1 | 2 | 3 | 173 /// | DFU | 3 | 3 | 1 | 2 | 3 |
180 /// +-----------+------------+--------+--------+--------+--------+
181 /// 174 ///
182 /// REVERTING 175 /// ## REVERTING
183 /// 176 ///
184 /// The reverting algorithm uses the swap index to discover that images were swapped, but that 177 /// The reverting algorithm uses the swap index to discover that images were swapped, but that
185 /// the application failed to mark the boot successful. In this case, the revert algorithm will 178 /// the application failed to mark the boot successful. In this case, the revert algorithm will
@@ -190,28 +183,21 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
190 /// 183 ///
191 /// The revert algorithm works forwards, by starting copying into the 'unused' DFU page at the start. 184 /// The revert algorithm works forwards, by starting copying into the 'unused' DFU page at the start.
192 /// 185 ///
193 /// +-----------+--------------+--------+--------+--------+--------+
194 /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | 186 /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 |
195 //*/ 187 /// |-----------|--------------|--------|--------|--------|--------|
196 /// +-----------+--------------+--------+--------+--------+--------+
197 /// | Active | 3 | 1 | 2 | 1 | - | 188 /// | Active | 3 | 1 | 2 | 1 | - |
198 /// | DFU | 3 | 3 | 1 | 2 | 3 | 189 /// | DFU | 3 | 3 | 1 | 2 | 3 |
199 /// +-----------+--------------+--------+--------+--------+--------+
200 /// 190 ///
201 /// 191 ///
202 /// +-----------+--------------+--------+--------+--------+--------+
203 /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | 192 /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 |
204 /// +-----------+--------------+--------+--------+--------+--------+ 193 /// |-----------|--------------|--------|--------|--------|--------|
205 /// | Active | 3 | 1 | 2 | 1 | - | 194 /// | Active | 3 | 1 | 2 | 1 | - |
206 /// | DFU | 3 | 3 | 2 | 2 | 3 | 195 /// | DFU | 3 | 3 | 2 | 2 | 3 |
207 /// +-----------+--------------+--------+--------+--------+--------+
208 /// 196 ///
209 /// +-----------+--------------+--------+--------+--------+--------+
210 /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 | 197 /// | Partition | Revert Index | Page 0 | Page 1 | Page 3 | Page 4 |
211 /// +-----------+--------------+--------+--------+--------+--------+ 198 /// |-----------|--------------|--------|--------|--------|--------|
212 /// | Active | 3 | 1 | 2 | 3 | - | 199 /// | Active | 3 | 1 | 2 | 3 | - |
213 /// | DFU | 3 | 3 | 2 | 1 | 3 | 200 /// | DFU | 3 | 3 | 2 | 1 | 3 |
214 /// +-----------+--------------+--------+--------+--------+--------+
215 /// 201 ///
216 pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> { 202 pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> {
217 // Ensure we have enough progress pages to store copy progress 203 // Ensure we have enough progress pages to store copy progress
@@ -224,6 +210,7 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
224 assert_eq!(0, aligned_buf.len() % ACTIVE::WRITE_SIZE); 210 assert_eq!(0, aligned_buf.len() % ACTIVE::WRITE_SIZE);
225 assert_eq!(0, aligned_buf.len() % DFU::WRITE_SIZE); 211 assert_eq!(0, aligned_buf.len() % DFU::WRITE_SIZE);
226 212
213 // Ensure our partitions are able to handle boot operations
227 assert_partitions(&self.active, &self.dfu, &self.state, Self::PAGE_SIZE); 214 assert_partitions(&self.active, &self.dfu, &self.state, Self::PAGE_SIZE);
228 215
229 // Copy contents from partition N to active 216 // Copy contents from partition N to active
@@ -384,6 +371,8 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
384 371
385 if !state_word.iter().any(|&b| b != SWAP_MAGIC) { 372 if !state_word.iter().any(|&b| b != SWAP_MAGIC) {
386 Ok(State::Swap) 373 Ok(State::Swap)
374 } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) {
375 Ok(State::DfuDetach)
387 } else { 376 } else {
388 Ok(State::Boot) 377 Ok(State::Boot)
389 } 378 }
@@ -398,6 +387,7 @@ fn assert_partitions<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
398) { 387) {
399 assert_eq!(active.capacity() as u32 % page_size, 0); 388 assert_eq!(active.capacity() as u32 % page_size, 0);
400 assert_eq!(dfu.capacity() as u32 % page_size, 0); 389 assert_eq!(dfu.capacity() as u32 % page_size, 0);
390 // DFU partition has to be bigger than ACTIVE partition to handle swap algorithm
401 assert!(dfu.capacity() as u32 - active.capacity() as u32 >= page_size); 391 assert!(dfu.capacity() as u32 - active.capacity() as u32 >= page_size);
402 assert!(2 + 2 * (active.capacity() as u32 / page_size) <= state.capacity() as u32 / STATE::WRITE_SIZE as u32); 392 assert!(2 + 2 * (active.capacity() as u32 / page_size) <= state.capacity() as u32 / STATE::WRITE_SIZE as u32);
403} 393}
diff --git a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs
index a184d1c51..2e4e03da3 100644
--- a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs
+++ b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs
@@ -1,6 +1,6 @@
1use digest::typenum::U64; 1use digest::typenum::U64;
2use digest::{FixedOutput, HashMarker, OutputSizeUser, Update}; 2use digest::{FixedOutput, HashMarker, OutputSizeUser, Update};
3use ed25519_dalek::Digest as _; 3use ed25519_dalek::Digest;
4 4
5pub struct Sha512(ed25519_dalek::Sha512); 5pub struct Sha512(ed25519_dalek::Sha512);
6 6
@@ -12,7 +12,7 @@ impl Default for Sha512 {
12 12
13impl Update for Sha512 { 13impl Update for Sha512 {
14 fn update(&mut self, data: &[u8]) { 14 fn update(&mut self, data: &[u8]) {
15 self.0.update(data) 15 Digest::update(&mut self.0, data)
16 } 16 }
17} 17}
18 18
diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs
index ae713bb6f..64a4b32ec 100644
--- a/embassy-boot/boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/boot/src/firmware_updater/asynch.rs
@@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
6use embedded_storage_async::nor_flash::NorFlash; 6use embedded_storage_async::nor_flash::NorFlash;
7 7
8use super::FirmwareUpdaterConfig; 8use super::FirmwareUpdaterConfig;
9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
10 10
11/// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to 11/// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to
12/// 'mess up' the internal bootloader state 12/// 'mess up' the internal bootloader state
@@ -79,8 +79,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
79 #[cfg(feature = "_verify")] 79 #[cfg(feature = "_verify")]
80 pub async fn verify_and_mark_updated( 80 pub async fn verify_and_mark_updated(
81 &mut self, 81 &mut self,
82 _public_key: &[u8], 82 _public_key: &[u8; 32],
83 _signature: &[u8], 83 _signature: &[u8; 64],
84 _update_len: u32, 84 _update_len: u32,
85 ) -> Result<(), FirmwareUpdaterError> { 85 ) -> Result<(), FirmwareUpdaterError> {
86 assert!(_update_len <= self.dfu.capacity() as u32); 86 assert!(_update_len <= self.dfu.capacity() as u32);
@@ -89,14 +89,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
89 89
90 #[cfg(feature = "ed25519-dalek")] 90 #[cfg(feature = "ed25519-dalek")]
91 { 91 {
92 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; 92 use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey};
93 93
94 use crate::digest_adapters::ed25519_dalek::Sha512; 94 use crate::digest_adapters::ed25519_dalek::Sha512;
95 95
96 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); 96 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
97 97
98 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; 98 let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?;
99 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; 99 let signature = Signature::from_bytes(_signature);
100 100
101 let mut chunk_buf = [0; 2]; 101 let mut chunk_buf = [0; 2];
102 let mut message = [0; 64]; 102 let mut message = [0; 64];
@@ -106,7 +106,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
106 } 106 }
107 #[cfg(feature = "ed25519-salty")] 107 #[cfg(feature = "ed25519-salty")]
108 { 108 {
109 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
110 use salty::{PublicKey, Signature}; 109 use salty::{PublicKey, Signature};
111 110
112 use crate::digest_adapters::salty::Sha512; 111 use crate::digest_adapters::salty::Sha512;
@@ -115,10 +114,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
115 FirmwareUpdaterError::Signature(signature::Error::default()) 114 FirmwareUpdaterError::Signature(signature::Error::default())
116 } 115 }
117 116
118 let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; 117 let public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?;
119 let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; 118 let signature = Signature::try_from(_signature).map_err(into_signature_error)?;
120 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
121 let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
122 119
123 let mut message = [0; 64]; 120 let mut message = [0; 64];
124 let mut chunk_buf = [0; 2]; 121 let mut chunk_buf = [0; 2];
@@ -161,6 +158,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
161 self.state.mark_updated().await 158 self.state.mark_updated().await
162 } 159 }
163 160
161 /// Mark to trigger USB DFU on next boot.
162 pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
163 self.state.verify_booted().await?;
164 self.state.mark_dfu().await
165 }
166
164 /// Mark firmware boot successful and stop rollback on reset. 167 /// Mark firmware boot successful and stop rollback on reset.
165 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 168 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
166 self.state.mark_booted().await 169 self.state.mark_booted().await
@@ -207,6 +210,16 @@ pub struct FirmwareState<'d, STATE> {
207} 210}
208 211
209impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { 212impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
213 /// Create a firmware state instance from a FirmwareUpdaterConfig with a buffer for magic content and state partition.
214 ///
215 /// # Safety
216 ///
217 /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from
218 /// and written to.
219 pub fn from_config<DFU: NorFlash>(config: FirmwareUpdaterConfig<DFU, STATE>, aligned: &'d mut [u8]) -> Self {
220 Self::new(config.state, aligned)
221 }
222
210 /// Create a firmware state instance with a buffer for magic content and state partition. 223 /// Create a firmware state instance with a buffer for magic content and state partition.
211 /// 224 ///
212 /// # Safety 225 /// # Safety
@@ -247,6 +260,11 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
247 self.set_magic(SWAP_MAGIC).await 260 self.set_magic(SWAP_MAGIC).await
248 } 261 }
249 262
263 /// Mark to trigger USB DFU on next boot.
264 pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
265 self.set_magic(DFU_DETACH_MAGIC).await
266 }
267
250 /// Mark firmware boot successful and stop rollback on reset. 268 /// Mark firmware boot successful and stop rollback on reset.
251 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 269 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
252 self.set_magic(BOOT_MAGIC).await 270 self.set_magic(BOOT_MAGIC).await
diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs
index 76e4264a0..f1368540d 100644
--- a/embassy-boot/boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/boot/src/firmware_updater/blocking.rs
@@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
6use embedded_storage::nor_flash::NorFlash; 6use embedded_storage::nor_flash::NorFlash;
7 7
8use super::FirmwareUpdaterConfig; 8use super::FirmwareUpdaterConfig;
9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
10 10
11/// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to 11/// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to
12/// 'mess up' the internal bootloader state 12/// 'mess up' the internal bootloader state
@@ -86,8 +86,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
86 #[cfg(feature = "_verify")] 86 #[cfg(feature = "_verify")]
87 pub fn verify_and_mark_updated( 87 pub fn verify_and_mark_updated(
88 &mut self, 88 &mut self,
89 _public_key: &[u8], 89 _public_key: &[u8; 32],
90 _signature: &[u8], 90 _signature: &[u8; 64],
91 _update_len: u32, 91 _update_len: u32,
92 ) -> Result<(), FirmwareUpdaterError> { 92 ) -> Result<(), FirmwareUpdaterError> {
93 assert!(_update_len <= self.dfu.capacity() as u32); 93 assert!(_update_len <= self.dfu.capacity() as u32);
@@ -96,14 +96,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
96 96
97 #[cfg(feature = "ed25519-dalek")] 97 #[cfg(feature = "ed25519-dalek")]
98 { 98 {
99 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; 99 use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey};
100 100
101 use crate::digest_adapters::ed25519_dalek::Sha512; 101 use crate::digest_adapters::ed25519_dalek::Sha512;
102 102
103 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); 103 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
104 104
105 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; 105 let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?;
106 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; 106 let signature = Signature::from_bytes(_signature);
107 107
108 let mut message = [0; 64]; 108 let mut message = [0; 64];
109 let mut chunk_buf = [0; 2]; 109 let mut chunk_buf = [0; 2];
@@ -113,7 +113,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
113 } 113 }
114 #[cfg(feature = "ed25519-salty")] 114 #[cfg(feature = "ed25519-salty")]
115 { 115 {
116 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
117 use salty::{PublicKey, Signature}; 116 use salty::{PublicKey, Signature};
118 117
119 use crate::digest_adapters::salty::Sha512; 118 use crate::digest_adapters::salty::Sha512;
@@ -122,10 +121,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
122 FirmwareUpdaterError::Signature(signature::Error::default()) 121 FirmwareUpdaterError::Signature(signature::Error::default())
123 } 122 }
124 123
125 let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; 124 let public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?;
126 let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; 125 let signature = Signature::try_from(_signature).map_err(into_signature_error)?;
127 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
128 let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
129 126
130 let mut message = [0; 64]; 127 let mut message = [0; 64];
131 let mut chunk_buf = [0; 2]; 128 let mut chunk_buf = [0; 2];
@@ -168,6 +165,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
168 self.state.mark_updated() 165 self.state.mark_updated()
169 } 166 }
170 167
168 /// Mark to trigger USB DFU device on next boot.
169 pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
170 self.state.verify_booted()?;
171 self.state.mark_dfu()
172 }
173
171 /// Mark firmware boot successful and stop rollback on reset. 174 /// Mark firmware boot successful and stop rollback on reset.
172 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 175 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
173 self.state.mark_booted() 176 self.state.mark_booted()
@@ -213,6 +216,16 @@ pub struct BlockingFirmwareState<'d, STATE> {
213} 216}
214 217
215impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { 218impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
219 /// Creates a firmware state instance from a FirmwareUpdaterConfig, with a buffer for magic content and state partition.
220 ///
221 /// # Safety
222 ///
223 /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from
224 /// and written to.
225 pub fn from_config<DFU: NorFlash>(config: FirmwareUpdaterConfig<DFU, STATE>, aligned: &'d mut [u8]) -> Self {
226 Self::new(config.state, aligned)
227 }
228
216 /// Create a firmware state instance with a buffer for magic content and state partition. 229 /// Create a firmware state instance with a buffer for magic content and state partition.
217 /// 230 ///
218 /// # Safety 231 /// # Safety
@@ -226,7 +239,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
226 239
227 // Make sure we are running a booted firmware to avoid reverting to a bad state. 240 // Make sure we are running a booted firmware to avoid reverting to a bad state.
228 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 241 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
229 if self.get_state()? == State::Boot { 242 if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach {
230 Ok(()) 243 Ok(())
231 } else { 244 } else {
232 Err(FirmwareUpdaterError::BadState) 245 Err(FirmwareUpdaterError::BadState)
@@ -243,6 +256,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
243 256
244 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { 257 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
245 Ok(State::Swap) 258 Ok(State::Swap)
259 } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) {
260 Ok(State::DfuDetach)
246 } else { 261 } else {
247 Ok(State::Boot) 262 Ok(State::Boot)
248 } 263 }
@@ -253,6 +268,11 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
253 self.set_magic(SWAP_MAGIC) 268 self.set_magic(SWAP_MAGIC)
254 } 269 }
255 270
271 /// Mark to trigger USB DFU on next boot.
272 pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
273 self.set_magic(DFU_DETACH_MAGIC)
274 }
275
256 /// Mark firmware boot successful and stop rollback on reset. 276 /// Mark firmware boot successful and stop rollback on reset.
257 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 277 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
258 self.set_magic(BOOT_MAGIC) 278 self.set_magic(BOOT_MAGIC)
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 9e70a4dca..b4f03e01e 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -23,6 +23,7 @@ pub use firmware_updater::{
23 23
24pub(crate) const BOOT_MAGIC: u8 = 0xD0; 24pub(crate) const BOOT_MAGIC: u8 = 0xD0;
25pub(crate) const SWAP_MAGIC: u8 = 0xF0; 25pub(crate) const SWAP_MAGIC: u8 = 0xF0;
26pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
26 27
27/// The state of the bootloader after running prepare. 28/// The state of the bootloader after running prepare.
28#[derive(PartialEq, Eq, Debug)] 29#[derive(PartialEq, Eq, Debug)]
@@ -32,6 +33,8 @@ pub enum State {
32 Boot, 33 Boot,
33 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. 34 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot.
34 Swap, 35 Swap,
36 /// Application has received a request to reboot into DFU mode to apply an update.
37 DfuDetach,
35} 38}
36 39
37/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. 40/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot.
@@ -272,21 +275,19 @@ mod tests {
272 // The following key setup is based on: 275 // The following key setup is based on:
273 // https://docs.rs/ed25519-dalek/latest/ed25519_dalek/#example 276 // https://docs.rs/ed25519-dalek/latest/ed25519_dalek/#example
274 277
275 use ed25519_dalek::Keypair; 278 use ed25519_dalek::{Digest, Sha512, Signature, Signer, SigningKey, VerifyingKey};
276 use rand::rngs::OsRng; 279 use rand::rngs::OsRng;
277 280
278 let mut csprng = OsRng {}; 281 let mut csprng = OsRng {};
279 let keypair: Keypair = Keypair::generate(&mut csprng); 282 let keypair = SigningKey::generate(&mut csprng);
280 283
281 use ed25519_dalek::{Digest, Sha512, Signature, Signer};
282 let firmware: &[u8] = b"This are bytes that would otherwise be firmware bytes for DFU."; 284 let firmware: &[u8] = b"This are bytes that would otherwise be firmware bytes for DFU.";
283 let mut digest = Sha512::new(); 285 let mut digest = Sha512::new();
284 digest.update(&firmware); 286 digest.update(&firmware);
285 let message = digest.finalize(); 287 let message = digest.finalize();
286 let signature: Signature = keypair.sign(&message); 288 let signature: Signature = keypair.sign(&message);
287 289
288 use ed25519_dalek::PublicKey; 290 let public_key = keypair.verifying_key();
289 let public_key: PublicKey = keypair.public;
290 291
291 // Setup flash 292 // Setup flash
292 let flash = BlockingTestFlash::new(BootLoaderConfig { 293 let flash = BlockingTestFlash::new(BootLoaderConfig {
diff --git a/embassy-boot/nrf/Cargo.toml b/embassy-boot/nrf/Cargo.toml
index eea29cf2e..9f74fb126 100644
--- a/embassy-boot/nrf/Cargo.toml
+++ b/embassy-boot/nrf/Cargo.toml
@@ -4,6 +4,12 @@ name = "embassy-boot-nrf"
4version = "0.1.0" 4version = "0.1.0"
5description = "Bootloader lib for nRF chips" 5description = "Bootloader lib for nRF chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy"
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-boot-nrf-v$VERSION/embassy-boot/nrf/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/nrf/src/"
@@ -25,7 +31,7 @@ embedded-storage = "0.3.1"
25embedded-storage-async = { version = "0.4.1" } 31embedded-storage-async = { version = "0.4.1" }
26cfg-if = "1.0.0" 32cfg-if = "1.0.0"
27 33
28nrf-softdevice-mbr = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-softdevice.git", branch = "master", optional = true } 34nrf-softdevice-mbr = { version = "0.2.0", optional = true }
29 35
30[features] 36[features]
31defmt = [ 37defmt = [
diff --git a/embassy-boot/rp/Cargo.toml b/embassy-boot/rp/Cargo.toml
index 0f2dc4628..90bab0996 100644
--- a/embassy-boot/rp/Cargo.toml
+++ b/embassy-boot/rp/Cargo.toml
@@ -4,6 +4,12 @@ name = "embassy-boot-rp"
4version = "0.1.0" 4version = "0.1.0"
5description = "Bootloader lib for RP2040 chips" 5description = "Bootloader lib for RP2040 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy"
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-boot-rp-v$VERSION/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/"
diff --git a/embassy-boot/stm32/Cargo.toml b/embassy-boot/stm32/Cargo.toml
index bc8da6738..70919b76d 100644
--- a/embassy-boot/stm32/Cargo.toml
+++ b/embassy-boot/stm32/Cargo.toml
@@ -4,6 +4,12 @@ name = "embassy-boot-stm32"
4version = "0.1.0" 4version = "0.1.0"
5description = "Bootloader lib for STM32 chips" 5description = "Bootloader lib for STM32 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
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-boot-nrf-v$VERSION/embassy-boot/stm32/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/stm32/src/"
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index c418cb262..4b4091ac9 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -10,7 +10,10 @@ pub use embassy_boot::{
10use embedded_storage::nor_flash::NorFlash; 10use embedded_storage::nor_flash::NorFlash;
11 11
12/// A bootloader for STM32 devices. 12/// A bootloader for STM32 devices.
13pub struct BootLoader; 13pub struct BootLoader {
14 /// The reported state of the bootloader after preparing for boot
15 pub state: State,
16}
14 17
15impl BootLoader { 18impl BootLoader {
16 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware 19 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware
@@ -19,8 +22,8 @@ impl BootLoader {
19 ) -> Self { 22 ) -> Self {
20 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); 23 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
21 let mut boot = embassy_boot::BootLoader::new(config); 24 let mut boot = embassy_boot::BootLoader::new(config);
22 boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); 25 let state = boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error");
23 Self 26 Self { state }
24 } 27 }
25 28
26 /// Boots the application. 29 /// Boots the application.
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index 2a0b25479..f292f952d 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -23,8 +23,8 @@ embassy-time = { version = "0.2", path = "../embassy-time", optional = true }
23embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ 23embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
24 "unproven", 24 "unproven",
25] } 25] }
26embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 26embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
27embedded-hal-async = { version = "=1.0.0-rc.2" } 27embedded-hal-async = { version = "=1.0.0-rc.3" }
28embedded-storage = "0.3.1" 28embedded-storage = "0.3.1"
29embedded-storage-async = { version = "0.4.1" } 29embedded-storage-async = { version = "0.4.1" }
30nb = "1.0.0" 30nb = "1.0.0"
diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs
index 5161e1020..1efb2788b 100644
--- a/embassy-executor-macros/src/macros/task.rs
+++ b/embassy-executor-macros/src/macros/task.rs
@@ -49,7 +49,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
49 }, 49 },
50 } 50 }
51 51
52 let mut arg_names = Vec::new(); 52 let mut args = Vec::new();
53 let mut fargs = f.sig.inputs.clone(); 53 let mut fargs = f.sig.inputs.clone();
54 54
55 for arg in fargs.iter_mut() { 55 for arg in fargs.iter_mut() {
@@ -59,8 +59,8 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
59 } 59 }
60 syn::FnArg::Typed(t) => match t.pat.as_mut() { 60 syn::FnArg::Typed(t) => match t.pat.as_mut() {
61 syn::Pat::Ident(id) => { 61 syn::Pat::Ident(id) => {
62 arg_names.push(id.ident.clone());
63 id.mutability = None; 62 id.mutability = None;
63 args.push((id.clone(), t.attrs.clone()));
64 } 64 }
65 _ => { 65 _ => {
66 ctxt.error_spanned_by(arg, "pattern matching in task arguments is not yet supported"); 66 ctxt.error_spanned_by(arg, "pattern matching in task arguments is not yet supported");
@@ -79,13 +79,24 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
79 task_inner.vis = syn::Visibility::Inherited; 79 task_inner.vis = syn::Visibility::Inherited;
80 task_inner.sig.ident = task_inner_ident.clone(); 80 task_inner.sig.ident = task_inner_ident.clone();
81 81
82 // assemble the original input arguments,
83 // including any attributes that may have
84 // been applied previously
85 let mut full_args = Vec::new();
86 for (arg, cfgs) in args {
87 full_args.push(quote!(
88 #(#cfgs)*
89 #arg
90 ));
91 }
92
82 #[cfg(feature = "nightly")] 93 #[cfg(feature = "nightly")]
83 let mut task_outer: ItemFn = parse_quote! { 94 let mut task_outer: ItemFn = parse_quote! {
84 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> { 95 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
85 type Fut = impl ::core::future::Future + 'static; 96 type Fut = impl ::core::future::Future + 'static;
86 const POOL_SIZE: usize = #pool_size; 97 const POOL_SIZE: usize = #pool_size;
87 static POOL: ::embassy_executor::raw::TaskPool<Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); 98 static POOL: ::embassy_executor::raw::TaskPool<Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new();
88 unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) } 99 unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) }
89 } 100 }
90 }; 101 };
91 #[cfg(not(feature = "nightly"))] 102 #[cfg(not(feature = "nightly"))]
@@ -93,7 +104,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
93 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> { 104 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
94 const POOL_SIZE: usize = #pool_size; 105 const POOL_SIZE: usize = #pool_size;
95 static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new(); 106 static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new();
96 unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) } 107 unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) }
97 } 108 }
98 }; 109 };
99 110
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index c937194ce..25c2c6a1d 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -14,7 +14,7 @@ categories = [
14[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
16src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" 16src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
17features = ["nightly", "defmt"] 17features = ["defmt"]
18flavors = [ 18flavors = [
19 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, 19 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
20 { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, 20 { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
@@ -25,7 +25,7 @@ flavors = [
25[package.metadata.docs.rs] 25[package.metadata.docs.rs]
26default-target = "thumbv7em-none-eabi" 26default-target = "thumbv7em-none-eabi"
27targets = ["thumbv7em-none-eabi"] 27targets = ["thumbv7em-none-eabi"]
28features = ["nightly", "defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] 28features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"]
29 29
30[dependencies] 30[dependencies]
31defmt = { version = "0.3", optional = true } 31defmt = { version = "0.3", optional = true }
@@ -36,11 +36,12 @@ embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macro
36embassy-time = { version = "0.2", path = "../embassy-time", optional = true} 36embassy-time = { version = "0.2", path = "../embassy-time", optional = true}
37critical-section = "1.1" 37critical-section = "1.1"
38 38
39document-features = "0.2.7"
40
39# needed for riscv and avr 41# needed for riscv and avr
40# remove when https://github.com/rust-lang/rust/pull/114499 is merged 42# remove when https://github.com/rust-lang/rust/pull/114499 is merged
41portable-atomic = { version = "1.5", optional = true } 43portable-atomic = { version = "1.5", optional = true }
42 44
43
44# arch-cortex-m dependencies 45# arch-cortex-m dependencies
45cortex-m = { version = "0.7.6", optional = true } 46cortex-m = { version = "0.7.6", optional = true }
46 47
@@ -57,67 +58,128 @@ critical-section = { version = "1.1", features = ["std"] }
57 58
58[features] 59[features]
59 60
60# Architecture 61## Enable nightly-only features
62nightly = ["embassy-executor-macros/nightly"]
63
64# Enables turbo wakers, which requires patching core. Not surfaced in the docs by default due to
65# being an complicated advanced and undocumented feature.
66# See: https://github.com/embassy-rs/embassy/pull/1263
67turbowakers = []
68
69## Use timers from `embassy-time`
70integrated-timers = ["dep:embassy-time"]
71
72#! ### Architecture
61_arch = [] # some arch was picked 73_arch = [] # some arch was picked
62arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] 74## std
63arch-std = ["_arch", "critical-section/std"] 75arch-std = ["_arch", "critical-section/std"]
76## Cortex-M
64arch-cortex-m = ["_arch", "dep:cortex-m"] 77arch-cortex-m = ["_arch", "dep:cortex-m"]
78## RISC-V 32
65arch-riscv32 = ["_arch", "dep:portable-atomic"] 79arch-riscv32 = ["_arch", "dep:portable-atomic"]
80## WASM
66arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] 81arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
82## AVR
83arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"]
84
85#! ### Executor
67 86
68# Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs) 87## Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs)
69executor-thread = [] 88executor-thread = []
70# Enable the interrupt-mode executor (available in Cortex-M only) 89## Enable the interrupt-mode executor (available in Cortex-M only)
71executor-interrupt = [] 90executor-interrupt = []
72 91
73# Enable nightly-only features 92#! ### Task Arena Size
74nightly = ["embassy-executor-macros/nightly"] 93#! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`.
75 94#!
76turbowakers = [] 95#! <details>
77 96#! <summary>Preconfigured Task Arena Sizes:</summary>
78integrated-timers = ["dep:embassy-time"] 97#! <!-- rustdoc requires the following blank line for the feature list to render correctly! -->
98#!
79 99
80# BEGIN AUTOGENERATED CONFIG FEATURES 100# BEGIN AUTOGENERATED CONFIG FEATURES
81# Generated by gen_config.py. DO NOT EDIT. 101# Generated by gen_config.py. DO NOT EDIT.
102## 64
82task-arena-size-64 = [] 103task-arena-size-64 = []
104## 128
83task-arena-size-128 = [] 105task-arena-size-128 = []
106## 192
84task-arena-size-192 = [] 107task-arena-size-192 = []
108## 256
85task-arena-size-256 = [] 109task-arena-size-256 = []
110## 320
86task-arena-size-320 = [] 111task-arena-size-320 = []
112## 384
87task-arena-size-384 = [] 113task-arena-size-384 = []
114## 512
88task-arena-size-512 = [] 115task-arena-size-512 = []
116## 640
89task-arena-size-640 = [] 117task-arena-size-640 = []
118## 768
90task-arena-size-768 = [] 119task-arena-size-768 = []
120## 1024
91task-arena-size-1024 = [] 121task-arena-size-1024 = []
122## 1280
92task-arena-size-1280 = [] 123task-arena-size-1280 = []
124## 1536
93task-arena-size-1536 = [] 125task-arena-size-1536 = []
126## 2048
94task-arena-size-2048 = [] 127task-arena-size-2048 = []
128## 2560
95task-arena-size-2560 = [] 129task-arena-size-2560 = []
130## 3072
96task-arena-size-3072 = [] 131task-arena-size-3072 = []
132## 4096 (default)
97task-arena-size-4096 = [] # Default 133task-arena-size-4096 = [] # Default
134## 5120
98task-arena-size-5120 = [] 135task-arena-size-5120 = []
136## 6144
99task-arena-size-6144 = [] 137task-arena-size-6144 = []
138## 8192
100task-arena-size-8192 = [] 139task-arena-size-8192 = []
140## 10240
101task-arena-size-10240 = [] 141task-arena-size-10240 = []
142## 12288
102task-arena-size-12288 = [] 143task-arena-size-12288 = []
144## 16384
103task-arena-size-16384 = [] 145task-arena-size-16384 = []
146## 20480
104task-arena-size-20480 = [] 147task-arena-size-20480 = []
148## 24576
105task-arena-size-24576 = [] 149task-arena-size-24576 = []
150## 32768
106task-arena-size-32768 = [] 151task-arena-size-32768 = []
152## 40960
107task-arena-size-40960 = [] 153task-arena-size-40960 = []
154## 49152
108task-arena-size-49152 = [] 155task-arena-size-49152 = []
156## 65536
109task-arena-size-65536 = [] 157task-arena-size-65536 = []
158## 81920
110task-arena-size-81920 = [] 159task-arena-size-81920 = []
160## 98304
111task-arena-size-98304 = [] 161task-arena-size-98304 = []
162## 131072
112task-arena-size-131072 = [] 163task-arena-size-131072 = []
164## 163840
113task-arena-size-163840 = [] 165task-arena-size-163840 = []
166## 196608
114task-arena-size-196608 = [] 167task-arena-size-196608 = []
168## 262144
115task-arena-size-262144 = [] 169task-arena-size-262144 = []
170## 327680
116task-arena-size-327680 = [] 171task-arena-size-327680 = []
172## 393216
117task-arena-size-393216 = [] 173task-arena-size-393216 = []
174## 524288
118task-arena-size-524288 = [] 175task-arena-size-524288 = []
176## 655360
119task-arena-size-655360 = [] 177task-arena-size-655360 = []
178## 786432
120task-arena-size-786432 = [] 179task-arena-size-786432 = []
180## 1048576
121task-arena-size-1048576 = [] 181task-arena-size-1048576 = []
122 182
123# END AUTOGENERATED CONFIG FEATURES 183# END AUTOGENERATED CONFIG FEATURES
184
185#! </details> \ No newline at end of file
diff --git a/embassy-executor/README.md b/embassy-executor/README.md
index 80ecfc71a..aa9d59907 100644
--- a/embassy-executor/README.md
+++ b/embassy-executor/README.md
@@ -22,7 +22,7 @@ Tasks are allocated from the arena when spawned for the first time. If the task
22The arena size can be configured in two ways: 22The arena size can be configured in two ways:
23 23
24- Via Cargo features: enable a Cargo feature like `task-arena-size-8192`. Only a selection of values 24- Via Cargo features: enable a Cargo feature like `task-arena-size-8192`. Only a selection of values
25 is available, check `Cargo.toml` for the list. 25 is available, see [Task Area Sizes](#task-arena-size) for reference.
26- Via environment variables at build time: set the variable named `EMBASSY_EXECUTOR_TASK_ARENA_SIZE`. For example 26- Via environment variables at build time: set the variable named `EMBASSY_EXECUTOR_TASK_ARENA_SIZE`. For example
27 `EMBASSY_EXECUTOR_TASK_ARENA_SIZE=4321 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`. 27 `EMBASSY_EXECUTOR_TASK_ARENA_SIZE=4321 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
28 Any value can be set, unlike with Cargo features. 28 Any value can be set, unlike with Cargo features.
diff --git a/embassy-executor/gen_config.py b/embassy-executor/gen_config.py
index e427d29f4..cf32bd530 100644
--- a/embassy-executor/gen_config.py
+++ b/embassy-executor/gen_config.py
@@ -45,6 +45,12 @@ things = ""
45for f in features: 45for f in features:
46 name = f["name"].replace("_", "-") 46 name = f["name"].replace("_", "-")
47 for val in f["vals"]: 47 for val in f["vals"]:
48 things += f"## {val}"
49 if val == f["default"]:
50 things += " (default)\n"
51 else:
52 things += "\n"
53
48 things += f"{name}-{val} = []" 54 things += f"{name}-{val} = []"
49 if val == f["default"]: 55 if val == f["default"]:
50 things += " # Default" 56 things += " # Default"
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 834ebf16a..6a2e493a2 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -3,6 +3,9 @@
3#![doc = include_str!("../README.md")] 3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)] 4#![warn(missing_docs)]
5 5
6//! ## Feature flags
7#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
8
6// This mod MUST go first, so that the others see its macros. 9// This mod MUST go first, so that the others see its macros.
7pub(crate) mod fmt; 10pub(crate) mod fmt;
8 11
diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs
index 0dbd391e8..2c2441dd5 100644
--- a/embassy-executor/tests/test.rs
+++ b/embassy-executor/tests/test.rs
@@ -135,3 +135,17 @@ fn executor_task_self_wake_twice() {
135 ] 135 ]
136 ) 136 )
137} 137}
138
139#[test]
140fn executor_task_cfg_args() {
141 // simulate cfg'ing away argument c
142 #[task]
143 async fn task1(a: u32, b: u32, #[cfg(any())] c: u32) {
144 let (_, _) = (a, b);
145 }
146
147 #[task]
148 async fn task2(a: u32, b: u32, #[cfg(all())] c: u32) {
149 let (_, _, _) = (a, b, c);
150 }
151}
diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml
index d95b2628c..f1be52da5 100644
--- a/embassy-net-adin1110/Cargo.toml
+++ b/embassy-net-adin1110/Cargo.toml
@@ -6,23 +6,22 @@ keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethern
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] 6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
7license = "MIT OR Apache-2.0" 7license = "MIT OR Apache-2.0"
8edition = "2021" 8edition = "2021"
9 9repository = "https://github.com/embassy-rs/embassy"
10# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11 10
12[dependencies] 11[dependencies]
13heapless = "0.8" 12heapless = "0.8"
14defmt = { version = "0.3", optional = true } 13defmt = { version = "0.3", optional = true }
15log = { version = "0.4", default-features = false, optional = true } 14log = { version = "0.4", default-features = false, optional = true }
16embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 15embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
17embedded-hal-async = { version = "=1.0.0-rc.2" } 16embedded-hal-async = { version = "=1.0.0-rc.3" }
18embedded-hal-bus = { version = "=0.1.0-rc.2", features = ["async"] } 17embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] }
19embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } 18embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
20embassy-time = { version = "0.2", path = "../embassy-time" } 19embassy-time = { version = "0.2", path = "../embassy-time" }
21embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 20embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
22bitfield = "0.14.0" 21bitfield = "0.14.0"
23 22
24[dev-dependencies] 23[dev-dependencies]
25embedded-hal-mock = { git = "https://github.com/Dirbaio/embedded-hal-mock", rev = "c5c4dca18e043e6386aee02173f61a65fea3981e", features = ["embedded-hal-async", "eh1"] } 24embedded-hal-mock = { version = "0.10.0-rc.4", features = ["embedded-hal-async", "eh1"] }
26crc = "3.0.1" 25crc = "3.0.1"
27env_logger = "0.10" 26env_logger = "0.10"
28critical-section = { version = "1.1.2", features = ["std"] } 27critical-section = { version = "1.1.2", features = ["std"] }
diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs
index ec020b70c..4b3c69f23 100644
--- a/embassy-net-adin1110/src/crc32.rs
+++ b/embassy-net-adin1110/src/crc32.rs
@@ -1,3 +1,4 @@
1/// CRC32 lookup table.
1pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ 2pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
2 0x0000_0000, 3 0x0000_0000,
3 0x7707_3096, 4 0x7707_3096,
@@ -263,8 +264,9 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
263pub struct ETH_FCS(pub u32); 264pub struct ETH_FCS(pub u32);
264 265
265impl ETH_FCS { 266impl ETH_FCS {
266 pub const CRC32_OK: u32 = 0x2144_df1c; 267 const CRC32_OK: u32 = 0x2144_df1c;
267 268
269 /// Create a new frame check sequence from `data`.
268 #[must_use] 270 #[must_use]
269 pub fn new(data: &[u8]) -> Self { 271 pub fn new(data: &[u8]) -> Self {
270 let fcs = data.iter().fold(u32::MAX, |crc, byte| { 272 let fcs = data.iter().fold(u32::MAX, |crc, byte| {
@@ -274,6 +276,7 @@ impl ETH_FCS {
274 Self(fcs) 276 Self(fcs)
275 } 277 }
276 278
279 /// Update the frame check sequence with `data`.
277 #[must_use] 280 #[must_use]
278 pub fn update(self, data: &[u8]) -> Self { 281 pub fn update(self, data: &[u8]) -> Self {
279 let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { 282 let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
@@ -283,16 +286,19 @@ impl ETH_FCS {
283 Self(fcs) 286 Self(fcs)
284 } 287 }
285 288
289 /// Check if the frame check sequence is correct.
286 #[must_use] 290 #[must_use]
287 pub fn crc_ok(&self) -> bool { 291 pub fn crc_ok(&self) -> bool {
288 self.0 == Self::CRC32_OK 292 self.0 == Self::CRC32_OK
289 } 293 }
290 294
295 /// Switch byte order.
291 #[must_use] 296 #[must_use]
292 pub fn hton_bytes(&self) -> [u8; 4] { 297 pub fn hton_bytes(&self) -> [u8; 4] {
293 self.0.to_le_bytes() 298 self.0.to_le_bytes()
294 } 299 }
295 300
301 /// Switch byte order as a u32.
296 #[must_use] 302 #[must_use]
297 pub fn hton(&self) -> u32 { 303 pub fn hton(&self) -> u32 {
298 self.0.to_le() 304 self.0.to_le()
diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs
index 080b3f94d..6ecfa587d 100644
--- a/embassy-net-adin1110/src/lib.rs
+++ b/embassy-net-adin1110/src/lib.rs
@@ -5,6 +5,7 @@
5#![allow(clippy::missing_errors_doc)] 5#![allow(clippy::missing_errors_doc)]
6#![allow(clippy::missing_panics_doc)] 6#![allow(clippy::missing_panics_doc)]
7#![doc = include_str!("../README.md")] 7#![doc = include_str!("../README.md")]
8#![warn(missing_docs)]
8 9
9// must go first! 10// must go first!
10mod fmt; 11mod fmt;
@@ -26,8 +27,9 @@ use embedded_hal_async::digital::Wait;
26use embedded_hal_async::spi::{Error, Operation, SpiDevice}; 27use embedded_hal_async::spi::{Error, Operation, SpiDevice};
27use heapless::Vec; 28use heapless::Vec;
28pub use mdio::MdioBus; 29pub use mdio::MdioBus;
29pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; 30pub use phy::Phy10BaseT1x;
30pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; 31use phy::{RegsC22, RegsC45};
32use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
31 33
32use crate::fmt::Bytes; 34use crate::fmt::Bytes;
33use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; 35use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader};
@@ -446,6 +448,7 @@ pub struct Runner<'d, SPI, INT, RST> {
446} 448}
447 449
448impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { 450impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
451 /// Run the driver.
449 #[allow(clippy::too_many_lines)] 452 #[allow(clippy::too_many_lines)]
450 pub async fn run(mut self) -> ! { 453 pub async fn run(mut self) -> ! {
451 loop { 454 loop {
diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs
index 1ae5f0043..6fea9370e 100644
--- a/embassy-net-adin1110/src/mdio.rs
+++ b/embassy-net-adin1110/src/mdio.rs
@@ -39,6 +39,7 @@ enum Reg13Op {
39/// 39///
40/// Clause 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf> 40/// Clause 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf>
41pub trait MdioBus { 41pub trait MdioBus {
42 /// Error type.
42 type Error; 43 type Error;
43 44
44 /// Read, Clause 22 45 /// Read, Clause 22
diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs
index beaf9466e..8780c2b9d 100644
--- a/embassy-net-adin1110/src/regs.rs
+++ b/embassy-net-adin1110/src/regs.rs
@@ -2,6 +2,7 @@ use core::fmt::{Debug, Display};
2 2
3use bitfield::{bitfield, bitfield_bitrange, bitfield_fields}; 3use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
4 4
5#[allow(missing_docs)]
5#[allow(non_camel_case_types)] 6#[allow(non_camel_case_types)]
6#[derive(Debug, Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))] 8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs
index bfb2c9c03..7ad4d449e 100644
--- a/embassy-net-driver-channel/src/lib.rs
+++ b/embassy-net-driver-channel/src/lib.rs
@@ -1,5 +1,6 @@
1#![no_std] 1#![no_std]
2#![doc = include_str!("../README.md")] 2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
3 4
4// must go first! 5// must go first!
5mod fmt; 6mod fmt;
@@ -15,6 +16,9 @@ use embassy_sync::blocking_mutex::Mutex;
15use embassy_sync::waitqueue::WakerRegistration; 16use embassy_sync::waitqueue::WakerRegistration;
16use embassy_sync::zerocopy_channel; 17use embassy_sync::zerocopy_channel;
17 18
19/// Channel state.
20///
21/// Holds a buffer of packets with size MTU, for both TX and RX.
18pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> { 22pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
19 rx: [PacketBuf<MTU>; N_RX], 23 rx: [PacketBuf<MTU>; N_RX],
20 tx: [PacketBuf<MTU>; N_TX], 24 tx: [PacketBuf<MTU>; N_TX],
@@ -24,6 +28,7 @@ pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
24impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> { 28impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> {
25 const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new(); 29 const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new();
26 30
31 /// Create a new channel state.
27 pub const fn new() -> Self { 32 pub const fn new() -> Self {
28 Self { 33 Self {
29 rx: [Self::NEW_PACKET; N_RX], 34 rx: [Self::NEW_PACKET; N_RX],
@@ -39,33 +44,45 @@ struct StateInner<'d, const MTU: usize> {
39 shared: Mutex<NoopRawMutex, RefCell<Shared>>, 44 shared: Mutex<NoopRawMutex, RefCell<Shared>>,
40} 45}
41 46
42/// State of the LinkState
43struct Shared { 47struct Shared {
44 link_state: LinkState, 48 link_state: LinkState,
45 waker: WakerRegistration, 49 waker: WakerRegistration,
46 hardware_address: driver::HardwareAddress, 50 hardware_address: driver::HardwareAddress,
47} 51}
48 52
53/// Channel runner.
54///
55/// Holds the shared state and the lower end of channels for inbound and outbound packets.
49pub struct Runner<'d, const MTU: usize> { 56pub struct Runner<'d, const MTU: usize> {
50 tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, 57 tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
51 rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, 58 rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
52 shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, 59 shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>,
53} 60}
54 61
62/// State runner.
63///
64/// Holds the shared state of the channel such as link state.
55#[derive(Clone, Copy)] 65#[derive(Clone, Copy)]
56pub struct StateRunner<'d> { 66pub struct StateRunner<'d> {
57 shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, 67 shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>,
58} 68}
59 69
70/// RX runner.
71///
72/// Holds the lower end of the channel for passing inbound packets up the stack.
60pub struct RxRunner<'d, const MTU: usize> { 73pub struct RxRunner<'d, const MTU: usize> {
61 rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, 74 rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
62} 75}
63 76
77/// TX runner.
78///
79/// Holds the lower end of the channel for passing outbound packets down the stack.
64pub struct TxRunner<'d, const MTU: usize> { 80pub struct TxRunner<'d, const MTU: usize> {
65 tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, 81 tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
66} 82}
67 83
68impl<'d, const MTU: usize> Runner<'d, MTU> { 84impl<'d, const MTU: usize> Runner<'d, MTU> {
85 /// Split the runner into separate runners for controlling state, rx and tx.
69 pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) { 86 pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) {
70 ( 87 (
71 StateRunner { shared: self.shared }, 88 StateRunner { shared: self.shared },
@@ -74,6 +91,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
74 ) 91 )
75 } 92 }
76 93
94 /// Split the runner into separate runners for controlling state, rx and tx borrowing the underlying state.
77 pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) { 95 pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) {
78 ( 96 (
79 StateRunner { shared: self.shared }, 97 StateRunner { shared: self.shared },
@@ -86,10 +104,12 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
86 ) 104 )
87 } 105 }
88 106
107 /// Create a state runner sharing the state channel.
89 pub fn state_runner(&self) -> StateRunner<'d> { 108 pub fn state_runner(&self) -> StateRunner<'d> {
90 StateRunner { shared: self.shared } 109 StateRunner { shared: self.shared }
91 } 110 }
92 111
112 /// Set the link state.
93 pub fn set_link_state(&mut self, state: LinkState) { 113 pub fn set_link_state(&mut self, state: LinkState) {
94 self.shared.lock(|s| { 114 self.shared.lock(|s| {
95 let s = &mut *s.borrow_mut(); 115 let s = &mut *s.borrow_mut();
@@ -98,6 +118,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
98 }); 118 });
99 } 119 }
100 120
121 /// Set the hardware address.
101 pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) { 122 pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) {
102 self.shared.lock(|s| { 123 self.shared.lock(|s| {
103 let s = &mut *s.borrow_mut(); 124 let s = &mut *s.borrow_mut();
@@ -106,16 +127,19 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
106 }); 127 });
107 } 128 }
108 129
130 /// Wait until there is space for more inbound packets and return a slice they can be copied into.
109 pub async fn rx_buf(&mut self) -> &mut [u8] { 131 pub async fn rx_buf(&mut self) -> &mut [u8] {
110 let p = self.rx_chan.send().await; 132 let p = self.rx_chan.send().await;
111 &mut p.buf 133 &mut p.buf
112 } 134 }
113 135
136 /// Check if there is space for more inbound packets right now.
114 pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { 137 pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
115 let p = self.rx_chan.try_send()?; 138 let p = self.rx_chan.try_send()?;
116 Some(&mut p.buf) 139 Some(&mut p.buf)
117 } 140 }
118 141
142 /// Polling the inbound channel if there is space for packets.
119 pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { 143 pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
120 match self.rx_chan.poll_send(cx) { 144 match self.rx_chan.poll_send(cx) {
121 Poll::Ready(p) => Poll::Ready(&mut p.buf), 145 Poll::Ready(p) => Poll::Ready(&mut p.buf),
@@ -123,22 +147,26 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
123 } 147 }
124 } 148 }
125 149
150 /// Mark packet of len bytes as pushed to the inbound channel.
126 pub fn rx_done(&mut self, len: usize) { 151 pub fn rx_done(&mut self, len: usize) {
127 let p = self.rx_chan.try_send().unwrap(); 152 let p = self.rx_chan.try_send().unwrap();
128 p.len = len; 153 p.len = len;
129 self.rx_chan.send_done(); 154 self.rx_chan.send_done();
130 } 155 }
131 156
157 /// Wait until there is space for more outbound packets and return a slice they can be copied into.
132 pub async fn tx_buf(&mut self) -> &mut [u8] { 158 pub async fn tx_buf(&mut self) -> &mut [u8] {
133 let p = self.tx_chan.receive().await; 159 let p = self.tx_chan.receive().await;
134 &mut p.buf[..p.len] 160 &mut p.buf[..p.len]
135 } 161 }
136 162
163 /// Check if there is space for more outbound packets right now.
137 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { 164 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
138 let p = self.tx_chan.try_receive()?; 165 let p = self.tx_chan.try_receive()?;
139 Some(&mut p.buf[..p.len]) 166 Some(&mut p.buf[..p.len])
140 } 167 }
141 168
169 /// Polling the outbound channel if there is space for packets.
142 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { 170 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
143 match self.tx_chan.poll_receive(cx) { 171 match self.tx_chan.poll_receive(cx) {
144 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), 172 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
@@ -146,12 +174,14 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
146 } 174 }
147 } 175 }
148 176
177 /// Mark outbound packet as copied.
149 pub fn tx_done(&mut self) { 178 pub fn tx_done(&mut self) {
150 self.tx_chan.receive_done(); 179 self.tx_chan.receive_done();
151 } 180 }
152} 181}
153 182
154impl<'d> StateRunner<'d> { 183impl<'d> StateRunner<'d> {
184 /// Set link state.
155 pub fn set_link_state(&self, state: LinkState) { 185 pub fn set_link_state(&self, state: LinkState) {
156 self.shared.lock(|s| { 186 self.shared.lock(|s| {
157 let s = &mut *s.borrow_mut(); 187 let s = &mut *s.borrow_mut();
@@ -160,6 +190,7 @@ impl<'d> StateRunner<'d> {
160 }); 190 });
161 } 191 }
162 192
193 /// Set the hardware address.
163 pub fn set_hardware_address(&self, address: driver::HardwareAddress) { 194 pub fn set_hardware_address(&self, address: driver::HardwareAddress) {
164 self.shared.lock(|s| { 195 self.shared.lock(|s| {
165 let s = &mut *s.borrow_mut(); 196 let s = &mut *s.borrow_mut();
@@ -170,16 +201,19 @@ impl<'d> StateRunner<'d> {
170} 201}
171 202
172impl<'d, const MTU: usize> RxRunner<'d, MTU> { 203impl<'d, const MTU: usize> RxRunner<'d, MTU> {
204 /// Wait until there is space for more inbound packets and return a slice they can be copied into.
173 pub async fn rx_buf(&mut self) -> &mut [u8] { 205 pub async fn rx_buf(&mut self) -> &mut [u8] {
174 let p = self.rx_chan.send().await; 206 let p = self.rx_chan.send().await;
175 &mut p.buf 207 &mut p.buf
176 } 208 }
177 209
210 /// Check if there is space for more inbound packets right now.
178 pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { 211 pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
179 let p = self.rx_chan.try_send()?; 212 let p = self.rx_chan.try_send()?;
180 Some(&mut p.buf) 213 Some(&mut p.buf)
181 } 214 }
182 215
216 /// Polling the inbound channel if there is space for packets.
183 pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { 217 pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
184 match self.rx_chan.poll_send(cx) { 218 match self.rx_chan.poll_send(cx) {
185 Poll::Ready(p) => Poll::Ready(&mut p.buf), 219 Poll::Ready(p) => Poll::Ready(&mut p.buf),
@@ -187,6 +221,7 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
187 } 221 }
188 } 222 }
189 223
224 /// Mark packet of len bytes as pushed to the inbound channel.
190 pub fn rx_done(&mut self, len: usize) { 225 pub fn rx_done(&mut self, len: usize) {
191 let p = self.rx_chan.try_send().unwrap(); 226 let p = self.rx_chan.try_send().unwrap();
192 p.len = len; 227 p.len = len;
@@ -195,16 +230,19 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
195} 230}
196 231
197impl<'d, const MTU: usize> TxRunner<'d, MTU> { 232impl<'d, const MTU: usize> TxRunner<'d, MTU> {
233 /// Wait until there is space for more outbound packets and return a slice they can be copied into.
198 pub async fn tx_buf(&mut self) -> &mut [u8] { 234 pub async fn tx_buf(&mut self) -> &mut [u8] {
199 let p = self.tx_chan.receive().await; 235 let p = self.tx_chan.receive().await;
200 &mut p.buf[..p.len] 236 &mut p.buf[..p.len]
201 } 237 }
202 238
239 /// Check if there is space for more outbound packets right now.
203 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { 240 pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
204 let p = self.tx_chan.try_receive()?; 241 let p = self.tx_chan.try_receive()?;
205 Some(&mut p.buf[..p.len]) 242 Some(&mut p.buf[..p.len])
206 } 243 }
207 244
245 /// Polling the outbound channel if there is space for packets.
208 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { 246 pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
209 match self.tx_chan.poll_receive(cx) { 247 match self.tx_chan.poll_receive(cx) {
210 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), 248 Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
@@ -212,11 +250,18 @@ impl<'d, const MTU: usize> TxRunner<'d, MTU> {
212 } 250 }
213 } 251 }
214 252
253 /// Mark outbound packet as copied.
215 pub fn tx_done(&mut self) { 254 pub fn tx_done(&mut self) {
216 self.tx_chan.receive_done(); 255 self.tx_chan.receive_done();
217 } 256 }
218} 257}
219 258
259/// Create a channel.
260///
261/// Returns a pair of handles for interfacing with the peripheral and the networking stack.
262///
263/// The runner is interfacing with the peripheral at the lower part of the stack.
264/// The device is interfacing with the networking stack on the layer above.
220pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( 265pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
221 state: &'d mut State<MTU, N_RX, N_TX>, 266 state: &'d mut State<MTU, N_RX, N_TX>,
222 hardware_address: driver::HardwareAddress, 267 hardware_address: driver::HardwareAddress,
@@ -257,17 +302,22 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
257 ) 302 )
258} 303}
259 304
305/// Represents a packet of size MTU.
260pub struct PacketBuf<const MTU: usize> { 306pub struct PacketBuf<const MTU: usize> {
261 len: usize, 307 len: usize,
262 buf: [u8; MTU], 308 buf: [u8; MTU],
263} 309}
264 310
265impl<const MTU: usize> PacketBuf<MTU> { 311impl<const MTU: usize> PacketBuf<MTU> {
312 /// Create a new packet buffer.
266 pub const fn new() -> Self { 313 pub const fn new() -> Self {
267 Self { len: 0, buf: [0; MTU] } 314 Self { len: 0, buf: [0; MTU] }
268 } 315 }
269} 316}
270 317
318/// Channel device.
319///
320/// Holds the shared state and upper end of channels for inbound and outbound packets.
271pub struct Device<'d, const MTU: usize> { 321pub struct Device<'d, const MTU: usize> {
272 rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, 322 rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
273 tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, 323 tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
@@ -314,6 +364,9 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> {
314 } 364 }
315} 365}
316 366
367/// A rx token.
368///
369/// Holds inbound receive channel and interfaces with embassy-net-driver.
317pub struct RxToken<'a, const MTU: usize> { 370pub struct RxToken<'a, const MTU: usize> {
318 rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>, 371 rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>,
319} 372}
@@ -331,6 +384,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> {
331 } 384 }
332} 385}
333 386
387/// A tx token.
388///
389/// Holds outbound transmit channel and interfaces with embassy-net-driver.
334pub struct TxToken<'a, const MTU: usize> { 390pub struct TxToken<'a, const MTU: usize> {
335 tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>, 391 tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>,
336} 392}
diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml
index 72e1d4e5c..8cd723c4c 100644
--- a/embassy-net-enc28j60/Cargo.toml
+++ b/embassy-net-enc28j60/Cargo.toml
@@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0"
8edition = "2021" 8edition = "2021"
9 9
10[dependencies] 10[dependencies]
11embedded-hal = { version = "1.0.0-rc.2" } 11embedded-hal = { version = "1.0.0-rc.3" }
12embedded-hal-async = { version = "=1.0.0-rc.2" } 12embedded-hal-async = { version = "=1.0.0-rc.3" }
13embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 13embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
14embassy-time = { version = "0.2", path = "../embassy-time" } 14embassy-time = { version = "0.2", path = "../embassy-time" }
15embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
index eb44a6544..61984dd53 100644
--- a/embassy-net-esp-hosted/Cargo.toml
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -2,6 +2,10 @@
2name = "embassy-net-esp-hosted" 2name = "embassy-net-esp-hosted"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5description = "embassy-net driver for ESP-Hosted"
6keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi", "async"]
7categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
8license = "MIT OR Apache-2.0"
5 9
6[dependencies] 10[dependencies]
7defmt = { version = "0.3", optional = true } 11defmt = { version = "0.3", optional = true }
@@ -12,11 +16,10 @@ embassy-sync = { version = "0.5.0", path = "../embassy-sync"}
12embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 16embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
13embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} 17embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
14 18
15embedded-hal = { version = "1.0.0-rc.2" } 19embedded-hal = { version = "1.0.0-rc.3" }
16embedded-hal-async = { version = "=1.0.0-rc.2" } 20embedded-hal-async = { version = "=1.0.0-rc.3" }
17 21
18noproto = { git="https://github.com/embassy-rs/noproto", rev = "f5e6d1f325b6ad4e344f60452b09576e24671f62", default-features = false, features = ["derive"] } 22noproto = "0.1.0"
19#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }
20heapless = "0.8" 23heapless = "0.8"
21 24
22[package.metadata.embassy_docs] 25[package.metadata.embassy_docs]
diff --git a/embassy-net-esp-hosted/README.md b/embassy-net-esp-hosted/README.md
new file mode 100644
index 000000000..3c9cc4c9e
--- /dev/null
+++ b/embassy-net-esp-hosted/README.md
@@ -0,0 +1,27 @@
1# ESP-Hosted `embassy-net` integration
2
3[`embassy-net`](https://crates.io/crates/embassy-net) integration for Espressif SoCs running the the ESP-Hosted stack.
4
5See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840) directory for usage examples with the nRF52840.
6
7## Supported chips
8
9- W5500
10- W5100S
11
12## Interoperability
13
14This crate can run on any executor.
15
16It supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async).
17
18
19## License
20
21This work is licensed under either of
22
23- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
24 http://www.apache.org/licenses/LICENSE-2.0)
25- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
26
27at your option.
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index c86891bc3..c8cea8503 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -5,38 +5,54 @@ use heapless::String;
5use crate::ioctl::Shared; 5use crate::ioctl::Shared;
6use crate::proto::{self, CtrlMsg}; 6use crate::proto::{self, CtrlMsg};
7 7
8/// Errors reported by control.
8#[derive(Copy, Clone, PartialEq, Eq, Debug)] 9#[derive(Copy, Clone, PartialEq, Eq, Debug)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))] 10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10pub enum Error { 11pub enum Error {
12 /// The operation failed with the given error code.
11 Failed(u32), 13 Failed(u32),
14 /// The operation timed out.
12 Timeout, 15 Timeout,
16 /// Internal error.
13 Internal, 17 Internal,
14} 18}
15 19
20/// Handle for managing the network and WiFI state.
16pub struct Control<'a> { 21pub struct Control<'a> {
17 state_ch: ch::StateRunner<'a>, 22 state_ch: ch::StateRunner<'a>,
18 shared: &'a Shared, 23 shared: &'a Shared,
19} 24}
20 25
26/// WiFi mode.
21#[allow(unused)] 27#[allow(unused)]
22#[derive(Copy, Clone, PartialEq, Eq, Debug)] 28#[derive(Copy, Clone, PartialEq, Eq, Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))] 29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24enum WifiMode { 30enum WifiMode {
31 /// No mode.
25 None = 0, 32 None = 0,
33 /// Client station.
26 Sta = 1, 34 Sta = 1,
35 /// Access point mode.
27 Ap = 2, 36 Ap = 2,
37 /// Repeater mode.
28 ApSta = 3, 38 ApSta = 3,
29} 39}
30 40
31pub use proto::CtrlWifiSecProt as Security; 41pub use proto::CtrlWifiSecProt as Security;
32 42
43/// WiFi status.
33#[derive(Clone, Debug)] 44#[derive(Clone, Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))] 45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub struct Status { 46pub struct Status {
47 /// Service Set Identifier.
36 pub ssid: String<32>, 48 pub ssid: String<32>,
49 /// Basic Service Set Identifier.
37 pub bssid: [u8; 6], 50 pub bssid: [u8; 6],
51 /// Received Signal Strength Indicator.
38 pub rssi: i32, 52 pub rssi: i32,
53 /// WiFi channel.
39 pub channel: u32, 54 pub channel: u32,
55 /// Security mode.
40 pub security: Security, 56 pub security: Security,
41} 57}
42 58
@@ -65,6 +81,7 @@ impl<'a> Control<'a> {
65 Self { state_ch, shared } 81 Self { state_ch, shared }
66 } 82 }
67 83
84 /// Initialize device.
68 pub async fn init(&mut self) -> Result<(), Error> { 85 pub async fn init(&mut self) -> Result<(), Error> {
69 debug!("wait for init event..."); 86 debug!("wait for init event...");
70 self.shared.init_wait().await; 87 self.shared.init_wait().await;
@@ -82,6 +99,7 @@ impl<'a> Control<'a> {
82 Ok(()) 99 Ok(())
83 } 100 }
84 101
102 /// Get the current status.
85 pub async fn get_status(&mut self) -> Result<Status, Error> { 103 pub async fn get_status(&mut self) -> Result<Status, Error> {
86 let req = proto::CtrlMsgReqGetApConfig {}; 104 let req = proto::CtrlMsgReqGetApConfig {};
87 ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp); 105 ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp);
@@ -95,6 +113,7 @@ impl<'a> Control<'a> {
95 }) 113 })
96 } 114 }
97 115
116 /// Connect to the network identified by ssid using the provided password.
98 pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { 117 pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
99 let req = proto::CtrlMsgReqConnectAp { 118 let req = proto::CtrlMsgReqConnectAp {
100 ssid: unwrap!(String::try_from(ssid)), 119 ssid: unwrap!(String::try_from(ssid)),
@@ -108,6 +127,7 @@ impl<'a> Control<'a> {
108 Ok(()) 127 Ok(())
109 } 128 }
110 129
130 /// Disconnect from any currently connected network.
111 pub async fn disconnect(&mut self) -> Result<(), Error> { 131 pub async fn disconnect(&mut self) -> Result<(), Error> {
112 let req = proto::CtrlMsgReqGetStatus {}; 132 let req = proto::CtrlMsgReqGetStatus {};
113 ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp); 133 ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp);
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index d61eaef3a..c78578bf1 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -1,4 +1,6 @@
1#![no_std] 1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
2 4
3use embassy_futures::select::{select4, Either4}; 5use embassy_futures::select::{select4, Either4};
4use embassy_net_driver_channel as ch; 6use embassy_net_driver_channel as ch;
@@ -97,12 +99,14 @@ enum InterfaceType {
97const MAX_SPI_BUFFER_SIZE: usize = 1600; 99const MAX_SPI_BUFFER_SIZE: usize = 1600;
98const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20); 100const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20);
99 101
102/// State for the esp-hosted driver.
100pub struct State { 103pub struct State {
101 shared: Shared, 104 shared: Shared,
102 ch: ch::State<MTU, 4, 4>, 105 ch: ch::State<MTU, 4, 4>,
103} 106}
104 107
105impl State { 108impl State {
109 /// Create a new state.
106 pub fn new() -> Self { 110 pub fn new() -> Self {
107 Self { 111 Self {
108 shared: Shared::new(), 112 shared: Shared::new(),
@@ -111,8 +115,13 @@ impl State {
111 } 115 }
112} 116}
113 117
118/// Type alias for network driver.
114pub type NetDriver<'a> = ch::Device<'a, MTU>; 119pub type NetDriver<'a> = ch::Device<'a, MTU>;
115 120
121/// Create a new esp-hosted driver using the provided state, SPI peripheral and pins.
122///
123/// Returns a device handle for interfacing with embassy-net, a control handle for
124/// interacting with the driver, and a runner for communicating with the WiFi device.
116pub async fn new<'a, SPI, IN, OUT>( 125pub async fn new<'a, SPI, IN, OUT>(
117 state: &'a mut State, 126 state: &'a mut State,
118 spi: SPI, 127 spi: SPI,
@@ -144,6 +153,7 @@ where
144 (device, Control::new(state_ch, &state.shared), runner) 153 (device, Control::new(state_ch, &state.shared), runner)
145} 154}
146 155
156/// Runner for communicating with the WiFi device.
147pub struct Runner<'a, SPI, IN, OUT> { 157pub struct Runner<'a, SPI, IN, OUT> {
148 ch: ch::Runner<'a, MTU>, 158 ch: ch::Runner<'a, MTU>,
149 state_ch: ch::StateRunner<'a>, 159 state_ch: ch::StateRunner<'a>,
@@ -166,6 +176,7 @@ where
166{ 176{
167 async fn init(&mut self) {} 177 async fn init(&mut self) {}
168 178
179 /// Run the packet processing.
169 pub async fn run(mut self) -> ! { 180 pub async fn run(mut self) -> ! {
170 debug!("resetting..."); 181 debug!("resetting...");
171 self.reset.set_low().unwrap(); 182 self.reset.set_low().unwrap();
diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs
index 8ceb1579d..034d5bf84 100644
--- a/embassy-net-esp-hosted/src/proto.rs
+++ b/embassy-net-esp-hosted/src/proto.rs
@@ -4,7 +4,7 @@ use heapless::{String, Vec};
4 4
5#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 5#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))] 6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub struct ScanResult { 7pub(crate) struct ScanResult {
8 #[noproto(tag = "1")] 8 #[noproto(tag = "1")]
9 pub ssid: String<32>, 9 pub ssid: String<32>,
10 #[noproto(tag = "2")] 10 #[noproto(tag = "2")]
@@ -19,7 +19,7 @@ pub struct ScanResult {
19 19
20#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 20#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct ConnectedStaList { 22pub(crate) struct ConnectedStaList {
23 #[noproto(tag = "1")] 23 #[noproto(tag = "1")]
24 pub mac: String<32>, 24 pub mac: String<32>,
25 #[noproto(tag = "2")] 25 #[noproto(tag = "2")]
@@ -29,14 +29,14 @@ pub struct ConnectedStaList {
29 29
30#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 30#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))] 31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub struct CtrlMsgReqGetMacAddress { 32pub(crate) struct CtrlMsgReqGetMacAddress {
33 #[noproto(tag = "1")] 33 #[noproto(tag = "1")]
34 pub mode: u32, 34 pub mode: u32,
35} 35}
36 36
37#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 37#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))] 38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39pub struct CtrlMsgRespGetMacAddress { 39pub(crate) struct CtrlMsgRespGetMacAddress {
40 #[noproto(tag = "1")] 40 #[noproto(tag = "1")]
41 pub mac: String<32>, 41 pub mac: String<32>,
42 #[noproto(tag = "2")] 42 #[noproto(tag = "2")]
@@ -45,11 +45,11 @@ pub struct CtrlMsgRespGetMacAddress {
45 45
46#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 46#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))] 47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub struct CtrlMsgReqGetMode {} 48pub(crate) struct CtrlMsgReqGetMode {}
49 49
50#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 50#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))] 51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52pub struct CtrlMsgRespGetMode { 52pub(crate) struct CtrlMsgRespGetMode {
53 #[noproto(tag = "1")] 53 #[noproto(tag = "1")]
54 pub mode: u32, 54 pub mode: u32,
55 #[noproto(tag = "2")] 55 #[noproto(tag = "2")]
@@ -58,32 +58,32 @@ pub struct CtrlMsgRespGetMode {
58 58
59#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 59#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))] 60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61pub struct CtrlMsgReqSetMode { 61pub(crate) struct CtrlMsgReqSetMode {
62 #[noproto(tag = "1")] 62 #[noproto(tag = "1")]
63 pub mode: u32, 63 pub mode: u32,
64} 64}
65 65
66#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 66#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
67#[cfg_attr(feature = "defmt", derive(defmt::Format))] 67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
68pub struct CtrlMsgRespSetMode { 68pub(crate) struct CtrlMsgRespSetMode {
69 #[noproto(tag = "1")] 69 #[noproto(tag = "1")]
70 pub resp: u32, 70 pub resp: u32,
71} 71}
72 72
73#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 73#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub struct CtrlMsgReqGetStatus {} 75pub(crate) struct CtrlMsgReqGetStatus {}
76 76
77#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 77#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))] 78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79pub struct CtrlMsgRespGetStatus { 79pub(crate) struct CtrlMsgRespGetStatus {
80 #[noproto(tag = "1")] 80 #[noproto(tag = "1")]
81 pub resp: u32, 81 pub resp: u32,
82} 82}
83 83
84#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 84#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))] 85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub struct CtrlMsgReqSetMacAddress { 86pub(crate) struct CtrlMsgReqSetMacAddress {
87 #[noproto(tag = "1")] 87 #[noproto(tag = "1")]
88 pub mac: String<32>, 88 pub mac: String<32>,
89 #[noproto(tag = "2")] 89 #[noproto(tag = "2")]
@@ -92,18 +92,18 @@ pub struct CtrlMsgReqSetMacAddress {
92 92
93#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 93#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))] 94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95pub struct CtrlMsgRespSetMacAddress { 95pub(crate) struct CtrlMsgRespSetMacAddress {
96 #[noproto(tag = "1")] 96 #[noproto(tag = "1")]
97 pub resp: u32, 97 pub resp: u32,
98} 98}
99 99
100#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 100#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))] 101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub struct CtrlMsgReqGetApConfig {} 102pub(crate) struct CtrlMsgReqGetApConfig {}
103 103
104#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 104#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))] 105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub struct CtrlMsgRespGetApConfig { 106pub(crate) struct CtrlMsgRespGetApConfig {
107 #[noproto(tag = "1")] 107 #[noproto(tag = "1")]
108 pub ssid: String<32>, 108 pub ssid: String<32>,
109 #[noproto(tag = "2")] 109 #[noproto(tag = "2")]
@@ -120,7 +120,7 @@ pub struct CtrlMsgRespGetApConfig {
120 120
121#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 121#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
122#[cfg_attr(feature = "defmt", derive(defmt::Format))] 122#[cfg_attr(feature = "defmt", derive(defmt::Format))]
123pub struct CtrlMsgReqConnectAp { 123pub(crate) struct CtrlMsgReqConnectAp {
124 #[noproto(tag = "1")] 124 #[noproto(tag = "1")]
125 pub ssid: String<32>, 125 pub ssid: String<32>,
126 #[noproto(tag = "2")] 126 #[noproto(tag = "2")]
@@ -135,7 +135,7 @@ pub struct CtrlMsgReqConnectAp {
135 135
136#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 136#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
137#[cfg_attr(feature = "defmt", derive(defmt::Format))] 137#[cfg_attr(feature = "defmt", derive(defmt::Format))]
138pub struct CtrlMsgRespConnectAp { 138pub(crate) struct CtrlMsgRespConnectAp {
139 #[noproto(tag = "1")] 139 #[noproto(tag = "1")]
140 pub resp: u32, 140 pub resp: u32,
141 #[noproto(tag = "2")] 141 #[noproto(tag = "2")]
@@ -144,11 +144,11 @@ pub struct CtrlMsgRespConnectAp {
144 144
145#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 145#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
146#[cfg_attr(feature = "defmt", derive(defmt::Format))] 146#[cfg_attr(feature = "defmt", derive(defmt::Format))]
147pub struct CtrlMsgReqGetSoftApConfig {} 147pub(crate) struct CtrlMsgReqGetSoftApConfig {}
148 148
149#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 149#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
150#[cfg_attr(feature = "defmt", derive(defmt::Format))] 150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151pub struct CtrlMsgRespGetSoftApConfig { 151pub(crate) struct CtrlMsgRespGetSoftApConfig {
152 #[noproto(tag = "1")] 152 #[noproto(tag = "1")]
153 pub ssid: String<32>, 153 pub ssid: String<32>,
154 #[noproto(tag = "2")] 154 #[noproto(tag = "2")]
@@ -169,7 +169,7 @@ pub struct CtrlMsgRespGetSoftApConfig {
169 169
170#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 170#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
171#[cfg_attr(feature = "defmt", derive(defmt::Format))] 171#[cfg_attr(feature = "defmt", derive(defmt::Format))]
172pub struct CtrlMsgReqStartSoftAp { 172pub(crate) struct CtrlMsgReqStartSoftAp {
173 #[noproto(tag = "1")] 173 #[noproto(tag = "1")]
174 pub ssid: String<32>, 174 pub ssid: String<32>,
175 #[noproto(tag = "2")] 175 #[noproto(tag = "2")]
@@ -188,7 +188,7 @@ pub struct CtrlMsgReqStartSoftAp {
188 188
189#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 189#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
190#[cfg_attr(feature = "defmt", derive(defmt::Format))] 190#[cfg_attr(feature = "defmt", derive(defmt::Format))]
191pub struct CtrlMsgRespStartSoftAp { 191pub(crate) struct CtrlMsgRespStartSoftAp {
192 #[noproto(tag = "1")] 192 #[noproto(tag = "1")]
193 pub resp: u32, 193 pub resp: u32,
194 #[noproto(tag = "2")] 194 #[noproto(tag = "2")]
@@ -197,11 +197,11 @@ pub struct CtrlMsgRespStartSoftAp {
197 197
198#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 198#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
199#[cfg_attr(feature = "defmt", derive(defmt::Format))] 199#[cfg_attr(feature = "defmt", derive(defmt::Format))]
200pub struct CtrlMsgReqScanResult {} 200pub(crate) struct CtrlMsgReqScanResult {}
201 201
202#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 202#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
203#[cfg_attr(feature = "defmt", derive(defmt::Format))] 203#[cfg_attr(feature = "defmt", derive(defmt::Format))]
204pub struct CtrlMsgRespScanResult { 204pub(crate) struct CtrlMsgRespScanResult {
205 #[noproto(tag = "1")] 205 #[noproto(tag = "1")]
206 pub count: u32, 206 pub count: u32,
207 #[noproto(repeated, tag = "2")] 207 #[noproto(repeated, tag = "2")]
@@ -212,11 +212,11 @@ pub struct CtrlMsgRespScanResult {
212 212
213#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 213#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
214#[cfg_attr(feature = "defmt", derive(defmt::Format))] 214#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub struct CtrlMsgReqSoftApConnectedSta {} 215pub(crate) struct CtrlMsgReqSoftApConnectedSta {}
216 216
217#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 217#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
218#[cfg_attr(feature = "defmt", derive(defmt::Format))] 218#[cfg_attr(feature = "defmt", derive(defmt::Format))]
219pub struct CtrlMsgRespSoftApConnectedSta { 219pub(crate) struct CtrlMsgRespSoftApConnectedSta {
220 #[noproto(tag = "1")] 220 #[noproto(tag = "1")]
221 pub num: u32, 221 pub num: u32,
222 #[noproto(repeated, tag = "2")] 222 #[noproto(repeated, tag = "2")]
@@ -227,43 +227,43 @@ pub struct CtrlMsgRespSoftApConnectedSta {
227 227
228#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 228#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
229#[cfg_attr(feature = "defmt", derive(defmt::Format))] 229#[cfg_attr(feature = "defmt", derive(defmt::Format))]
230pub struct CtrlMsgReqOtaBegin {} 230pub(crate) struct CtrlMsgReqOtaBegin {}
231 231
232#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 232#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
233#[cfg_attr(feature = "defmt", derive(defmt::Format))] 233#[cfg_attr(feature = "defmt", derive(defmt::Format))]
234pub struct CtrlMsgRespOtaBegin { 234pub(crate) struct CtrlMsgRespOtaBegin {
235 #[noproto(tag = "1")] 235 #[noproto(tag = "1")]
236 pub resp: u32, 236 pub resp: u32,
237} 237}
238 238
239#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 239#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
240#[cfg_attr(feature = "defmt", derive(defmt::Format))] 240#[cfg_attr(feature = "defmt", derive(defmt::Format))]
241pub struct CtrlMsgReqOtaWrite { 241pub(crate) struct CtrlMsgReqOtaWrite {
242 #[noproto(tag = "1")] 242 #[noproto(tag = "1")]
243 pub ota_data: Vec<u8, 1024>, 243 pub ota_data: Vec<u8, 1024>,
244} 244}
245 245
246#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 246#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
247#[cfg_attr(feature = "defmt", derive(defmt::Format))] 247#[cfg_attr(feature = "defmt", derive(defmt::Format))]
248pub struct CtrlMsgRespOtaWrite { 248pub(crate) struct CtrlMsgRespOtaWrite {
249 #[noproto(tag = "1")] 249 #[noproto(tag = "1")]
250 pub resp: u32, 250 pub resp: u32,
251} 251}
252 252
253#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 253#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
254#[cfg_attr(feature = "defmt", derive(defmt::Format))] 254#[cfg_attr(feature = "defmt", derive(defmt::Format))]
255pub struct CtrlMsgReqOtaEnd {} 255pub(crate) struct CtrlMsgReqOtaEnd {}
256 256
257#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 257#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
258#[cfg_attr(feature = "defmt", derive(defmt::Format))] 258#[cfg_attr(feature = "defmt", derive(defmt::Format))]
259pub struct CtrlMsgRespOtaEnd { 259pub(crate) struct CtrlMsgRespOtaEnd {
260 #[noproto(tag = "1")] 260 #[noproto(tag = "1")]
261 pub resp: u32, 261 pub resp: u32,
262} 262}
263 263
264#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 264#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
265#[cfg_attr(feature = "defmt", derive(defmt::Format))] 265#[cfg_attr(feature = "defmt", derive(defmt::Format))]
266pub struct CtrlMsgReqVendorIeData { 266pub(crate) struct CtrlMsgReqVendorIeData {
267 #[noproto(tag = "1")] 267 #[noproto(tag = "1")]
268 pub element_id: u32, 268 pub element_id: u32,
269 #[noproto(tag = "2")] 269 #[noproto(tag = "2")]
@@ -278,7 +278,7 @@ pub struct CtrlMsgReqVendorIeData {
278 278
279#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 279#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
280#[cfg_attr(feature = "defmt", derive(defmt::Format))] 280#[cfg_attr(feature = "defmt", derive(defmt::Format))]
281pub struct CtrlMsgReqSetSoftApVendorSpecificIe { 281pub(crate) struct CtrlMsgReqSetSoftApVendorSpecificIe {
282 #[noproto(tag = "1")] 282 #[noproto(tag = "1")]
283 pub enable: bool, 283 pub enable: bool,
284 #[noproto(tag = "2")] 284 #[noproto(tag = "2")]
@@ -291,32 +291,32 @@ pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
291 291
292#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 292#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
293#[cfg_attr(feature = "defmt", derive(defmt::Format))] 293#[cfg_attr(feature = "defmt", derive(defmt::Format))]
294pub struct CtrlMsgRespSetSoftApVendorSpecificIe { 294pub(crate) struct CtrlMsgRespSetSoftApVendorSpecificIe {
295 #[noproto(tag = "1")] 295 #[noproto(tag = "1")]
296 pub resp: u32, 296 pub resp: u32,
297} 297}
298 298
299#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 299#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
300#[cfg_attr(feature = "defmt", derive(defmt::Format))] 300#[cfg_attr(feature = "defmt", derive(defmt::Format))]
301pub struct CtrlMsgReqSetWifiMaxTxPower { 301pub(crate) struct CtrlMsgReqSetWifiMaxTxPower {
302 #[noproto(tag = "1")] 302 #[noproto(tag = "1")]
303 pub wifi_max_tx_power: u32, 303 pub wifi_max_tx_power: u32,
304} 304}
305 305
306#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 306#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
307#[cfg_attr(feature = "defmt", derive(defmt::Format))] 307#[cfg_attr(feature = "defmt", derive(defmt::Format))]
308pub struct CtrlMsgRespSetWifiMaxTxPower { 308pub(crate) struct CtrlMsgRespSetWifiMaxTxPower {
309 #[noproto(tag = "1")] 309 #[noproto(tag = "1")]
310 pub resp: u32, 310 pub resp: u32,
311} 311}
312 312
313#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 313#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
314#[cfg_attr(feature = "defmt", derive(defmt::Format))] 314#[cfg_attr(feature = "defmt", derive(defmt::Format))]
315pub struct CtrlMsgReqGetWifiCurrTxPower {} 315pub(crate) struct CtrlMsgReqGetWifiCurrTxPower {}
316 316
317#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 317#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
318#[cfg_attr(feature = "defmt", derive(defmt::Format))] 318#[cfg_attr(feature = "defmt", derive(defmt::Format))]
319pub struct CtrlMsgRespGetWifiCurrTxPower { 319pub(crate) struct CtrlMsgRespGetWifiCurrTxPower {
320 #[noproto(tag = "1")] 320 #[noproto(tag = "1")]
321 pub wifi_curr_tx_power: u32, 321 pub wifi_curr_tx_power: u32,
322 #[noproto(tag = "2")] 322 #[noproto(tag = "2")]
@@ -325,7 +325,7 @@ pub struct CtrlMsgRespGetWifiCurrTxPower {
325 325
326#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 326#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
327#[cfg_attr(feature = "defmt", derive(defmt::Format))] 327#[cfg_attr(feature = "defmt", derive(defmt::Format))]
328pub struct CtrlMsgReqConfigHeartbeat { 328pub(crate) struct CtrlMsgReqConfigHeartbeat {
329 #[noproto(tag = "1")] 329 #[noproto(tag = "1")]
330 pub enable: bool, 330 pub enable: bool,
331 #[noproto(tag = "2")] 331 #[noproto(tag = "2")]
@@ -334,7 +334,7 @@ pub struct CtrlMsgReqConfigHeartbeat {
334 334
335#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 335#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
336#[cfg_attr(feature = "defmt", derive(defmt::Format))] 336#[cfg_attr(feature = "defmt", derive(defmt::Format))]
337pub struct CtrlMsgRespConfigHeartbeat { 337pub(crate) struct CtrlMsgRespConfigHeartbeat {
338 #[noproto(tag = "1")] 338 #[noproto(tag = "1")]
339 pub resp: u32, 339 pub resp: u32,
340} 340}
@@ -342,28 +342,28 @@ pub struct CtrlMsgRespConfigHeartbeat {
342 342
343#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 343#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
344#[cfg_attr(feature = "defmt", derive(defmt::Format))] 344#[cfg_attr(feature = "defmt", derive(defmt::Format))]
345pub struct CtrlMsgEventEspInit { 345pub(crate) struct CtrlMsgEventEspInit {
346 #[noproto(tag = "1")] 346 #[noproto(tag = "1")]
347 pub init_data: Vec<u8, 64>, 347 pub init_data: Vec<u8, 64>,
348} 348}
349 349
350#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 350#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
351#[cfg_attr(feature = "defmt", derive(defmt::Format))] 351#[cfg_attr(feature = "defmt", derive(defmt::Format))]
352pub struct CtrlMsgEventHeartbeat { 352pub(crate) struct CtrlMsgEventHeartbeat {
353 #[noproto(tag = "1")] 353 #[noproto(tag = "1")]
354 pub hb_num: u32, 354 pub hb_num: u32,
355} 355}
356 356
357#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 357#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
358#[cfg_attr(feature = "defmt", derive(defmt::Format))] 358#[cfg_attr(feature = "defmt", derive(defmt::Format))]
359pub struct CtrlMsgEventStationDisconnectFromAp { 359pub(crate) struct CtrlMsgEventStationDisconnectFromAp {
360 #[noproto(tag = "1")] 360 #[noproto(tag = "1")]
361 pub resp: u32, 361 pub resp: u32,
362} 362}
363 363
364#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 364#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
365#[cfg_attr(feature = "defmt", derive(defmt::Format))] 365#[cfg_attr(feature = "defmt", derive(defmt::Format))]
366pub struct CtrlMsgEventStationDisconnectFromEspSoftAp { 366pub(crate) struct CtrlMsgEventStationDisconnectFromEspSoftAp {
367 #[noproto(tag = "1")] 367 #[noproto(tag = "1")]
368 pub resp: u32, 368 pub resp: u32,
369 #[noproto(tag = "2")] 369 #[noproto(tag = "2")]
@@ -372,7 +372,7 @@ pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
372 372
373#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] 373#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
374#[cfg_attr(feature = "defmt", derive(defmt::Format))] 374#[cfg_attr(feature = "defmt", derive(defmt::Format))]
375pub struct CtrlMsg { 375pub(crate) struct CtrlMsg {
376 /// msg_type could be req, resp or Event 376 /// msg_type could be req, resp or Event
377 #[noproto(tag = "1")] 377 #[noproto(tag = "1")]
378 pub msg_type: CtrlMsgType, 378 pub msg_type: CtrlMsgType,
@@ -390,7 +390,7 @@ pub struct CtrlMsg {
390/// union of all msg ids 390/// union of all msg ids
391#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)] 391#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)]
392#[cfg_attr(feature = "defmt", derive(defmt::Format))] 392#[cfg_attr(feature = "defmt", derive(defmt::Format))]
393pub enum CtrlMsgPayload { 393pub(crate) enum CtrlMsgPayload {
394 /// * Requests * 394 /// * Requests *
395 #[noproto(tag = "101")] 395 #[noproto(tag = "101")]
396 ReqGetMacAddress(CtrlMsgReqGetMacAddress), 396 ReqGetMacAddress(CtrlMsgReqGetMacAddress),
@@ -492,7 +492,7 @@ pub enum CtrlMsgPayload {
492#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 492#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
493#[repr(u32)] 493#[repr(u32)]
494#[cfg_attr(feature = "defmt", derive(defmt::Format))] 494#[cfg_attr(feature = "defmt", derive(defmt::Format))]
495pub enum CtrlVendorIeType { 495pub(crate) enum CtrlVendorIeType {
496 #[default] 496 #[default]
497 Beacon = 0, 497 Beacon = 0,
498 ProbeReq = 1, 498 ProbeReq = 1,
@@ -504,7 +504,7 @@ pub enum CtrlVendorIeType {
504#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 504#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
505#[repr(u32)] 505#[repr(u32)]
506#[cfg_attr(feature = "defmt", derive(defmt::Format))] 506#[cfg_attr(feature = "defmt", derive(defmt::Format))]
507pub enum CtrlVendorIeid { 507pub(crate) enum CtrlVendorIeid {
508 #[default] 508 #[default]
509 Id0 = 0, 509 Id0 = 0,
510 Id1 = 1, 510 Id1 = 1,
@@ -513,7 +513,7 @@ pub enum CtrlVendorIeid {
513#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 513#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
514#[repr(u32)] 514#[repr(u32)]
515#[cfg_attr(feature = "defmt", derive(defmt::Format))] 515#[cfg_attr(feature = "defmt", derive(defmt::Format))]
516pub enum CtrlWifiMode { 516pub(crate) enum CtrlWifiMode {
517 #[default] 517 #[default]
518 None = 0, 518 None = 0,
519 Sta = 1, 519 Sta = 1,
@@ -524,7 +524,7 @@ pub enum CtrlWifiMode {
524#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 524#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
525#[repr(u32)] 525#[repr(u32)]
526#[cfg_attr(feature = "defmt", derive(defmt::Format))] 526#[cfg_attr(feature = "defmt", derive(defmt::Format))]
527pub enum CtrlWifiBw { 527pub(crate) enum CtrlWifiBw {
528 #[default] 528 #[default]
529 BwInvalid = 0, 529 BwInvalid = 0,
530 Ht20 = 1, 530 Ht20 = 1,
@@ -534,13 +534,15 @@ pub enum CtrlWifiBw {
534#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 534#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
535#[repr(u32)] 535#[repr(u32)]
536#[cfg_attr(feature = "defmt", derive(defmt::Format))] 536#[cfg_attr(feature = "defmt", derive(defmt::Format))]
537pub enum CtrlWifiPowerSave { 537pub(crate) enum CtrlWifiPowerSave {
538 #[default] 538 #[default]
539 PsInvalid = 0, 539 PsInvalid = 0,
540 MinModem = 1, 540 MinModem = 1,
541 MaxModem = 2, 541 MaxModem = 2,
542} 542}
543 543
544/// Wifi Security Settings
545#[allow(missing_docs)]
544#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 546#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
545#[repr(u32)] 547#[repr(u32)]
546#[cfg_attr(feature = "defmt", derive(defmt::Format))] 548#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -560,7 +562,7 @@ pub enum CtrlWifiSecProt {
560#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 562#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
561#[repr(u32)] 563#[repr(u32)]
562#[cfg_attr(feature = "defmt", derive(defmt::Format))] 564#[cfg_attr(feature = "defmt", derive(defmt::Format))]
563pub enum CtrlStatus { 565pub(crate) enum CtrlStatus {
564 #[default] 566 #[default]
565 Connected = 0, 567 Connected = 0,
566 NotConnected = 1, 568 NotConnected = 1,
@@ -573,7 +575,7 @@ pub enum CtrlStatus {
573#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 575#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
574#[repr(u32)] 576#[repr(u32)]
575#[cfg_attr(feature = "defmt", derive(defmt::Format))] 577#[cfg_attr(feature = "defmt", derive(defmt::Format))]
576pub enum CtrlMsgType { 578pub(crate) enum CtrlMsgType {
577 #[default] 579 #[default]
578 MsgTypeInvalid = 0, 580 MsgTypeInvalid = 0,
579 Req = 1, 581 Req = 1,
@@ -585,7 +587,7 @@ pub enum CtrlMsgType {
585#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] 587#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
586#[repr(u32)] 588#[repr(u32)]
587#[cfg_attr(feature = "defmt", derive(defmt::Format))] 589#[cfg_attr(feature = "defmt", derive(defmt::Format))]
588pub enum CtrlMsgId { 590pub(crate) enum CtrlMsgId {
589 #[default] 591 #[default]
590 MsgIdInvalid = 0, 592 MsgIdInvalid = 0,
591 /// * Request Msgs * 593 /// * Request Msgs *
diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml
index 4e374c365..7e2c7bfd5 100644
--- a/embassy-net-tuntap/Cargo.toml
+++ b/embassy-net-tuntap/Cargo.toml
@@ -6,6 +6,7 @@ keywords = ["embedded", "tuntap", "embassy-net", "embedded-hal-async", "ethernet
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] 6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
7license = "MIT OR Apache-2.0" 7license = "MIT OR Apache-2.0"
8edition = "2021" 8edition = "2021"
9repository = "https://github.com/embassy-rs/embassy"
9 10
10[dependencies] 11[dependencies]
11embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 12embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
@@ -16,4 +17,4 @@ libc = "0.2.101"
16[package.metadata.embassy_docs] 17[package.metadata.embassy_docs]
17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-tuntap-v$VERSION/embassy-net-tuntap/src/" 18src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-tuntap-v$VERSION/embassy-net-tuntap/src/"
18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-tuntap/src/" 19src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-tuntap/src/"
19target = "thumbv7em-none-eabi" \ No newline at end of file 20target = "thumbv7em-none-eabi"
diff --git a/embassy-net-tuntap/src/lib.rs b/embassy-net-tuntap/src/lib.rs
index 75c54c487..de30934eb 100644
--- a/embassy-net-tuntap/src/lib.rs
+++ b/embassy-net-tuntap/src/lib.rs
@@ -1,3 +1,5 @@
1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
1use std::io; 3use std::io;
2use std::io::{Read, Write}; 4use std::io::{Read, Write};
3use std::os::unix::io::{AsRawFd, RawFd}; 5use std::os::unix::io::{AsRawFd, RawFd};
@@ -7,12 +9,19 @@ use async_io::Async;
7use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState}; 9use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState};
8use log::*; 10use log::*;
9 11
12/// Get the MTU of the given interface.
10pub const SIOCGIFMTU: libc::c_ulong = 0x8921; 13pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
14/// Get the index of the given interface.
11pub const _SIOCGIFINDEX: libc::c_ulong = 0x8933; 15pub const _SIOCGIFINDEX: libc::c_ulong = 0x8933;
16/// Capture all packages.
12pub const _ETH_P_ALL: libc::c_short = 0x0003; 17pub const _ETH_P_ALL: libc::c_short = 0x0003;
18/// Set the interface flags.
13pub const TUNSETIFF: libc::c_ulong = 0x400454CA; 19pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
20/// TUN device.
14pub const _IFF_TUN: libc::c_int = 0x0001; 21pub const _IFF_TUN: libc::c_int = 0x0001;
22/// TAP device.
15pub const IFF_TAP: libc::c_int = 0x0002; 23pub const IFF_TAP: libc::c_int = 0x0002;
24/// No packet information.
16pub const IFF_NO_PI: libc::c_int = 0x1000; 25pub const IFF_NO_PI: libc::c_int = 0x1000;
17 26
18const ETHERNET_HEADER_LEN: usize = 14; 27const ETHERNET_HEADER_LEN: usize = 14;
@@ -47,6 +56,7 @@ fn ifreq_ioctl(lower: libc::c_int, ifreq: &mut ifreq, cmd: libc::c_ulong) -> io:
47 Ok(ifreq.ifr_data) 56 Ok(ifreq.ifr_data)
48} 57}
49 58
59/// A TUN/TAP device.
50#[derive(Debug)] 60#[derive(Debug)]
51pub struct TunTap { 61pub struct TunTap {
52 fd: libc::c_int, 62 fd: libc::c_int,
@@ -60,6 +70,7 @@ impl AsRawFd for TunTap {
60} 70}
61 71
62impl TunTap { 72impl TunTap {
73 /// Create a new TUN/TAP device.
63 pub fn new(name: &str) -> io::Result<TunTap> { 74 pub fn new(name: &str) -> io::Result<TunTap> {
64 unsafe { 75 unsafe {
65 let fd = libc::open( 76 let fd = libc::open(
@@ -126,11 +137,13 @@ impl io::Write for TunTap {
126 } 137 }
127} 138}
128 139
140/// A TUN/TAP device, wrapped in an async interface.
129pub struct TunTapDevice { 141pub struct TunTapDevice {
130 device: Async<TunTap>, 142 device: Async<TunTap>,
131} 143}
132 144
133impl TunTapDevice { 145impl TunTapDevice {
146 /// Create a new TUN/TAP device.
134 pub fn new(name: &str) -> io::Result<TunTapDevice> { 147 pub fn new(name: &str) -> io::Result<TunTapDevice> {
135 Ok(Self { 148 Ok(Self {
136 device: Async::new(TunTap::new(name)?)?, 149 device: Async::new(TunTap::new(name)?)?,
diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml
index 9c103ebb1..f628d8bd1 100644
--- a/embassy-net-wiznet/Cargo.toml
+++ b/embassy-net-wiznet/Cargo.toml
@@ -6,10 +6,11 @@ keywords = ["embedded", "wiznet", "embassy-net", "embedded-hal-async", "ethernet
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] 6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
7license = "MIT OR Apache-2.0" 7license = "MIT OR Apache-2.0"
8edition = "2021" 8edition = "2021"
9repository = "https://github.com/embassy-rs/embassy"
9 10
10[dependencies] 11[dependencies]
11embedded-hal = { version = "1.0.0-rc.2" } 12embedded-hal = { version = "1.0.0-rc.3" }
12embedded-hal-async = { version = "=1.0.0-rc.2" } 13embedded-hal-async = { version = "=1.0.0-rc.3" }
13embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } 14embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
14embassy-time = { version = "0.2", path = "../embassy-time" } 15embassy-time = { version = "0.2", path = "../embassy-time" }
15embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs
index 562db515a..b987c2b36 100644
--- a/embassy-net-wiznet/src/chip/mod.rs
+++ b/embassy-net-wiznet/src/chip/mod.rs
@@ -1,3 +1,4 @@
1//! Wiznet W5100s and W5500 family driver.
1mod w5500; 2mod w5500;
2pub use w5500::W5500; 3pub use w5500::W5500;
3mod w5100s; 4mod w5100s;
@@ -45,4 +46,5 @@ pub(crate) mod sealed {
45 } 46 }
46} 47}
47 48
49/// Trait for Wiznet chips.
48pub trait Chip: sealed::Chip {} 50pub trait Chip: sealed::Chip {}
diff --git a/embassy-net-wiznet/src/chip/w5100s.rs b/embassy-net-wiznet/src/chip/w5100s.rs
index 07a840370..7d328bce5 100644
--- a/embassy-net-wiznet/src/chip/w5100s.rs
+++ b/embassy-net-wiznet/src/chip/w5100s.rs
@@ -4,6 +4,7 @@ const SOCKET_BASE: u16 = 0x400;
4const TX_BASE: u16 = 0x4000; 4const TX_BASE: u16 = 0x4000;
5const RX_BASE: u16 = 0x6000; 5const RX_BASE: u16 = 0x6000;
6 6
7/// Wizard W5100S chip.
7pub enum W5100S {} 8pub enum W5100S {}
8 9
9impl super::Chip for W5100S {} 10impl super::Chip for W5100S {}
diff --git a/embassy-net-wiznet/src/chip/w5500.rs b/embassy-net-wiznet/src/chip/w5500.rs
index 61e512946..16236126d 100644
--- a/embassy-net-wiznet/src/chip/w5500.rs
+++ b/embassy-net-wiznet/src/chip/w5500.rs
@@ -8,6 +8,7 @@ pub enum RegisterBlock {
8 RxBuf = 0x03, 8 RxBuf = 0x03,
9} 9}
10 10
11/// Wiznet W5500 chip.
11pub enum W5500 {} 12pub enum W5500 {}
12 13
13impl super::Chip for W5500 {} 14impl super::Chip for W5500 {}
diff --git a/embassy-net-wiznet/src/lib.rs b/embassy-net-wiznet/src/lib.rs
index f26f2bbb7..da70d22bd 100644
--- a/embassy-net-wiznet/src/lib.rs
+++ b/embassy-net-wiznet/src/lib.rs
@@ -1,6 +1,7 @@
1#![no_std] 1#![no_std]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")] 3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
4 5
5pub mod chip; 6pub mod chip;
6mod device; 7mod device;
@@ -47,6 +48,7 @@ pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
47 48
48/// You must call this in a background task for the driver to operate. 49/// You must call this in a background task for the driver to operate.
49impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> { 50impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
51 /// Run the driver.
50 pub async fn run(mut self) -> ! { 52 pub async fn run(mut self) -> ! {
51 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); 53 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
52 let mut tick = Ticker::every(Duration::from_millis(500)); 54 let mut tick = Ticker::every(Duration::from_millis(500));
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 0c07e3651..612a3d689 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -25,18 +25,34 @@ features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethern
25default = [] 25default = []
26std = [] 26std = []
27 27
28## Enable defmt
28defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03"] 29defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03"]
29 30
31#! Many of the following feature flags are re-exports of smoltcp feature flags. See
32#! the [smoltcp feature flag documentation](https://github.com/smoltcp-rs/smoltcp#feature-flags)
33#! for more details
34
35## Enable UDP support
30udp = ["smoltcp/socket-udp"] 36udp = ["smoltcp/socket-udp"]
37## Enable TCP support
31tcp = ["smoltcp/socket-tcp"] 38tcp = ["smoltcp/socket-tcp"]
39## Enable DNS support
32dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] 40dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
41## Enable DHCPv4 support
33dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] 42dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
43## Enable DHCPv4 support with hostname
34dhcpv4-hostname = ["dhcpv4"] 44dhcpv4-hostname = ["dhcpv4"]
45## Enable IPv4 support
35proto-ipv4 = ["smoltcp/proto-ipv4"] 46proto-ipv4 = ["smoltcp/proto-ipv4"]
47## Enable IPv6 support
36proto-ipv6 = ["smoltcp/proto-ipv6"] 48proto-ipv6 = ["smoltcp/proto-ipv6"]
49## Enable the Ethernet medium
37medium-ethernet = ["smoltcp/medium-ethernet"] 50medium-ethernet = ["smoltcp/medium-ethernet"]
51## Enable the IP medium
38medium-ip = ["smoltcp/medium-ip"] 52medium-ip = ["smoltcp/medium-ip"]
53## Enable the IEEE 802.15.4 medium
39medium-ieee802154 = ["smoltcp/medium-ieee802154"] 54medium-ieee802154 = ["smoltcp/medium-ieee802154"]
55## Enable IGMP support
40igmp = ["smoltcp/proto-igmp"] 56igmp = ["smoltcp/proto-igmp"]
41 57
42[dependencies] 58[dependencies]
@@ -44,7 +60,7 @@ igmp = ["smoltcp/proto-igmp"]
44defmt = { version = "0.3", optional = true } 60defmt = { version = "0.3", optional = true }
45log = { version = "0.4.14", optional = true } 61log = { version = "0.4.14", optional = true }
46 62
47smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp.git", rev = "b57e2f9e70e82a13f31d5ea17e55232c11cc2b2d", default-features = false, features = [ 63smoltcp = { version = "0.11.0", default-features = false, features = [
48 "socket", 64 "socket",
49 "async", 65 "async",
50] } 66] }
@@ -62,3 +78,4 @@ stable_deref_trait = { version = "1.2.0", default-features = false }
62futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } 78futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
63atomic-pool = "1.0" 79atomic-pool = "1.0"
64embedded-nal-async = { version = "0.7.1" } 80embedded-nal-async = { version = "0.7.1" }
81document-features = "0.2.7"
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index bf1468642..2cef2232c 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -5,6 +5,9 @@
5#![warn(missing_docs)] 5#![warn(missing_docs)]
6#![doc = include_str!("../README.md")] 6#![doc = include_str!("../README.md")]
7 7
8//! ## Feature flags
9#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
10
8#[cfg(not(any(feature = "proto-ipv4", feature = "proto-ipv6")))] 11#[cfg(not(any(feature = "proto-ipv4", feature = "proto-ipv6")))]
9compile_error!("You must enable at least one of the following features: proto-ipv4, proto-ipv6"); 12compile_error!("You must enable at least one of the following features: proto-ipv4, proto-ipv6");
10 13
@@ -411,10 +414,12 @@ impl<D: Driver> Stack<D> {
411 /// ```ignore 414 /// ```ignore
412 /// let config = embassy_net::Config::dhcpv4(Default::default()); 415 /// let config = embassy_net::Config::dhcpv4(Default::default());
413 ///// Init network stack 416 ///// Init network stack
414 /// let stack = &*make_static!(embassy_net::Stack::new( 417 /// static RESOURCES: StaticCell<embassy_net::StackResources<2> = StaticCell::new();
418 /// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new();
419 /// let stack = &*STACK.init(embassy_net::Stack::new(
415 /// device, 420 /// device,
416 /// config, 421 /// config,
417 /// make_static!(embassy_net::StackResources::<2>::new()), 422 /// RESOURCES.init(embassy_net::StackResources::new()),
418 /// seed 423 /// seed
419 /// )); 424 /// ));
420 /// // Launch network task that runs `stack.run().await` 425 /// // Launch network task that runs `stack.run().await`
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 61058c1ba..a22cd8827 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -26,13 +26,21 @@ pub enum BindError {
26/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. 26/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`].
27#[derive(PartialEq, Eq, Clone, Copy, Debug)] 27#[derive(PartialEq, Eq, Clone, Copy, Debug)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))] 28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum Error { 29pub enum SendError {
30 /// No route to host. 30 /// No route to host.
31 NoRoute, 31 NoRoute,
32 /// Socket not bound to an outgoing port. 32 /// Socket not bound to an outgoing port.
33 SocketNotBound, 33 SocketNotBound,
34} 34}
35 35
36/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`].
37#[derive(PartialEq, Eq, Clone, Copy, Debug)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39pub enum RecvError {
40 /// Provided buffer was smaller than the received packet.
41 Truncated,
42}
43
36/// An UDP socket. 44/// An UDP socket.
37pub struct UdpSocket<'a> { 45pub struct UdpSocket<'a> {
38 stack: &'a RefCell<SocketStack>, 46 stack: &'a RefCell<SocketStack>,
@@ -103,7 +111,7 @@ impl<'a> UdpSocket<'a> {
103 /// This method will wait until a datagram is received. 111 /// This method will wait until a datagram is received.
104 /// 112 ///
105 /// Returns the number of bytes received and the remote endpoint. 113 /// Returns the number of bytes received and the remote endpoint.
106 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> { 114 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), RecvError> {
107 poll_fn(move |cx| self.poll_recv_from(buf, cx)).await 115 poll_fn(move |cx| self.poll_recv_from(buf, cx)).await
108 } 116 }
109 117
@@ -114,10 +122,11 @@ impl<'a> UdpSocket<'a> {
114 /// 122 ///
115 /// When a datagram is received, this method will return `Poll::Ready` with the 123 /// When a datagram is received, this method will return `Poll::Ready` with the
116 /// number of bytes received and the remote endpoint. 124 /// number of bytes received and the remote endpoint.
117 pub fn poll_recv_from(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<(usize, IpEndpoint), Error>> { 125 pub fn poll_recv_from(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<(usize, IpEndpoint), RecvError>> {
118 self.with_mut(|s, _| match s.recv_slice(buf) { 126 self.with_mut(|s, _| match s.recv_slice(buf) {
119 Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))), 127 Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))),
120 // No data ready 128 // No data ready
129 Err(udp::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)),
121 Err(udp::RecvError::Exhausted) => { 130 Err(udp::RecvError::Exhausted) => {
122 s.register_recv_waker(cx.waker()); 131 s.register_recv_waker(cx.waker());
123 Poll::Pending 132 Poll::Pending
@@ -129,8 +138,8 @@ impl<'a> UdpSocket<'a> {
129 /// 138 ///
130 /// This method will wait until the datagram has been sent. 139 /// This method will wait until the datagram has been sent.
131 /// 140 ///
132 /// When the remote endpoint is not reachable, this method will return `Err(Error::NoRoute)` 141 /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)`
133 pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), Error> 142 pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError>
134 where 143 where
135 T: Into<IpEndpoint>, 144 T: Into<IpEndpoint>,
136 { 145 {
@@ -146,7 +155,7 @@ impl<'a> UdpSocket<'a> {
146 /// and register the current task to be notified when the buffer has space available. 155 /// and register the current task to be notified when the buffer has space available.
147 /// 156 ///
148 /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`. 157 /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`.
149 pub fn poll_send_to<T>(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll<Result<(), Error>> 158 pub fn poll_send_to<T>(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll<Result<(), SendError>>
150 where 159 where
151 T: Into<IpEndpoint>, 160 T: Into<IpEndpoint>,
152 { 161 {
@@ -160,9 +169,9 @@ impl<'a> UdpSocket<'a> {
160 Err(udp::SendError::Unaddressable) => { 169 Err(udp::SendError::Unaddressable) => {
161 // If no sender/outgoing port is specified, there is not really "no route" 170 // If no sender/outgoing port is specified, there is not really "no route"
162 if s.endpoint().port == 0 { 171 if s.endpoint().port == 0 {
163 Poll::Ready(Err(Error::SocketNotBound)) 172 Poll::Ready(Err(SendError::SocketNotBound))
164 } else { 173 } else {
165 Poll::Ready(Err(Error::NoRoute)) 174 Poll::Ready(Err(SendError::NoRoute))
166 } 175 }
167 } 176 }
168 }) 177 })
@@ -213,6 +222,11 @@ impl<'a> UdpSocket<'a> {
213 pub fn payload_send_capacity(&self) -> usize { 222 pub fn payload_send_capacity(&self) -> usize {
214 self.with(|s, _| s.payload_send_capacity()) 223 self.with(|s, _| s.payload_send_capacity())
215 } 224 }
225
226 /// Set the hop limit field in the IP header of sent packets.
227 pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) {
228 self.with_mut(|s, _| s.set_hop_limit(hop_limit))
229 }
216} 230}
217 231
218impl Drop for UdpSocket<'_> { 232impl Drop for UdpSocket<'_> {
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index a7f3cb35d..837a941a9 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -17,6 +17,7 @@ flavors = [
17 17
18[features] 18[features]
19default = ["rt"] 19default = ["rt"]
20## Cortex-M runtime (enabled by default)
20rt = [ 21rt = [
21 "nrf52805-pac?/rt", 22 "nrf52805-pac?/rt",
22 "nrf52810-pac?/rt", 23 "nrf52810-pac?/rt",
@@ -30,40 +31,62 @@ rt = [
30 "nrf9160-pac?/rt", 31 "nrf9160-pac?/rt",
31] 32]
32 33
34## Enable features requiring `embassy-time`
33time = ["dep:embassy-time"] 35time = ["dep:embassy-time"]
34 36
37## Enable defmt
35defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"] 38defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"]
36 39
37# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. 40## Reexport the PAC for the currently enabled chip at `embassy_nrf::pac` (unstable)
41unstable-pac = []
38# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. 42# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version.
39# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. 43# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
40# There are no plans to make this stable. 44# There are no plans to make this stable.
41unstable-pac = []
42 45
46## Enable GPIO tasks and events
47gpiote = []
48
49## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz
50time-driver-rtc1 = ["_time-driver"]
51
52## Allow using the NFC pins as regular GPIO pins (P0_09/P0_10 on nRF52, P0_02/P0_03 on nRF53)
53nfc-pins-as-gpio = []
54
55## Allow using the RST pin as a regular GPIO pin.
56## * nRF52805, nRF52810, nRF52811, nRF52832: P0_21
57## * nRF52820, nRF52833, nRF52840: P0_18
58reset-pin-as-gpio = []
59
60## Implements the MultiwriteNorFlash trait for QSPI. Should only be enabled if your external
61## flash supports the semantics described [here](https://docs.rs/embedded-storage/0.3.1/embedded_storage/nor_flash/trait.MultiwriteNorFlash.html)
62qspi-multiwrite-flash = []
63
64#! ### Chip selection features
65## nRF52805
43nrf52805 = ["nrf52805-pac", "_nrf52"] 66nrf52805 = ["nrf52805-pac", "_nrf52"]
67## nRF52810
44nrf52810 = ["nrf52810-pac", "_nrf52"] 68nrf52810 = ["nrf52810-pac", "_nrf52"]
69## nRF52811
45nrf52811 = ["nrf52811-pac", "_nrf52"] 70nrf52811 = ["nrf52811-pac", "_nrf52"]
71## nRF52820
46nrf52820 = ["nrf52820-pac", "_nrf52"] 72nrf52820 = ["nrf52820-pac", "_nrf52"]
73## nRF52832
47nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] 74nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"]
75## nRF52833
48nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] 76nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"]
77## nRF52840
49nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] 78nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"]
79## nRF5340 application core in Secure mode
50nrf5340-app-s = ["_nrf5340-app", "_s"] 80nrf5340-app-s = ["_nrf5340-app", "_s"]
81## nRF5340 application core in Non-Secure mode
51nrf5340-app-ns = ["_nrf5340-app", "_ns"] 82nrf5340-app-ns = ["_nrf5340-app", "_ns"]
83## nRF5340 network core
52nrf5340-net = ["_nrf5340-net"] 84nrf5340-net = ["_nrf5340-net"]
85## nRF9160 in Secure mode
53nrf9160-s = ["_nrf9160", "_s"] 86nrf9160-s = ["_nrf9160", "_s"]
87## nRF9160 in Non-Secure mode
54nrf9160-ns = ["_nrf9160", "_ns"] 88nrf9160-ns = ["_nrf9160", "_ns"]
55 89
56gpiote = []
57time-driver-rtc1 = ["_time-driver"]
58
59# Allow using the NFC pins as regular GPIO pins (P0_09/P0_10 on nRF52, P0_02/P0_03 on nRF53)
60nfc-pins-as-gpio = []
61
62# Allow using the RST pin as a regular GPIO pin.
63# nrf52805, nrf52810, nrf52811, nrf52832: P0_21
64# nrf52820, nrf52833, nrf52840: P0_18
65reset-pin-as-gpio = []
66
67# Features starting with `_` are for internal use only. They're not intended 90# Features starting with `_` are for internal use only. They're not intended
68# to be enabled by other crates, and are not covered by semver guarantees. 91# to be enabled by other crates, and are not covered by semver guarantees.
69 92
@@ -94,8 +117,8 @@ embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
94embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } 117embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
95 118
96embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 119embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
97embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 120embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
98embedded-hal-async = { version = "=1.0.0-rc.2" } 121embedded-hal-async = { version = "=1.0.0-rc.3" }
99embedded-io = { version = "0.6.0" } 122embedded-io = { version = "0.6.0" }
100embedded-io-async = { version = "0.6.1" } 123embedded-io-async = { version = "0.6.1" }
101 124
@@ -109,6 +132,7 @@ fixed = "1.10.0"
109embedded-storage = "0.3.1" 132embedded-storage = "0.3.1"
110embedded-storage-async = "0.4.0" 133embedded-storage-async = "0.4.0"
111cfg-if = "1.0.0" 134cfg-if = "1.0.0"
135document-features = "0.2.7"
112 136
113nrf52805-pac = { version = "0.12.0", optional = true } 137nrf52805-pac = { version = "0.12.0", optional = true }
114nrf52810-pac = { version = "0.12.0", optional = true } 138nrf52810-pac = { version = "0.12.0", optional = true }
@@ -120,4 +144,3 @@ nrf52840-pac = { version = "0.12.0", optional = true }
120nrf5340-app-pac = { version = "0.12.0", optional = true } 144nrf5340-app-pac = { version = "0.12.0", optional = true }
121nrf5340-net-pac = { version = "0.12.0", optional = true } 145nrf5340-net-pac = { version = "0.12.0", optional = true }
122nrf9160-pac = { version = "0.12.0", optional = true } 146nrf9160-pac = { version = "0.12.0", optional = true }
123
diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md
index 129ec0c01..39de3854b 100644
--- a/embassy-nrf/README.md
+++ b/embassy-nrf/README.md
@@ -6,6 +6,8 @@ The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The
6for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to 6for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to
7complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. 7complete operations in low power mod and handling interrupts, so that applications can focus on more important matters.
8 8
9NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use.
10
9## EasyDMA considerations 11## EasyDMA considerations
10 12
11On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting 13On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 4ac622d34..2c620798d 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -342,6 +342,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
342 s.tx_count.store(0, Ordering::Relaxed); 342 s.tx_count.store(0, Ordering::Relaxed);
343 s.rx_started_count.store(0, Ordering::Relaxed); 343 s.rx_started_count.store(0, Ordering::Relaxed);
344 s.rx_ended_count.store(0, Ordering::Relaxed); 344 s.rx_ended_count.store(0, Ordering::Relaxed);
345 s.rx_started.store(false, Ordering::Relaxed);
345 let len = tx_buffer.len(); 346 let len = tx_buffer.len();
346 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 347 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
347 let len = rx_buffer.len(); 348 let len = rx_buffer.len();
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index cf6225282..27c18383f 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -50,21 +50,21 @@ impl<'d, T: Pin> Input<'d, T> {
50 Self { pin } 50 Self { pin }
51 } 51 }
52 52
53 /// Test if current pin level is high. 53 /// Get whether the pin input level is high.
54 #[inline] 54 #[inline]
55 pub fn is_high(&self) -> bool { 55 pub fn is_high(&mut self) -> bool {
56 self.pin.is_high() 56 self.pin.is_high()
57 } 57 }
58 58
59 /// Test if current pin level is low. 59 /// Get whether the pin input level is low.
60 #[inline] 60 #[inline]
61 pub fn is_low(&self) -> bool { 61 pub fn is_low(&mut self) -> bool {
62 self.pin.is_low() 62 self.pin.is_low()
63 } 63 }
64 64
65 /// Returns current pin level 65 /// Get the pin input level.
66 #[inline] 66 #[inline]
67 pub fn get_level(&self) -> Level { 67 pub fn get_level(&mut self) -> Level {
68 self.pin.get_level() 68 self.pin.get_level()
69 } 69 }
70} 70}
@@ -152,27 +152,33 @@ impl<'d, T: Pin> Output<'d, T> {
152 self.pin.set_low() 152 self.pin.set_low()
153 } 153 }
154 154
155 /// Toggle the output level.
156 #[inline]
157 pub fn toggle(&mut self) {
158 self.pin.toggle()
159 }
160
155 /// Set the output level. 161 /// Set the output level.
156 #[inline] 162 #[inline]
157 pub fn set_level(&mut self, level: Level) { 163 pub fn set_level(&mut self, level: Level) {
158 self.pin.set_level(level) 164 self.pin.set_level(level)
159 } 165 }
160 166
161 /// Is the output pin set as high? 167 /// Get whether the output level is set to high.
162 #[inline] 168 #[inline]
163 pub fn is_set_high(&self) -> bool { 169 pub fn is_set_high(&mut self) -> bool {
164 self.pin.is_set_high() 170 self.pin.is_set_high()
165 } 171 }
166 172
167 /// Is the output pin set as low? 173 /// Get whether the output level is set to low.
168 #[inline] 174 #[inline]
169 pub fn is_set_low(&self) -> bool { 175 pub fn is_set_low(&mut self) -> bool {
170 self.pin.is_set_low() 176 self.pin.is_set_low()
171 } 177 }
172 178
173 /// What level output is set to 179 /// Get the current output level.
174 #[inline] 180 #[inline]
175 pub fn get_output_level(&self) -> Level { 181 pub fn get_output_level(&mut self) -> Level {
176 self.pin.get_output_level() 182 self.pin.get_output_level()
177 } 183 }
178} 184}
@@ -275,21 +281,26 @@ impl<'d, T: Pin> Flex<'d, T> {
275 self.pin.conf().reset(); 281 self.pin.conf().reset();
276 } 282 }
277 283
278 /// Test if current pin level is high. 284 /// Get whether the pin input level is high.
279 #[inline] 285 #[inline]
280 pub fn is_high(&self) -> bool { 286 pub fn is_high(&mut self) -> bool {
281 !self.is_low() 287 !self.is_low()
282 } 288 }
283 289
284 /// Test if current pin level is low. 290 /// Get whether the pin input level is low.
291 #[inline]
292 pub fn is_low(&mut self) -> bool {
293 self.ref_is_low()
294 }
295
285 #[inline] 296 #[inline]
286 pub fn is_low(&self) -> bool { 297 pub(crate) fn ref_is_low(&self) -> bool {
287 self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 298 self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0
288 } 299 }
289 300
290 /// Returns current pin level 301 /// Get the pin input level.
291 #[inline] 302 #[inline]
292 pub fn get_level(&self) -> Level { 303 pub fn get_level(&mut self) -> Level {
293 self.is_high().into() 304 self.is_high().into()
294 } 305 }
295 306
@@ -305,6 +316,16 @@ impl<'d, T: Pin> Flex<'d, T> {
305 self.pin.set_low() 316 self.pin.set_low()
306 } 317 }
307 318
319 /// Toggle the output level.
320 #[inline]
321 pub fn toggle(&mut self) {
322 if self.is_set_low() {
323 self.set_high()
324 } else {
325 self.set_low()
326 }
327 }
328
308 /// Set the output level. 329 /// Set the output level.
309 #[inline] 330 #[inline]
310 pub fn set_level(&mut self, level: Level) { 331 pub fn set_level(&mut self, level: Level) {
@@ -314,21 +335,26 @@ impl<'d, T: Pin> Flex<'d, T> {
314 } 335 }
315 } 336 }
316 337
317 /// Is the output pin set as high? 338 /// Get whether the output level is set to high.
318 #[inline] 339 #[inline]
319 pub fn is_set_high(&self) -> bool { 340 pub fn is_set_high(&mut self) -> bool {
320 !self.is_set_low() 341 !self.is_set_low()
321 } 342 }
322 343
323 /// Is the output pin set as low? 344 /// Get whether the output level is set to low.
324 #[inline] 345 #[inline]
325 pub fn is_set_low(&self) -> bool { 346 pub fn is_set_low(&mut self) -> bool {
347 self.ref_is_set_low()
348 }
349
350 #[inline]
351 pub(crate) fn ref_is_set_low(&self) -> bool {
326 self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 352 self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0
327 } 353 }
328 354
329 /// What level output is set to 355 /// Get the current output level.
330 #[inline] 356 #[inline]
331 pub fn get_output_level(&self) -> Level { 357 pub fn get_output_level(&mut self) -> Level {
332 self.is_set_high().into() 358 self.is_set_high().into()
333 } 359 }
334} 360}
@@ -498,11 +524,11 @@ mod eh02 {
498 type Error = Infallible; 524 type Error = Infallible;
499 525
500 fn is_high(&self) -> Result<bool, Self::Error> { 526 fn is_high(&self) -> Result<bool, Self::Error> {
501 Ok(self.is_high()) 527 Ok(!self.pin.ref_is_low())
502 } 528 }
503 529
504 fn is_low(&self) -> Result<bool, Self::Error> { 530 fn is_low(&self) -> Result<bool, Self::Error> {
505 Ok(self.is_low()) 531 Ok(self.pin.ref_is_low())
506 } 532 }
507 } 533 }
508 534
@@ -520,11 +546,20 @@ mod eh02 {
520 546
521 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { 547 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> {
522 fn is_set_high(&self) -> Result<bool, Self::Error> { 548 fn is_set_high(&self) -> Result<bool, Self::Error> {
523 Ok(self.is_set_high()) 549 Ok(!self.pin.ref_is_set_low())
524 } 550 }
525 551
526 fn is_set_low(&self) -> Result<bool, Self::Error> { 552 fn is_set_low(&self) -> Result<bool, Self::Error> {
527 Ok(self.is_set_low()) 553 Ok(self.pin.ref_is_set_low())
554 }
555 }
556
557 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> {
558 type Error = Infallible;
559 #[inline]
560 fn toggle(&mut self) -> Result<(), Self::Error> {
561 self.toggle();
562 Ok(())
528 } 563 }
529 } 564 }
530 565
@@ -535,11 +570,11 @@ mod eh02 {
535 type Error = Infallible; 570 type Error = Infallible;
536 571
537 fn is_high(&self) -> Result<bool, Self::Error> { 572 fn is_high(&self) -> Result<bool, Self::Error> {
538 Ok(self.is_high()) 573 Ok(!self.ref_is_low())
539 } 574 }
540 575
541 fn is_low(&self) -> Result<bool, Self::Error> { 576 fn is_low(&self) -> Result<bool, Self::Error> {
542 Ok(self.is_low()) 577 Ok(self.ref_is_low())
543 } 578 }
544 } 579 }
545 580
@@ -557,11 +592,20 @@ mod eh02 {
557 592
558 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { 593 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> {
559 fn is_set_high(&self) -> Result<bool, Self::Error> { 594 fn is_set_high(&self) -> Result<bool, Self::Error> {
560 Ok(self.is_set_high()) 595 Ok(!self.ref_is_set_low())
561 } 596 }
562 597
563 fn is_set_low(&self) -> Result<bool, Self::Error> { 598 fn is_set_low(&self) -> Result<bool, Self::Error> {
564 Ok(self.is_set_low()) 599 Ok(self.ref_is_set_low())
600 }
601 }
602
603 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> {
604 type Error = Infallible;
605 #[inline]
606 fn toggle(&mut self) -> Result<(), Self::Error> {
607 self.toggle();
608 Ok(())
565 } 609 }
566 } 610 }
567} 611}
@@ -571,11 +615,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
571} 615}
572 616
573impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { 617impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
574 fn is_high(&self) -> Result<bool, Self::Error> { 618 fn is_high(&mut self) -> Result<bool, Self::Error> {
575 Ok(self.is_high()) 619 Ok(self.is_high())
576 } 620 }
577 621
578 fn is_low(&self) -> Result<bool, Self::Error> { 622 fn is_low(&mut self) -> Result<bool, Self::Error> {
579 Ok(self.is_low()) 623 Ok(self.is_low())
580 } 624 }
581} 625}
@@ -595,11 +639,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
595} 639}
596 640
597impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { 641impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
598 fn is_set_high(&self) -> Result<bool, Self::Error> { 642 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
599 Ok(self.is_set_high()) 643 Ok(self.is_set_high())
600 } 644 }
601 645
602 fn is_set_low(&self) -> Result<bool, Self::Error> { 646 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
603 Ok(self.is_set_low()) 647 Ok(self.is_set_low())
604 } 648 }
605} 649}
@@ -612,11 +656,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
612/// 656///
613/// If the pin is not in input mode the result is unspecified. 657/// If the pin is not in input mode the result is unspecified.
614impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { 658impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
615 fn is_high(&self) -> Result<bool, Self::Error> { 659 fn is_high(&mut self) -> Result<bool, Self::Error> {
616 Ok(self.is_high()) 660 Ok(self.is_high())
617 } 661 }
618 662
619 fn is_low(&self) -> Result<bool, Self::Error> { 663 fn is_low(&mut self) -> Result<bool, Self::Error> {
620 Ok(self.is_low()) 664 Ok(self.is_low())
621 } 665 }
622} 666}
@@ -632,11 +676,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
632} 676}
633 677
634impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { 678impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
635 fn is_set_high(&self) -> Result<bool, Self::Error> { 679 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
636 Ok(self.is_set_high()) 680 Ok(self.is_set_high())
637 } 681 }
638 682
639 fn is_set_low(&self) -> Result<bool, Self::Error> { 683 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
640 Ok(self.is_set_low()) 684 Ok(self.is_set_low())
641 } 685 }
642} 686}
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index fd629ea76..07196abf7 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -243,7 +243,7 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> {
243 243
244impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { 244impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
245 /// Create a new GPIOTE output channel driver. 245 /// Create a new GPIOTE output channel driver.
246 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { 246 pub fn new(ch: impl Peripheral<P = C> + 'd, mut pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self {
247 into_ref!(ch); 247 into_ref!(ch);
248 let g = regs(); 248 let g = regs();
249 let num = ch.number(); 249 let num = ch.number();
@@ -481,11 +481,11 @@ mod eh02 {
481 type Error = Infallible; 481 type Error = Infallible;
482 482
483 fn is_high(&self) -> Result<bool, Self::Error> { 483 fn is_high(&self) -> Result<bool, Self::Error> {
484 Ok(self.pin.is_high()) 484 Ok(!self.pin.pin.ref_is_low())
485 } 485 }
486 486
487 fn is_low(&self) -> Result<bool, Self::Error> { 487 fn is_low(&self) -> Result<bool, Self::Error> {
488 Ok(self.pin.is_low()) 488 Ok(self.pin.pin.ref_is_low())
489 } 489 }
490 } 490 }
491} 491}
@@ -495,11 +495,11 @@ impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputCha
495} 495}
496 496
497impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> { 497impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> {
498 fn is_high(&self) -> Result<bool, Self::Error> { 498 fn is_high(&mut self) -> Result<bool, Self::Error> {
499 Ok(self.pin.is_high()) 499 Ok(self.pin.is_high())
500 } 500 }
501 501
502 fn is_low(&self) -> Result<bool, Self::Error> { 502 fn is_low(&mut self) -> Result<bool, Self::Error> {
503 Ok(self.pin.is_low()) 503 Ok(self.pin.is_low())
504 } 504 }
505} 505}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 9093ad919..1510b7265 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -3,6 +3,9 @@
3#![doc = include_str!("../README.md")] 3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)] 4#![warn(missing_docs)]
5 5
6//! ## Feature flags
7#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
8
6#[cfg(not(any( 9#[cfg(not(any(
7 feature = "nrf51", 10 feature = "nrf51",
8 feature = "nrf52805", 11 feature = "nrf52805",
@@ -354,7 +357,11 @@ unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteRe
354 WriteResult::Written 357 WriteResult::Written
355} 358}
356 359
357/// Initialize peripherals with the provided configuration. This should only be called once at startup. 360/// Initialize the `embassy-nrf` HAL with the provided configuration.
361///
362/// This returns the peripheral singletons that can be used for creating drivers.
363///
364/// This should only be called once at startup, otherwise it panics.
358pub fn init(config: config::Config) -> Peripherals { 365pub fn init(config: config::Config) -> Peripherals {
359 // Do this first, so that it panics if user is calling `init` a second time 366 // Do this first, so that it panics if user is calling `init` a second time
360 // before doing anything important. 367 // before doing anything important.
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 5e1a4e842..f35b83628 100755
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -605,6 +605,9 @@ impl<'d, T: Instance> NorFlash for Qspi<'d, T> {
605 } 605 }
606} 606}
607 607
608#[cfg(feature = "qspi-multiwrite-flash")]
609impl<'d, T: Instance> embedded_storage::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {}
610
608mod _eh1 { 611mod _eh1 {
609 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; 612 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
610 613
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index dfdd1fee9..669d79f40 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -14,43 +14,57 @@ flavors = [
14 14
15[features] 15[features]
16default = [ "rt" ] 16default = [ "rt" ]
17## Enable the RP runtime.
17rt = [ "rp-pac/rt" ] 18rt = [ "rp-pac/rt" ]
18 19
20## Enable defmt
19defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] 21defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"]
20 22
21# critical section that is safe for multicore use 23## critical section that is safe for multicore use
22critical-section-impl = ["critical-section/restore-state-u8"] 24critical-section-impl = ["critical-section/restore-state-u8"]
23 25
24# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. 26## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`.
25# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. 27## This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version.
26# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. 28## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
27# There are no plans to make this stable. 29## There are no plans to make this stable.
28unstable-pac = [] 30unstable-pac = []
29 31
32## Enable the timer for use with `embassy-time` with a 1MHz tick rate
30time-driver = [] 33time-driver = []
31 34
35## Enable ROM function cache
32rom-func-cache = [] 36rom-func-cache = []
37## Enable intrinsics
33intrinsics = [] 38intrinsics = []
39## Enable ROM v2 intrinsics
34rom-v2-intrinsics = [] 40rom-v2-intrinsics = []
35 41
36# boot2 flash chip support. if none of these is enabled we'll default to w25q080 (used on the pico) 42## Allow using QSPI pins as GPIO pins. This is mostly not what you want (because your flash lives there)
43## and would add both code and memory overhead when enabled needlessly.
44qspi-as-gpio = []
45
46## Indicate code is running from RAM.
47## Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP.
48## This allows the flash driver to not force pausing execution on both cores when doing flash operations.
49run-from-ram = []
50
51#! ### boot2 flash chip support
52#! If none of these are enabled, w25q080 is used by default (used on the pico)
53## AT25SF128a
37boot2-at25sf128a = [] 54boot2-at25sf128a = []
55## GD25Q64cs
38boot2-gd25q64cs = [] 56boot2-gd25q64cs = []
57## generic-03h
39boot2-generic-03h = [] 58boot2-generic-03h = []
59## IS25LP080
40boot2-is25lp080 = [] 60boot2-is25lp080 = []
61## ram-memcpy
41boot2-ram-memcpy = [] 62boot2-ram-memcpy = []
63## W25Q080
42boot2-w25q080 = [] 64boot2-w25q080 = []
65## W25X10cl
43boot2-w25x10cl = [] 66boot2-w25x10cl = []
44 67
45# Allow using QSPI pins as GPIO pins. This is mostly not what you want (because your flash lives there)
46# and would add both code and memory overhead when enabled needlessly.
47qspi-as-gpio = []
48
49# Indicate code is running from RAM.
50# Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP.
51# This allows the flash driver to not force pausing execution on both cores when doing flash operations.
52run-from-ram = []
53
54[dependencies] 68[dependencies]
55embassy-sync = { version = "0.5.0", path = "../embassy-sync" } 69embassy-sync = { version = "0.5.0", path = "../embassy-sync" }
56embassy-time = { version = "0.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } 70embassy-time = { version = "0.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
@@ -78,14 +92,15 @@ fixed = "1.23.1"
78rp-pac = { version = "6" } 92rp-pac = { version = "6" }
79 93
80embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 94embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
81embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 95embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
82embedded-hal-async = { version = "=1.0.0-rc.2" } 96embedded-hal-async = { version = "=1.0.0-rc.3" }
83embedded-hal-nb = { version = "=1.0.0-rc.2" } 97embedded-hal-nb = { version = "=1.0.0-rc.3" }
84 98
85pio-proc = {version= "0.2" } 99pio-proc = {version= "0.2" }
86pio = {version= "0.2.1" } 100pio = {version= "0.2.1" }
87rp2040-boot2 = "0.3" 101rp2040-boot2 = "0.3"
102document-features = "0.2.7"
88 103
89[dev-dependencies] 104[dev-dependencies]
90embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] } 105embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
91static_cell = { version = "2" } 106static_cell = { version = "2" }
diff --git a/embassy-rp/README.md b/embassy-rp/README.md
new file mode 100644
index 000000000..cd79fe501
--- /dev/null
+++ b/embassy-rp/README.md
@@ -0,0 +1,23 @@
1# Embassy RP HAL
2
3HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed.
4
5The Embassy RP HAL targets the Raspberry Pi 2040 family of hardware. The HAL implements both blocking and async APIs
6for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to
7complete operations in low power mod and handling interrupts, so that applications can focus on more important matters.
8
9NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use.
10
11## Minimum supported Rust version (MSRV)
12
13Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
14
15## License
16
17This work is licensed under either of
18
19- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
20 <http://www.apache.org/licenses/LICENSE-2.0>)
21- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
22
23at your option.
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 5b913f156..21360bf66 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -1,3 +1,4 @@
1//! ADC driver.
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::mem; 4use core::mem;
@@ -16,6 +17,7 @@ use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt};
16 17
17static WAKER: AtomicWaker = AtomicWaker::new(); 18static WAKER: AtomicWaker = AtomicWaker::new();
18 19
20/// ADC config.
19#[non_exhaustive] 21#[non_exhaustive]
20pub struct Config {} 22pub struct Config {}
21 23
@@ -30,9 +32,11 @@ enum Source<'p> {
30 TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), 32 TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>),
31} 33}
32 34
35/// ADC channel.
33pub struct Channel<'p>(Source<'p>); 36pub struct Channel<'p>(Source<'p>);
34 37
35impl<'p> Channel<'p> { 38impl<'p> Channel<'p> {
39 /// Create a new ADC channel from pin with the provided [Pull] configuration.
36 pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self { 40 pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self {
37 into_ref!(pin); 41 into_ref!(pin);
38 pin.pad_ctrl().modify(|w| { 42 pin.pad_ctrl().modify(|w| {
@@ -49,6 +53,7 @@ impl<'p> Channel<'p> {
49 Self(Source::Pin(pin.map_into())) 53 Self(Source::Pin(pin.map_into()))
50 } 54 }
51 55
56 /// Create a new ADC channel for the internal temperature sensor.
52 pub fn new_temp_sensor(s: impl Peripheral<P = ADC_TEMP_SENSOR> + 'p) -> Self { 57 pub fn new_temp_sensor(s: impl Peripheral<P = ADC_TEMP_SENSOR> + 'p) -> Self {
53 let r = pac::ADC; 58 let r = pac::ADC;
54 r.cs().write_set(|w| w.set_ts_en(true)); 59 r.cs().write_set(|w| w.set_ts_en(true));
@@ -83,35 +88,44 @@ impl<'p> Drop for Source<'p> {
83 } 88 }
84} 89}
85 90
91/// ADC sample.
86#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] 92#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))] 93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88#[repr(transparent)] 94#[repr(transparent)]
89pub struct Sample(u16); 95pub struct Sample(u16);
90 96
91impl Sample { 97impl Sample {
98 /// Sample is valid.
92 pub fn good(&self) -> bool { 99 pub fn good(&self) -> bool {
93 self.0 < 0x8000 100 self.0 < 0x8000
94 } 101 }
95 102
103 /// Sample value.
96 pub fn value(&self) -> u16 { 104 pub fn value(&self) -> u16 {
97 self.0 & !0x8000 105 self.0 & !0x8000
98 } 106 }
99} 107}
100 108
109/// ADC error.
101#[derive(Debug, Eq, PartialEq, Copy, Clone)] 110#[derive(Debug, Eq, PartialEq, Copy, Clone)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))] 111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103pub enum Error { 112pub enum Error {
113 /// Error converting value.
104 ConversionFailed, 114 ConversionFailed,
105} 115}
106 116
117/// ADC mode.
107pub trait Mode {} 118pub trait Mode {}
108 119
120/// ADC async mode.
109pub struct Async; 121pub struct Async;
110impl Mode for Async {} 122impl Mode for Async {}
111 123
124/// ADC blocking mode.
112pub struct Blocking; 125pub struct Blocking;
113impl Mode for Blocking {} 126impl Mode for Blocking {}
114 127
128/// ADC driver.
115pub struct Adc<'d, M: Mode> { 129pub struct Adc<'d, M: Mode> {
116 phantom: PhantomData<(&'d ADC, M)>, 130 phantom: PhantomData<(&'d ADC, M)>,
117} 131}
@@ -150,6 +164,7 @@ impl<'d, M: Mode> Adc<'d, M> {
150 while !r.cs().read().ready() {} 164 while !r.cs().read().ready() {}
151 } 165 }
152 166
167 /// Sample a value from a channel in blocking mode.
153 pub fn blocking_read(&mut self, ch: &mut Channel) -> Result<u16, Error> { 168 pub fn blocking_read(&mut self, ch: &mut Channel) -> Result<u16, Error> {
154 let r = Self::regs(); 169 let r = Self::regs();
155 r.cs().modify(|w| { 170 r.cs().modify(|w| {
@@ -166,6 +181,7 @@ impl<'d, M: Mode> Adc<'d, M> {
166} 181}
167 182
168impl<'d> Adc<'d, Async> { 183impl<'d> Adc<'d, Async> {
184 /// Create ADC driver in async mode.
169 pub fn new( 185 pub fn new(
170 _inner: impl Peripheral<P = ADC> + 'd, 186 _inner: impl Peripheral<P = ADC> + 'd,
171 _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, 187 _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
@@ -194,6 +210,7 @@ impl<'d> Adc<'d, Async> {
194 .await; 210 .await;
195 } 211 }
196 212
213 /// Sample a value from a channel until completed.
197 pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result<u16, Error> { 214 pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result<u16, Error> {
198 let r = Self::regs(); 215 let r = Self::regs();
199 r.cs().modify(|w| { 216 r.cs().modify(|w| {
@@ -272,6 +289,7 @@ impl<'d> Adc<'d, Async> {
272 } 289 }
273 } 290 }
274 291
292 /// Sample multiple values from a channel using DMA.
275 #[inline] 293 #[inline]
276 pub async fn read_many<S: AdcSample>( 294 pub async fn read_many<S: AdcSample>(
277 &mut self, 295 &mut self,
@@ -283,6 +301,7 @@ impl<'d> Adc<'d, Async> {
283 self.read_many_inner(ch, buf, false, div, dma).await 301 self.read_many_inner(ch, buf, false, div, dma).await
284 } 302 }
285 303
304 /// Sample multiple values from a channel using DMA with errors inlined in samples.
286 #[inline] 305 #[inline]
287 pub async fn read_many_raw( 306 pub async fn read_many_raw(
288 &mut self, 307 &mut self,
@@ -299,6 +318,7 @@ impl<'d> Adc<'d, Async> {
299} 318}
300 319
301impl<'d> Adc<'d, Blocking> { 320impl<'d> Adc<'d, Blocking> {
321 /// Create ADC driver in blocking mode.
302 pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self { 322 pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self {
303 Self::setup(); 323 Self::setup();
304 324
@@ -306,6 +326,7 @@ impl<'d> Adc<'d, Blocking> {
306 } 326 }
307} 327}
308 328
329/// Interrupt handler.
309pub struct InterruptHandler { 330pub struct InterruptHandler {
310 _empty: (), 331 _empty: (),
311} 332}
@@ -324,6 +345,7 @@ mod sealed {
324 pub trait AdcChannel {} 345 pub trait AdcChannel {}
325} 346}
326 347
348/// ADC sample.
327pub trait AdcSample: sealed::AdcSample {} 349pub trait AdcSample: sealed::AdcSample {}
328 350
329impl sealed::AdcSample for u16 {} 351impl sealed::AdcSample for u16 {}
@@ -332,7 +354,9 @@ impl AdcSample for u16 {}
332impl sealed::AdcSample for u8 {} 354impl sealed::AdcSample for u8 {}
333impl AdcSample for u8 {} 355impl AdcSample for u8 {}
334 356
357/// ADC channel.
335pub trait AdcChannel: sealed::AdcChannel {} 358pub trait AdcChannel: sealed::AdcChannel {}
359/// ADC pin.
336pub trait AdcPin: AdcChannel + gpio::Pin {} 360pub trait AdcPin: AdcChannel + gpio::Pin {}
337 361
338macro_rules! impl_pin { 362macro_rules! impl_pin {
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 220665462..19232b801 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,3 +1,4 @@
1//! Clock configuration for the RP2040
1use core::arch::asm; 2use core::arch::asm;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; 4use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
@@ -44,34 +45,50 @@ static CLOCKS: Clocks = Clocks {
44 rtc: AtomicU16::new(0), 45 rtc: AtomicU16::new(0),
45}; 46};
46 47
48/// Peripheral clock sources.
47#[repr(u8)] 49#[repr(u8)]
48#[non_exhaustive] 50#[non_exhaustive]
49#[derive(Clone, Copy, Debug, PartialEq, Eq)] 51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum PeriClkSrc { 52pub enum PeriClkSrc {
53 /// SYS.
51 Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _, 54 Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _,
55 /// PLL SYS.
52 PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _, 56 PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _,
57 /// PLL USB.
53 PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _, 58 PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _,
59 /// ROSC.
54 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, 60 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _,
61 /// XOSC.
55 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, 62 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _,
56 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , 63 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
57 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 64 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
58} 65}
59 66
67/// CLock configuration.
60#[non_exhaustive] 68#[non_exhaustive]
61pub struct ClockConfig { 69pub struct ClockConfig {
70 /// Ring oscillator configuration.
62 pub rosc: Option<RoscConfig>, 71 pub rosc: Option<RoscConfig>,
72 /// External oscillator configuration.
63 pub xosc: Option<XoscConfig>, 73 pub xosc: Option<XoscConfig>,
74 /// Reference clock configuration.
64 pub ref_clk: RefClkConfig, 75 pub ref_clk: RefClkConfig,
76 /// System clock configuration.
65 pub sys_clk: SysClkConfig, 77 pub sys_clk: SysClkConfig,
78 /// Peripheral clock source configuration.
66 pub peri_clk_src: Option<PeriClkSrc>, 79 pub peri_clk_src: Option<PeriClkSrc>,
80 /// USB clock configuration.
67 pub usb_clk: Option<UsbClkConfig>, 81 pub usb_clk: Option<UsbClkConfig>,
82 /// ADC clock configuration.
68 pub adc_clk: Option<AdcClkConfig>, 83 pub adc_clk: Option<AdcClkConfig>,
84 /// RTC clock configuration.
69 pub rtc_clk: Option<RtcClkConfig>, 85 pub rtc_clk: Option<RtcClkConfig>,
70 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 86 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
71 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, 87 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
72} 88}
73 89
74impl ClockConfig { 90impl ClockConfig {
91 /// Clock configuration derived from external crystal.
75 pub fn crystal(crystal_hz: u32) -> Self { 92 pub fn crystal(crystal_hz: u32) -> Self {
76 Self { 93 Self {
77 rosc: Some(RoscConfig { 94 rosc: Some(RoscConfig {
@@ -130,6 +147,7 @@ impl ClockConfig {
130 } 147 }
131 } 148 }
132 149
150 /// Clock configuration from internal oscillator.
133 pub fn rosc() -> Self { 151 pub fn rosc() -> Self {
134 Self { 152 Self {
135 rosc: Some(RoscConfig { 153 rosc: Some(RoscConfig {
@@ -179,130 +197,190 @@ impl ClockConfig {
179 // } 197 // }
180} 198}
181 199
200/// ROSC freq range.
182#[repr(u16)] 201#[repr(u16)]
183#[non_exhaustive] 202#[non_exhaustive]
184#[derive(Clone, Copy, Debug, PartialEq, Eq)] 203#[derive(Clone, Copy, Debug, PartialEq, Eq)]
185pub enum RoscRange { 204pub enum RoscRange {
205 /// Low range.
186 Low = pac::rosc::vals::FreqRange::LOW.0, 206 Low = pac::rosc::vals::FreqRange::LOW.0,
207 /// Medium range (1.33x low)
187 Medium = pac::rosc::vals::FreqRange::MEDIUM.0, 208 Medium = pac::rosc::vals::FreqRange::MEDIUM.0,
209 /// High range (2x low)
188 High = pac::rosc::vals::FreqRange::HIGH.0, 210 High = pac::rosc::vals::FreqRange::HIGH.0,
211 /// Too high. Should not be used.
189 TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0, 212 TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0,
190} 213}
191 214
215/// On-chip ring oscillator configuration.
192pub struct RoscConfig { 216pub struct RoscConfig {
193 /// Final frequency of the oscillator, after the divider has been applied. 217 /// Final frequency of the oscillator, after the divider has been applied.
194 /// The oscillator has a nominal frequency of 6.5MHz at medium range with 218 /// The oscillator has a nominal frequency of 6.5MHz at medium range with
195 /// divider 16 and all drive strengths set to 0, other values should be 219 /// divider 16 and all drive strengths set to 0, other values should be
196 /// measured in situ. 220 /// measured in situ.
197 pub hz: u32, 221 pub hz: u32,
222 /// Oscillator range.
198 pub range: RoscRange, 223 pub range: RoscRange,
224 /// Drive strength for oscillator.
199 pub drive_strength: [u8; 8], 225 pub drive_strength: [u8; 8],
226 /// Output divider.
200 pub div: u16, 227 pub div: u16,
201} 228}
202 229
230/// Crystal oscillator configuration.
203pub struct XoscConfig { 231pub struct XoscConfig {
232 /// Final frequency of the oscillator.
204 pub hz: u32, 233 pub hz: u32,
234 /// Configuring PLL for the system clock.
205 pub sys_pll: Option<PllConfig>, 235 pub sys_pll: Option<PllConfig>,
236 /// Configuring PLL for the USB clock.
206 pub usb_pll: Option<PllConfig>, 237 pub usb_pll: Option<PllConfig>,
238 /// Multiplier for the startup delay.
207 pub delay_multiplier: u32, 239 pub delay_multiplier: u32,
208} 240}
209 241
242/// PLL configuration.
210pub struct PllConfig { 243pub struct PllConfig {
244 /// Reference divisor.
211 pub refdiv: u8, 245 pub refdiv: u8,
246 /// Feedback divisor.
212 pub fbdiv: u16, 247 pub fbdiv: u16,
248 /// Output divisor 1.
213 pub post_div1: u8, 249 pub post_div1: u8,
250 /// Output divisor 2.
214 pub post_div2: u8, 251 pub post_div2: u8,
215} 252}
216 253
254/// Reference clock config.
217pub struct RefClkConfig { 255pub struct RefClkConfig {
256 /// Reference clock source.
218 pub src: RefClkSrc, 257 pub src: RefClkSrc,
258 /// Reference clock divider.
219 pub div: u8, 259 pub div: u8,
220} 260}
221 261
262/// Reference clock source.
222#[non_exhaustive] 263#[non_exhaustive]
223#[derive(Clone, Copy, Debug, PartialEq, Eq)] 264#[derive(Clone, Copy, Debug, PartialEq, Eq)]
224pub enum RefClkSrc { 265pub enum RefClkSrc {
225 // main sources 266 /// XOSC.
226 Xosc, 267 Xosc,
268 /// ROSC.
227 Rosc, 269 Rosc,
228 // aux sources 270 /// PLL USB.
229 PllUsb, 271 PllUsb,
230 // Gpin0, 272 // Gpin0,
231 // Gpin1, 273 // Gpin1,
232} 274}
233 275
276/// SYS clock source.
234#[non_exhaustive] 277#[non_exhaustive]
235#[derive(Clone, Copy, Debug, PartialEq, Eq)] 278#[derive(Clone, Copy, Debug, PartialEq, Eq)]
236pub enum SysClkSrc { 279pub enum SysClkSrc {
237 // main sources 280 /// REF.
238 Ref, 281 Ref,
239 // aux sources 282 /// PLL SYS.
240 PllSys, 283 PllSys,
284 /// PLL USB.
241 PllUsb, 285 PllUsb,
286 /// ROSC.
242 Rosc, 287 Rosc,
288 /// XOSC.
243 Xosc, 289 Xosc,
244 // Gpin0, 290 // Gpin0,
245 // Gpin1, 291 // Gpin1,
246} 292}
247 293
294/// SYS clock config.
248pub struct SysClkConfig { 295pub struct SysClkConfig {
296 /// SYS clock source.
249 pub src: SysClkSrc, 297 pub src: SysClkSrc,
298 /// SYS clock divider.
250 pub div_int: u32, 299 pub div_int: u32,
300 /// SYS clock fraction.
251 pub div_frac: u8, 301 pub div_frac: u8,
252} 302}
253 303
304/// USB clock source.
254#[repr(u8)] 305#[repr(u8)]
255#[non_exhaustive] 306#[non_exhaustive]
256#[derive(Clone, Copy, Debug, PartialEq, Eq)] 307#[derive(Clone, Copy, Debug, PartialEq, Eq)]
257pub enum UsbClkSrc { 308pub enum UsbClkSrc {
309 /// PLL USB.
258 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, 310 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
311 /// PLL SYS.
259 PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _, 312 PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _,
313 /// ROSC.
260 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, 314 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _,
315 /// XOSC.
261 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, 316 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _,
262 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , 317 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
263 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , 318 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
264} 319}
265 320
321/// USB clock config.
266pub struct UsbClkConfig { 322pub struct UsbClkConfig {
323 /// USB clock source.
267 pub src: UsbClkSrc, 324 pub src: UsbClkSrc,
325 /// USB clock divider.
268 pub div: u8, 326 pub div: u8,
327 /// USB clock phase.
269 pub phase: u8, 328 pub phase: u8,
270} 329}
271 330
331/// ADC clock source.
272#[repr(u8)] 332#[repr(u8)]
273#[non_exhaustive] 333#[non_exhaustive]
274#[derive(Clone, Copy, Debug, PartialEq, Eq)] 334#[derive(Clone, Copy, Debug, PartialEq, Eq)]
275pub enum AdcClkSrc { 335pub enum AdcClkSrc {
336 /// PLL USB.
276 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, 337 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
338 /// PLL SYS.
277 PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _, 339 PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
340 /// ROSC.
278 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, 341 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
342 /// XOSC.
279 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, 343 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _,
280 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , 344 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
281 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , 345 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
282} 346}
283 347
348/// ADC clock config.
284pub struct AdcClkConfig { 349pub struct AdcClkConfig {
350 /// ADC clock source.
285 pub src: AdcClkSrc, 351 pub src: AdcClkSrc,
352 /// ADC clock divider.
286 pub div: u8, 353 pub div: u8,
354 /// ADC clock phase.
287 pub phase: u8, 355 pub phase: u8,
288} 356}
289 357
358/// RTC clock source.
290#[repr(u8)] 359#[repr(u8)]
291#[non_exhaustive] 360#[non_exhaustive]
292#[derive(Clone, Copy, Debug, PartialEq, Eq)] 361#[derive(Clone, Copy, Debug, PartialEq, Eq)]
293pub enum RtcClkSrc { 362pub enum RtcClkSrc {
363 /// PLL USB.
294 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, 364 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _,
365 /// PLL SYS.
295 PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _, 366 PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
367 /// ROSC.
296 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, 368 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
369 /// XOSC.
297 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, 370 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _,
298 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , 371 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
299 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , 372 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
300} 373}
301 374
375/// RTC clock config.
302pub struct RtcClkConfig { 376pub struct RtcClkConfig {
377 /// RTC clock source.
303 pub src: RtcClkSrc, 378 pub src: RtcClkSrc,
379 /// RTC clock divider.
304 pub div_int: u32, 380 pub div_int: u32,
381 /// RTC clock divider fraction.
305 pub div_frac: u8, 382 pub div_frac: u8,
383 /// RTC clock phase.
306 pub phase: u8, 384 pub phase: u8,
307} 385}
308 386
@@ -579,10 +657,12 @@ fn configure_rosc(config: RoscConfig) -> u32 {
579 config.hz 657 config.hz
580} 658}
581 659
660/// ROSC clock frequency.
582pub fn rosc_freq() -> u32 { 661pub fn rosc_freq() -> u32 {
583 CLOCKS.rosc.load(Ordering::Relaxed) 662 CLOCKS.rosc.load(Ordering::Relaxed)
584} 663}
585 664
665/// XOSC clock frequency.
586pub fn xosc_freq() -> u32 { 666pub fn xosc_freq() -> u32 {
587 CLOCKS.xosc.load(Ordering::Relaxed) 667 CLOCKS.xosc.load(Ordering::Relaxed)
588} 668}
@@ -594,34 +674,42 @@ pub fn xosc_freq() -> u32 {
594// CLOCKS.gpin1.load(Ordering::Relaxed) 674// CLOCKS.gpin1.load(Ordering::Relaxed)
595// } 675// }
596 676
677/// PLL SYS clock frequency.
597pub fn pll_sys_freq() -> u32 { 678pub fn pll_sys_freq() -> u32 {
598 CLOCKS.pll_sys.load(Ordering::Relaxed) 679 CLOCKS.pll_sys.load(Ordering::Relaxed)
599} 680}
600 681
682/// PLL USB clock frequency.
601pub fn pll_usb_freq() -> u32 { 683pub fn pll_usb_freq() -> u32 {
602 CLOCKS.pll_usb.load(Ordering::Relaxed) 684 CLOCKS.pll_usb.load(Ordering::Relaxed)
603} 685}
604 686
687/// SYS clock frequency.
605pub fn clk_sys_freq() -> u32 { 688pub fn clk_sys_freq() -> u32 {
606 CLOCKS.sys.load(Ordering::Relaxed) 689 CLOCKS.sys.load(Ordering::Relaxed)
607} 690}
608 691
692/// REF clock frequency.
609pub fn clk_ref_freq() -> u32 { 693pub fn clk_ref_freq() -> u32 {
610 CLOCKS.reference.load(Ordering::Relaxed) 694 CLOCKS.reference.load(Ordering::Relaxed)
611} 695}
612 696
697/// Peripheral clock frequency.
613pub fn clk_peri_freq() -> u32 { 698pub fn clk_peri_freq() -> u32 {
614 CLOCKS.peri.load(Ordering::Relaxed) 699 CLOCKS.peri.load(Ordering::Relaxed)
615} 700}
616 701
702/// USB clock frequency.
617pub fn clk_usb_freq() -> u32 { 703pub fn clk_usb_freq() -> u32 {
618 CLOCKS.usb.load(Ordering::Relaxed) 704 CLOCKS.usb.load(Ordering::Relaxed)
619} 705}
620 706
707/// ADC clock frequency.
621pub fn clk_adc_freq() -> u32 { 708pub fn clk_adc_freq() -> u32 {
622 CLOCKS.adc.load(Ordering::Relaxed) 709 CLOCKS.adc.load(Ordering::Relaxed)
623} 710}
624 711
712/// RTC clock frequency.
625pub fn clk_rtc_freq() -> u16 { 713pub fn clk_rtc_freq() -> u16 {
626 CLOCKS.rtc.load(Ordering::Relaxed) 714 CLOCKS.rtc.load(Ordering::Relaxed)
627} 715}
@@ -682,7 +770,9 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
682 vco_freq / ((config.post_div1 * config.post_div2) as u32) 770 vco_freq / ((config.post_div1 * config.post_div2) as u32)
683} 771}
684 772
773/// General purpose input clock pin.
685pub trait GpinPin: crate::gpio::Pin { 774pub trait GpinPin: crate::gpio::Pin {
775 /// Pin number.
686 const NR: usize; 776 const NR: usize;
687} 777}
688 778
@@ -697,12 +787,14 @@ macro_rules! impl_gpinpin {
697impl_gpinpin!(PIN_20, 20, 0); 787impl_gpinpin!(PIN_20, 20, 0);
698impl_gpinpin!(PIN_22, 22, 1); 788impl_gpinpin!(PIN_22, 22, 1);
699 789
790/// General purpose clock input driver.
700pub struct Gpin<'d, T: Pin> { 791pub struct Gpin<'d, T: Pin> {
701 gpin: PeripheralRef<'d, AnyPin>, 792 gpin: PeripheralRef<'d, AnyPin>,
702 _phantom: PhantomData<T>, 793 _phantom: PhantomData<T>,
703} 794}
704 795
705impl<'d, T: Pin> Gpin<'d, T> { 796impl<'d, T: Pin> Gpin<'d, T> {
797 /// Create new gpin driver.
706 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { 798 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> {
707 into_ref!(gpin); 799 into_ref!(gpin);
708 800
@@ -728,7 +820,9 @@ impl<'d, T: Pin> Drop for Gpin<'d, T> {
728 } 820 }
729} 821}
730 822
823/// General purpose clock output pin.
731pub trait GpoutPin: crate::gpio::Pin { 824pub trait GpoutPin: crate::gpio::Pin {
825 /// Pin number.
732 fn number(&self) -> usize; 826 fn number(&self) -> usize;
733} 827}
734 828
@@ -747,26 +841,38 @@ impl_gpoutpin!(PIN_23, 1);
747impl_gpoutpin!(PIN_24, 2); 841impl_gpoutpin!(PIN_24, 2);
748impl_gpoutpin!(PIN_25, 3); 842impl_gpoutpin!(PIN_25, 3);
749 843
844/// Gpout clock source.
750#[repr(u8)] 845#[repr(u8)]
751pub enum GpoutSrc { 846pub enum GpoutSrc {
847 /// Sys PLL.
752 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, 848 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _,
753 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , 849 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
754 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , 850 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
851 /// USB PLL.
755 PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _, 852 PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _,
853 /// ROSC.
756 Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _, 854 Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _,
855 /// XOSC.
757 Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _, 856 Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _,
857 /// SYS.
758 Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _, 858 Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _,
859 /// USB.
759 Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, 860 Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _,
861 /// ADC.
760 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, 862 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _,
863 /// RTC.
761 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, 864 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
865 /// REF.
762 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, 866 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _,
763} 867}
764 868
869/// General purpose clock output driver.
765pub struct Gpout<'d, T: GpoutPin> { 870pub struct Gpout<'d, T: GpoutPin> {
766 gpout: PeripheralRef<'d, T>, 871 gpout: PeripheralRef<'d, T>,
767} 872}
768 873
769impl<'d, T: GpoutPin> Gpout<'d, T> { 874impl<'d, T: GpoutPin> Gpout<'d, T> {
875 /// Create new general purpose cloud output.
770 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { 876 pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self {
771 into_ref!(gpout); 877 into_ref!(gpout);
772 878
@@ -775,6 +881,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
775 Self { gpout } 881 Self { gpout }
776 } 882 }
777 883
884 /// Set clock divider.
778 pub fn set_div(&self, int: u32, frac: u8) { 885 pub fn set_div(&self, int: u32, frac: u8) {
779 let c = pac::CLOCKS; 886 let c = pac::CLOCKS;
780 c.clk_gpout_div(self.gpout.number()).write(|w| { 887 c.clk_gpout_div(self.gpout.number()).write(|w| {
@@ -783,6 +890,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
783 }); 890 });
784 } 891 }
785 892
893 /// Set clock source.
786 pub fn set_src(&self, src: GpoutSrc) { 894 pub fn set_src(&self, src: GpoutSrc) {
787 let c = pac::CLOCKS; 895 let c = pac::CLOCKS;
788 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 896 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
@@ -790,6 +898,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
790 }); 898 });
791 } 899 }
792 900
901 /// Enable clock.
793 pub fn enable(&self) { 902 pub fn enable(&self) {
794 let c = pac::CLOCKS; 903 let c = pac::CLOCKS;
795 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 904 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
@@ -797,6 +906,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
797 }); 906 });
798 } 907 }
799 908
909 /// Disable clock.
800 pub fn disable(&self) { 910 pub fn disable(&self) {
801 let c = pac::CLOCKS; 911 let c = pac::CLOCKS;
802 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 912 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
@@ -804,6 +914,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
804 }); 914 });
805 } 915 }
806 916
917 /// Clock frequency.
807 pub fn get_freq(&self) -> u32 { 918 pub fn get_freq(&self) -> u32 {
808 let c = pac::CLOCKS; 919 let c = pac::CLOCKS;
809 let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc(); 920 let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc();
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 45ca21a75..088a842a1 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -38,6 +38,9 @@ pub(crate) unsafe fn init() {
38 interrupt::DMA_IRQ_0.enable(); 38 interrupt::DMA_IRQ_0.enable();
39} 39}
40 40
41/// DMA read.
42///
43/// SAFETY: Slice must point to a valid location reachable by DMA.
41pub unsafe fn read<'a, C: Channel, W: Word>( 44pub unsafe fn read<'a, C: Channel, W: Word>(
42 ch: impl Peripheral<P = C> + 'a, 45 ch: impl Peripheral<P = C> + 'a,
43 from: *const W, 46 from: *const W,
@@ -57,6 +60,9 @@ pub unsafe fn read<'a, C: Channel, W: Word>(
57 ) 60 )
58} 61}
59 62
63/// DMA write.
64///
65/// SAFETY: Slice must point to a valid location reachable by DMA.
60pub unsafe fn write<'a, C: Channel, W: Word>( 66pub unsafe fn write<'a, C: Channel, W: Word>(
61 ch: impl Peripheral<P = C> + 'a, 67 ch: impl Peripheral<P = C> + 'a,
62 from: *const [W], 68 from: *const [W],
@@ -79,6 +85,9 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
79// static mut so that this is allocated in RAM. 85// static mut so that this is allocated in RAM.
80static mut DUMMY: u32 = 0; 86static mut DUMMY: u32 = 0;
81 87
88/// DMA repeated write.
89///
90/// SAFETY: Slice must point to a valid location reachable by DMA.
82pub unsafe fn write_repeated<'a, C: Channel, W: Word>( 91pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
83 ch: impl Peripheral<P = C> + 'a, 92 ch: impl Peripheral<P = C> + 'a,
84 to: *mut W, 93 to: *mut W,
@@ -97,6 +106,9 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
97 ) 106 )
98} 107}
99 108
109/// DMA copy between slices.
110///
111/// SAFETY: Slices must point to locations reachable by DMA.
100pub unsafe fn copy<'a, C: Channel, W: Word>( 112pub unsafe fn copy<'a, C: Channel, W: Word>(
101 ch: impl Peripheral<P = C> + 'a, 113 ch: impl Peripheral<P = C> + 'a,
102 from: &[W], 114 from: &[W],
@@ -152,6 +164,7 @@ fn copy_inner<'a, C: Channel>(
152 Transfer::new(ch) 164 Transfer::new(ch)
153} 165}
154 166
167/// DMA transfer driver.
155#[must_use = "futures do nothing unless you `.await` or poll them"] 168#[must_use = "futures do nothing unless you `.await` or poll them"]
156pub struct Transfer<'a, C: Channel> { 169pub struct Transfer<'a, C: Channel> {
157 channel: PeripheralRef<'a, C>, 170 channel: PeripheralRef<'a, C>,
@@ -201,19 +214,25 @@ mod sealed {
201 pub trait Word {} 214 pub trait Word {}
202} 215}
203 216
217/// DMA channel interface.
204pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static { 218pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static {
219 /// Channel number.
205 fn number(&self) -> u8; 220 fn number(&self) -> u8;
206 221
222 /// Channel registry block.
207 fn regs(&self) -> pac::dma::Channel { 223 fn regs(&self) -> pac::dma::Channel {
208 pac::DMA.ch(self.number() as _) 224 pac::DMA.ch(self.number() as _)
209 } 225 }
210 226
227 /// Convert into type-erased [AnyChannel].
211 fn degrade(self) -> AnyChannel { 228 fn degrade(self) -> AnyChannel {
212 AnyChannel { number: self.number() } 229 AnyChannel { number: self.number() }
213 } 230 }
214} 231}
215 232
233/// DMA word.
216pub trait Word: sealed::Word { 234pub trait Word: sealed::Word {
235 /// Word size.
217 fn size() -> vals::DataSize; 236 fn size() -> vals::DataSize;
218} 237}
219 238
@@ -238,6 +257,7 @@ impl Word for u32 {
238 } 257 }
239} 258}
240 259
260/// Type erased DMA channel.
241pub struct AnyChannel { 261pub struct AnyChannel {
242 number: u8, 262 number: u8,
243} 263}
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 1b20561da..2d673cf6c 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -1,3 +1,4 @@
1//! Flash driver.
1use core::future::Future; 2use core::future::Future;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::pin::Pin; 4use core::pin::Pin;
@@ -13,9 +14,10 @@ use crate::dma::{AnyChannel, Channel, Transfer};
13use crate::pac; 14use crate::pac;
14use crate::peripherals::FLASH; 15use crate::peripherals::FLASH;
15 16
17/// Flash base address.
16pub const FLASH_BASE: *const u32 = 0x10000000 as _; 18pub const FLASH_BASE: *const u32 = 0x10000000 as _;
17 19
18// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. 20/// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
19// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. 21// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
20pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); 22pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram");
21 23
@@ -24,10 +26,15 @@ pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram");
24// These limitations are currently enforced because of using the 26// These limitations are currently enforced because of using the
25// RP2040 boot-rom flash functions, that are optimized for flash compatibility 27// RP2040 boot-rom flash functions, that are optimized for flash compatibility
26// rather than performance. 28// rather than performance.
29/// Flash page size.
27pub const PAGE_SIZE: usize = 256; 30pub const PAGE_SIZE: usize = 256;
31/// Flash write size.
28pub const WRITE_SIZE: usize = 1; 32pub const WRITE_SIZE: usize = 1;
33/// Flash read size.
29pub const READ_SIZE: usize = 1; 34pub const READ_SIZE: usize = 1;
35/// Flash erase size.
30pub const ERASE_SIZE: usize = 4096; 36pub const ERASE_SIZE: usize = 4096;
37/// Flash DMA read size.
31pub const ASYNC_READ_SIZE: usize = 4; 38pub const ASYNC_READ_SIZE: usize = 4;
32 39
33/// Error type for NVMC operations. 40/// Error type for NVMC operations.
@@ -38,7 +45,9 @@ pub enum Error {
38 OutOfBounds, 45 OutOfBounds,
39 /// Unaligned operation or using unaligned buffers. 46 /// Unaligned operation or using unaligned buffers.
40 Unaligned, 47 Unaligned,
48 /// Accessed from the wrong core.
41 InvalidCore, 49 InvalidCore,
50 /// Other error
42 Other, 51 Other,
43} 52}
44 53
@@ -96,12 +105,18 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, '
96 } 105 }
97} 106}
98 107
108/// Flash driver.
99pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> { 109pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> {
100 dma: Option<PeripheralRef<'d, AnyChannel>>, 110 dma: Option<PeripheralRef<'d, AnyChannel>>,
101 phantom: PhantomData<(&'d mut T, M)>, 111 phantom: PhantomData<(&'d mut T, M)>,
102} 112}
103 113
104impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> { 114impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> {
115 /// Blocking read.
116 ///
117 /// The offset and buffer must be aligned.
118 ///
119 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
105 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 120 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
106 trace!( 121 trace!(
107 "Reading from 0x{:x} to 0x{:x}", 122 "Reading from 0x{:x} to 0x{:x}",
@@ -116,10 +131,14 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
116 Ok(()) 131 Ok(())
117 } 132 }
118 133
134 /// Flash capacity.
119 pub fn capacity(&self) -> usize { 135 pub fn capacity(&self) -> usize {
120 FLASH_SIZE 136 FLASH_SIZE
121 } 137 }
122 138
139 /// Blocking erase.
140 ///
141 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
123 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 142 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
124 check_erase(self, from, to)?; 143 check_erase(self, from, to)?;
125 144
@@ -136,6 +155,11 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
136 Ok(()) 155 Ok(())
137 } 156 }
138 157
158 /// Blocking write.
159 ///
160 /// The offset and buffer must be aligned.
161 ///
162 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
139 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 163 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
140 check_write(self, offset, bytes.len())?; 164 check_write(self, offset, bytes.len())?;
141 165
@@ -219,6 +243,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
219} 243}
220 244
221impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { 245impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> {
246 /// Create a new flash driver in blocking mode.
222 pub fn new_blocking(_flash: impl Peripheral<P = T> + 'd) -> Self { 247 pub fn new_blocking(_flash: impl Peripheral<P = T> + 'd) -> Self {
223 Self { 248 Self {
224 dma: None, 249 dma: None,
@@ -228,6 +253,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE
228} 253}
229 254
230impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { 255impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
256 /// Create a new flash driver in async mode.
231 pub fn new(_flash: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = impl Channel> + 'd) -> Self { 257 pub fn new(_flash: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = impl Channel> + 'd) -> Self {
232 into_ref!(dma); 258 into_ref!(dma);
233 Self { 259 Self {
@@ -236,6 +262,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
236 } 262 }
237 } 263 }
238 264
265 /// Start a background read operation.
266 ///
267 /// The offset and buffer must be aligned.
268 ///
269 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
239 pub fn background_read<'a>( 270 pub fn background_read<'a>(
240 &'a mut self, 271 &'a mut self,
241 offset: u32, 272 offset: u32,
@@ -279,6 +310,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
279 }) 310 })
280 } 311 }
281 312
313 /// Async read.
314 ///
315 /// The offset and buffer must be aligned.
316 ///
317 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
282 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 318 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
283 use core::mem::MaybeUninit; 319 use core::mem::MaybeUninit;
284 320
@@ -874,7 +910,9 @@ mod sealed {
874 pub trait Mode {} 910 pub trait Mode {}
875} 911}
876 912
913/// Flash instance.
877pub trait Instance: sealed::Instance {} 914pub trait Instance: sealed::Instance {}
915/// Flash mode.
878pub trait Mode: sealed::Mode {} 916pub trait Mode: sealed::Mode {}
879 917
880impl sealed::Instance for FLASH {} 918impl sealed::Instance for FLASH {}
@@ -887,7 +925,9 @@ macro_rules! impl_mode {
887 }; 925 };
888} 926}
889 927
928/// Flash blocking mode.
890pub struct Blocking; 929pub struct Blocking;
930/// Flash async mode.
891pub struct Async; 931pub struct Async;
892 932
893impl_mode!(Blocking); 933impl_mode!(Blocking);
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 9034f3f36..2e6692abe 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -1,3 +1,4 @@
1//! GPIO driver.
1#![macro_use] 2#![macro_use]
2use core::convert::Infallible; 3use core::convert::Infallible;
3use core::future::Future; 4use core::future::Future;
@@ -23,7 +24,9 @@ static QSPI_WAKERS: [AtomicWaker; QSPI_PIN_COUNT] = [NEW_AW; QSPI_PIN_COUNT];
23/// Represents a digital input or output level. 24/// Represents a digital input or output level.
24#[derive(Debug, Eq, PartialEq, Clone, Copy)] 25#[derive(Debug, Eq, PartialEq, Clone, Copy)]
25pub enum Level { 26pub enum Level {
27 /// Logical low.
26 Low, 28 Low,
29 /// Logical high.
27 High, 30 High,
28} 31}
29 32
@@ -48,48 +51,66 @@ impl From<Level> for bool {
48/// Represents a pull setting for an input. 51/// Represents a pull setting for an input.
49#[derive(Debug, Clone, Copy, Eq, PartialEq)] 52#[derive(Debug, Clone, Copy, Eq, PartialEq)]
50pub enum Pull { 53pub enum Pull {
54 /// No pull.
51 None, 55 None,
56 /// Internal pull-up resistor.
52 Up, 57 Up,
58 /// Internal pull-down resistor.
53 Down, 59 Down,
54} 60}
55 61
56/// Drive strength of an output 62/// Drive strength of an output
57#[derive(Debug, Eq, PartialEq)] 63#[derive(Debug, Eq, PartialEq)]
58pub enum Drive { 64pub enum Drive {
65 /// 2 mA drive.
59 _2mA, 66 _2mA,
67 /// 4 mA drive.
60 _4mA, 68 _4mA,
69 /// 8 mA drive.
61 _8mA, 70 _8mA,
71 /// 1 2mA drive.
62 _12mA, 72 _12mA,
63} 73}
64/// Slew rate of an output 74/// Slew rate of an output
65#[derive(Debug, Eq, PartialEq)] 75#[derive(Debug, Eq, PartialEq)]
66pub enum SlewRate { 76pub enum SlewRate {
77 /// Fast slew rate.
67 Fast, 78 Fast,
79 /// Slow slew rate.
68 Slow, 80 Slow,
69} 81}
70 82
71/// A GPIO bank with up to 32 pins. 83/// A GPIO bank with up to 32 pins.
72#[derive(Debug, Eq, PartialEq)] 84#[derive(Debug, Eq, PartialEq)]
73pub enum Bank { 85pub enum Bank {
86 /// Bank 0.
74 Bank0 = 0, 87 Bank0 = 0,
88 /// QSPI.
75 #[cfg(feature = "qspi-as-gpio")] 89 #[cfg(feature = "qspi-as-gpio")]
76 Qspi = 1, 90 Qspi = 1,
77} 91}
78 92
93/// Dormant mode config.
79#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] 94#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))] 95#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub struct DormantWakeConfig { 96pub struct DormantWakeConfig {
97 /// Wake on edge high.
82 pub edge_high: bool, 98 pub edge_high: bool,
99 /// Wake on edge low.
83 pub edge_low: bool, 100 pub edge_low: bool,
101 /// Wake on level high.
84 pub level_high: bool, 102 pub level_high: bool,
103 /// Wake on level low.
85 pub level_low: bool, 104 pub level_low: bool,
86} 105}
87 106
107/// GPIO input driver.
88pub struct Input<'d, T: Pin> { 108pub struct Input<'d, T: Pin> {
89 pin: Flex<'d, T>, 109 pin: Flex<'d, T>,
90} 110}
91 111
92impl<'d, T: Pin> Input<'d, T> { 112impl<'d, T: Pin> Input<'d, T> {
113 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
93 #[inline] 114 #[inline]
94 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { 115 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self {
95 let mut pin = Flex::new(pin); 116 let mut pin = Flex::new(pin);
@@ -104,47 +125,55 @@ impl<'d, T: Pin> Input<'d, T> {
104 self.pin.set_schmitt(enable) 125 self.pin.set_schmitt(enable)
105 } 126 }
106 127
128 /// Get whether the pin input level is high.
107 #[inline] 129 #[inline]
108 pub fn is_high(&self) -> bool { 130 pub fn is_high(&mut self) -> bool {
109 self.pin.is_high() 131 self.pin.is_high()
110 } 132 }
111 133
134 /// Get whether the pin input level is low.
112 #[inline] 135 #[inline]
113 pub fn is_low(&self) -> bool { 136 pub fn is_low(&mut self) -> bool {
114 self.pin.is_low() 137 self.pin.is_low()
115 } 138 }
116 139
117 /// Returns current pin level 140 /// Returns current pin level
118 #[inline] 141 #[inline]
119 pub fn get_level(&self) -> Level { 142 pub fn get_level(&mut self) -> Level {
120 self.pin.get_level() 143 self.pin.get_level()
121 } 144 }
122 145
146 /// Wait until the pin is high. If it is already high, return immediately.
123 #[inline] 147 #[inline]
124 pub async fn wait_for_high(&mut self) { 148 pub async fn wait_for_high(&mut self) {
125 self.pin.wait_for_high().await; 149 self.pin.wait_for_high().await;
126 } 150 }
127 151
152 /// Wait until the pin is low. If it is already low, return immediately.
128 #[inline] 153 #[inline]
129 pub async fn wait_for_low(&mut self) { 154 pub async fn wait_for_low(&mut self) {
130 self.pin.wait_for_low().await; 155 self.pin.wait_for_low().await;
131 } 156 }
132 157
158 /// Wait for the pin to undergo a transition from low to high.
133 #[inline] 159 #[inline]
134 pub async fn wait_for_rising_edge(&mut self) { 160 pub async fn wait_for_rising_edge(&mut self) {
135 self.pin.wait_for_rising_edge().await; 161 self.pin.wait_for_rising_edge().await;
136 } 162 }
137 163
164 /// Wait for the pin to undergo a transition from high to low.
138 #[inline] 165 #[inline]
139 pub async fn wait_for_falling_edge(&mut self) { 166 pub async fn wait_for_falling_edge(&mut self) {
140 self.pin.wait_for_falling_edge().await; 167 self.pin.wait_for_falling_edge().await;
141 } 168 }
142 169
170 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
143 #[inline] 171 #[inline]
144 pub async fn wait_for_any_edge(&mut self) { 172 pub async fn wait_for_any_edge(&mut self) {
145 self.pin.wait_for_any_edge().await; 173 self.pin.wait_for_any_edge().await;
146 } 174 }
147 175
176 /// Configure dormant wake.
148 #[inline] 177 #[inline]
149 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { 178 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> {
150 self.pin.dormant_wake(cfg) 179 self.pin.dormant_wake(cfg)
@@ -155,10 +184,15 @@ impl<'d, T: Pin> Input<'d, T> {
155#[derive(Debug, Eq, PartialEq, Copy, Clone)] 184#[derive(Debug, Eq, PartialEq, Copy, Clone)]
156#[cfg_attr(feature = "defmt", derive(defmt::Format))] 185#[cfg_attr(feature = "defmt", derive(defmt::Format))]
157pub enum InterruptTrigger { 186pub enum InterruptTrigger {
187 /// Trigger on pin low.
158 LevelLow, 188 LevelLow,
189 /// Trigger on pin high.
159 LevelHigh, 190 LevelHigh,
191 /// Trigger on high to low transition.
160 EdgeLow, 192 EdgeLow,
193 /// Trigger on low to high transition.
161 EdgeHigh, 194 EdgeHigh,
195 /// Trigger on any transition.
162 AnyEdge, 196 AnyEdge,
163} 197}
164 198
@@ -226,6 +260,7 @@ struct InputFuture<'a, T: Pin> {
226} 260}
227 261
228impl<'d, T: Pin> InputFuture<'d, T> { 262impl<'d, T: Pin> InputFuture<'d, T> {
263 /// Create a new future wiating for input trigger.
229 pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { 264 pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
230 into_ref!(pin); 265 into_ref!(pin);
231 let pin_group = (pin.pin() % 8) as usize; 266 let pin_group = (pin.pin() % 8) as usize;
@@ -308,11 +343,13 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
308 } 343 }
309} 344}
310 345
346/// GPIO output driver.
311pub struct Output<'d, T: Pin> { 347pub struct Output<'d, T: Pin> {
312 pin: Flex<'d, T>, 348 pin: Flex<'d, T>,
313} 349}
314 350
315impl<'d, T: Pin> Output<'d, T> { 351impl<'d, T: Pin> Output<'d, T> {
352 /// Create GPIO output driver for a [Pin] with the provided [Level].
316 #[inline] 353 #[inline]
317 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { 354 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self {
318 let mut pin = Flex::new(pin); 355 let mut pin = Flex::new(pin);
@@ -331,7 +368,7 @@ impl<'d, T: Pin> Output<'d, T> {
331 self.pin.set_drive_strength(strength) 368 self.pin.set_drive_strength(strength)
332 } 369 }
333 370
334 // Set the pin's slew rate. 371 /// Set the pin's slew rate.
335 #[inline] 372 #[inline]
336 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 373 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
337 self.pin.set_slew_rate(slew_rate) 374 self.pin.set_slew_rate(slew_rate)
@@ -357,19 +394,19 @@ impl<'d, T: Pin> Output<'d, T> {
357 394
358 /// Is the output pin set as high? 395 /// Is the output pin set as high?
359 #[inline] 396 #[inline]
360 pub fn is_set_high(&self) -> bool { 397 pub fn is_set_high(&mut self) -> bool {
361 self.pin.is_set_high() 398 self.pin.is_set_high()
362 } 399 }
363 400
364 /// Is the output pin set as low? 401 /// Is the output pin set as low?
365 #[inline] 402 #[inline]
366 pub fn is_set_low(&self) -> bool { 403 pub fn is_set_low(&mut self) -> bool {
367 self.pin.is_set_low() 404 self.pin.is_set_low()
368 } 405 }
369 406
370 /// What level output is set to 407 /// What level output is set to
371 #[inline] 408 #[inline]
372 pub fn get_output_level(&self) -> Level { 409 pub fn get_output_level(&mut self) -> Level {
373 self.pin.get_output_level() 410 self.pin.get_output_level()
374 } 411 }
375 412
@@ -386,6 +423,7 @@ pub struct OutputOpenDrain<'d, T: Pin> {
386} 423}
387 424
388impl<'d, T: Pin> OutputOpenDrain<'d, T> { 425impl<'d, T: Pin> OutputOpenDrain<'d, T> {
426 /// Create GPIO output driver for a [Pin] in open drain mode with the provided [Level].
389 #[inline] 427 #[inline]
390 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { 428 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self {
391 let mut pin = Flex::new(pin); 429 let mut pin = Flex::new(pin);
@@ -403,7 +441,7 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
403 self.pin.set_drive_strength(strength) 441 self.pin.set_drive_strength(strength)
404 } 442 }
405 443
406 // Set the pin's slew rate. 444 /// Set the pin's slew rate.
407 #[inline] 445 #[inline]
408 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 446 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
409 self.pin.set_slew_rate(slew_rate) 447 self.pin.set_slew_rate(slew_rate)
@@ -434,19 +472,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
434 472
435 /// Is the output level high? 473 /// Is the output level high?
436 #[inline] 474 #[inline]
437 pub fn is_set_high(&self) -> bool { 475 pub fn is_set_high(&mut self) -> bool {
438 !self.is_set_low() 476 !self.is_set_low()
439 } 477 }
440 478
441 /// Is the output level low? 479 /// Is the output level low?
442 #[inline] 480 #[inline]
443 pub fn is_set_low(&self) -> bool { 481 pub fn is_set_low(&mut self) -> bool {
444 self.pin.is_set_as_output() 482 self.pin.is_set_as_output()
445 } 483 }
446 484
447 /// What level output is set to 485 /// What level output is set to
448 #[inline] 486 #[inline]
449 pub fn get_output_level(&self) -> Level { 487 pub fn get_output_level(&mut self) -> Level {
450 self.is_set_high().into() 488 self.is_set_high().into()
451 } 489 }
452 490
@@ -456,42 +494,49 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
456 self.pin.toggle_set_as_output() 494 self.pin.toggle_set_as_output()
457 } 495 }
458 496
497 /// Get whether the pin input level is high.
459 #[inline] 498 #[inline]
460 pub fn is_high(&self) -> bool { 499 pub fn is_high(&mut self) -> bool {
461 self.pin.is_high() 500 self.pin.is_high()
462 } 501 }
463 502
503 /// Get whether the pin input level is low.
464 #[inline] 504 #[inline]
465 pub fn is_low(&self) -> bool { 505 pub fn is_low(&mut self) -> bool {
466 self.pin.is_low() 506 self.pin.is_low()
467 } 507 }
468 508
469 /// Returns current pin level 509 /// Returns current pin level
470 #[inline] 510 #[inline]
471 pub fn get_level(&self) -> Level { 511 pub fn get_level(&mut self) -> Level {
472 self.is_high().into() 512 self.is_high().into()
473 } 513 }
474 514
515 /// Wait until the pin is high. If it is already high, return immediately.
475 #[inline] 516 #[inline]
476 pub async fn wait_for_high(&mut self) { 517 pub async fn wait_for_high(&mut self) {
477 self.pin.wait_for_high().await; 518 self.pin.wait_for_high().await;
478 } 519 }
479 520
521 /// Wait until the pin is low. If it is already low, return immediately.
480 #[inline] 522 #[inline]
481 pub async fn wait_for_low(&mut self) { 523 pub async fn wait_for_low(&mut self) {
482 self.pin.wait_for_low().await; 524 self.pin.wait_for_low().await;
483 } 525 }
484 526
527 /// Wait for the pin to undergo a transition from low to high.
485 #[inline] 528 #[inline]
486 pub async fn wait_for_rising_edge(&mut self) { 529 pub async fn wait_for_rising_edge(&mut self) {
487 self.pin.wait_for_rising_edge().await; 530 self.pin.wait_for_rising_edge().await;
488 } 531 }
489 532
533 /// Wait for the pin to undergo a transition from high to low.
490 #[inline] 534 #[inline]
491 pub async fn wait_for_falling_edge(&mut self) { 535 pub async fn wait_for_falling_edge(&mut self) {
492 self.pin.wait_for_falling_edge().await; 536 self.pin.wait_for_falling_edge().await;
493 } 537 }
494 538
539 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
495 #[inline] 540 #[inline]
496 pub async fn wait_for_any_edge(&mut self) { 541 pub async fn wait_for_any_edge(&mut self) {
497 self.pin.wait_for_any_edge().await; 542 self.pin.wait_for_any_edge().await;
@@ -508,6 +553,10 @@ pub struct Flex<'d, T: Pin> {
508} 553}
509 554
510impl<'d, T: Pin> Flex<'d, T> { 555impl<'d, T: Pin> Flex<'d, T> {
556 /// Wrap the pin in a `Flex`.
557 ///
558 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
559 /// before the pin is put into output mode.
511 #[inline] 560 #[inline]
512 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { 561 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self {
513 into_ref!(pin); 562 into_ref!(pin);
@@ -556,7 +605,7 @@ impl<'d, T: Pin> Flex<'d, T> {
556 }); 605 });
557 } 606 }
558 607
559 // Set the pin's slew rate. 608 /// Set the pin's slew rate.
560 #[inline] 609 #[inline]
561 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 610 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
562 self.pin.pad_ctrl().modify(|w| { 611 self.pin.pad_ctrl().modify(|w| {
@@ -589,29 +638,43 @@ impl<'d, T: Pin> Flex<'d, T> {
589 self.pin.sio_oe().value_set().write_value(self.bit()) 638 self.pin.sio_oe().value_set().write_value(self.bit())
590 } 639 }
591 640
641 /// Set as output pin.
592 #[inline] 642 #[inline]
593 fn is_set_as_output(&self) -> bool { 643 pub fn is_set_as_output(&mut self) -> bool {
644 self.ref_is_set_as_output()
645 }
646
647 #[inline]
648 pub(crate) fn ref_is_set_as_output(&self) -> bool {
594 (self.pin.sio_oe().value().read() & self.bit()) != 0 649 (self.pin.sio_oe().value().read() & self.bit()) != 0
595 } 650 }
596 651
652 /// Toggle output pin.
597 #[inline] 653 #[inline]
598 pub fn toggle_set_as_output(&mut self) { 654 pub fn toggle_set_as_output(&mut self) {
599 self.pin.sio_oe().value_xor().write_value(self.bit()) 655 self.pin.sio_oe().value_xor().write_value(self.bit())
600 } 656 }
601 657
658 /// Get whether the pin input level is high.
602 #[inline] 659 #[inline]
603 pub fn is_high(&self) -> bool { 660 pub fn is_high(&mut self) -> bool {
604 !self.is_low() 661 !self.is_low()
605 } 662 }
663 /// Get whether the pin input level is low.
664
665 #[inline]
666 pub fn is_low(&mut self) -> bool {
667 self.ref_is_low()
668 }
606 669
607 #[inline] 670 #[inline]
608 pub fn is_low(&self) -> bool { 671 pub(crate) fn ref_is_low(&self) -> bool {
609 self.pin.sio_in().read() & self.bit() == 0 672 self.pin.sio_in().read() & self.bit() == 0
610 } 673 }
611 674
612 /// Returns current pin level 675 /// Returns current pin level
613 #[inline] 676 #[inline]
614 pub fn get_level(&self) -> Level { 677 pub fn get_level(&mut self) -> Level {
615 self.is_high().into() 678 self.is_high().into()
616 } 679 }
617 680
@@ -638,19 +701,24 @@ impl<'d, T: Pin> Flex<'d, T> {
638 701
639 /// Is the output level high? 702 /// Is the output level high?
640 #[inline] 703 #[inline]
641 pub fn is_set_high(&self) -> bool { 704 pub fn is_set_high(&mut self) -> bool {
642 !self.is_set_low() 705 !self.is_set_low()
643 } 706 }
644 707
645 /// Is the output level low? 708 /// Is the output level low?
646 #[inline] 709 #[inline]
647 pub fn is_set_low(&self) -> bool { 710 pub fn is_set_low(&mut self) -> bool {
711 self.ref_is_set_low()
712 }
713
714 #[inline]
715 pub(crate) fn ref_is_set_low(&self) -> bool {
648 (self.pin.sio_out().value().read() & self.bit()) == 0 716 (self.pin.sio_out().value().read() & self.bit()) == 0
649 } 717 }
650 718
651 /// What level output is set to 719 /// What level output is set to
652 #[inline] 720 #[inline]
653 pub fn get_output_level(&self) -> Level { 721 pub fn get_output_level(&mut self) -> Level {
654 self.is_set_high().into() 722 self.is_set_high().into()
655 } 723 }
656 724
@@ -660,31 +728,37 @@ impl<'d, T: Pin> Flex<'d, T> {
660 self.pin.sio_out().value_xor().write_value(self.bit()) 728 self.pin.sio_out().value_xor().write_value(self.bit())
661 } 729 }
662 730
731 /// Wait until the pin is high. If it is already high, return immediately.
663 #[inline] 732 #[inline]
664 pub async fn wait_for_high(&mut self) { 733 pub async fn wait_for_high(&mut self) {
665 InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await; 734 InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await;
666 } 735 }
667 736
737 /// Wait until the pin is low. If it is already low, return immediately.
668 #[inline] 738 #[inline]
669 pub async fn wait_for_low(&mut self) { 739 pub async fn wait_for_low(&mut self) {
670 InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await; 740 InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await;
671 } 741 }
672 742
743 /// Wait for the pin to undergo a transition from low to high.
673 #[inline] 744 #[inline]
674 pub async fn wait_for_rising_edge(&mut self) { 745 pub async fn wait_for_rising_edge(&mut self) {
675 InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await; 746 InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await;
676 } 747 }
677 748
749 /// Wait for the pin to undergo a transition from high to low.
678 #[inline] 750 #[inline]
679 pub async fn wait_for_falling_edge(&mut self) { 751 pub async fn wait_for_falling_edge(&mut self) {
680 InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await; 752 InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await;
681 } 753 }
682 754
755 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
683 #[inline] 756 #[inline]
684 pub async fn wait_for_any_edge(&mut self) { 757 pub async fn wait_for_any_edge(&mut self) {
685 InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await; 758 InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await;
686 } 759 }
687 760
761 /// Configure dormant wake.
688 #[inline] 762 #[inline]
689 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { 763 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> {
690 let idx = self.pin._pin() as usize; 764 let idx = self.pin._pin() as usize;
@@ -722,6 +796,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
722 } 796 }
723} 797}
724 798
799/// Dormant wake driver.
725pub struct DormantWake<'w, T: Pin> { 800pub struct DormantWake<'w, T: Pin> {
726 pin: PeripheralRef<'w, T>, 801 pin: PeripheralRef<'w, T>,
727 cfg: DormantWakeConfig, 802 cfg: DormantWakeConfig,
@@ -803,6 +878,7 @@ pub(crate) mod sealed {
803 } 878 }
804} 879}
805 880
881/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
806pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { 882pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static {
807 /// Degrade to a generic pin struct 883 /// Degrade to a generic pin struct
808 fn degrade(self) -> AnyPin { 884 fn degrade(self) -> AnyPin {
@@ -824,6 +900,7 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
824 } 900 }
825} 901}
826 902
903/// Type-erased GPIO pin
827pub struct AnyPin { 904pub struct AnyPin {
828 pin_bank: u8, 905 pin_bank: u8,
829} 906}
@@ -912,11 +989,11 @@ mod eh02 {
912 type Error = Infallible; 989 type Error = Infallible;
913 990
914 fn is_high(&self) -> Result<bool, Self::Error> { 991 fn is_high(&self) -> Result<bool, Self::Error> {
915 Ok(self.is_high()) 992 Ok(!self.pin.ref_is_low())
916 } 993 }
917 994
918 fn is_low(&self) -> Result<bool, Self::Error> { 995 fn is_low(&self) -> Result<bool, Self::Error> {
919 Ok(self.is_low()) 996 Ok(self.pin.ref_is_low())
920 } 997 }
921 } 998 }
922 999
@@ -934,11 +1011,11 @@ mod eh02 {
934 1011
935 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { 1012 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> {
936 fn is_set_high(&self) -> Result<bool, Self::Error> { 1013 fn is_set_high(&self) -> Result<bool, Self::Error> {
937 Ok(self.is_set_high()) 1014 Ok(!self.pin.ref_is_set_low())
938 } 1015 }
939 1016
940 fn is_set_low(&self) -> Result<bool, Self::Error> { 1017 fn is_set_low(&self) -> Result<bool, Self::Error> {
941 Ok(self.is_set_low()) 1018 Ok(self.pin.ref_is_set_low())
942 } 1019 }
943 } 1020 }
944 1021
@@ -954,11 +1031,11 @@ mod eh02 {
954 type Error = Infallible; 1031 type Error = Infallible;
955 1032
956 fn is_high(&self) -> Result<bool, Self::Error> { 1033 fn is_high(&self) -> Result<bool, Self::Error> {
957 Ok(self.is_high()) 1034 Ok(!self.pin.ref_is_low())
958 } 1035 }
959 1036
960 fn is_low(&self) -> Result<bool, Self::Error> { 1037 fn is_low(&self) -> Result<bool, Self::Error> {
961 Ok(self.is_low()) 1038 Ok(self.pin.ref_is_low())
962 } 1039 }
963 } 1040 }
964 1041
@@ -978,11 +1055,11 @@ mod eh02 {
978 1055
979 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { 1056 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> {
980 fn is_set_high(&self) -> Result<bool, Self::Error> { 1057 fn is_set_high(&self) -> Result<bool, Self::Error> {
981 Ok(self.is_set_high()) 1058 Ok(!self.pin.ref_is_set_as_output())
982 } 1059 }
983 1060
984 fn is_set_low(&self) -> Result<bool, Self::Error> { 1061 fn is_set_low(&self) -> Result<bool, Self::Error> {
985 Ok(self.is_set_low()) 1062 Ok(self.pin.ref_is_set_as_output())
986 } 1063 }
987 } 1064 }
988 1065
@@ -998,11 +1075,11 @@ mod eh02 {
998 type Error = Infallible; 1075 type Error = Infallible;
999 1076
1000 fn is_high(&self) -> Result<bool, Self::Error> { 1077 fn is_high(&self) -> Result<bool, Self::Error> {
1001 Ok(self.is_high()) 1078 Ok(!self.ref_is_low())
1002 } 1079 }
1003 1080
1004 fn is_low(&self) -> Result<bool, Self::Error> { 1081 fn is_low(&self) -> Result<bool, Self::Error> {
1005 Ok(self.is_low()) 1082 Ok(self.ref_is_low())
1006 } 1083 }
1007 } 1084 }
1008 1085
@@ -1020,11 +1097,11 @@ mod eh02 {
1020 1097
1021 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { 1098 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> {
1022 fn is_set_high(&self) -> Result<bool, Self::Error> { 1099 fn is_set_high(&self) -> Result<bool, Self::Error> {
1023 Ok(self.is_set_high()) 1100 Ok(!self.ref_is_set_low())
1024 } 1101 }
1025 1102
1026 fn is_set_low(&self) -> Result<bool, Self::Error> { 1103 fn is_set_low(&self) -> Result<bool, Self::Error> {
1027 Ok(self.is_set_low()) 1104 Ok(self.ref_is_set_low())
1028 } 1105 }
1029 } 1106 }
1030 1107
@@ -1042,11 +1119,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
1042} 1119}
1043 1120
1044impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { 1121impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
1045 fn is_high(&self) -> Result<bool, Self::Error> { 1122 fn is_high(&mut self) -> Result<bool, Self::Error> {
1046 Ok(self.is_high()) 1123 Ok(self.is_high())
1047 } 1124 }
1048 1125
1049 fn is_low(&self) -> Result<bool, Self::Error> { 1126 fn is_low(&mut self) -> Result<bool, Self::Error> {
1050 Ok(self.is_low()) 1127 Ok(self.is_low())
1051 } 1128 }
1052} 1129}
@@ -1066,11 +1143,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
1066} 1143}
1067 1144
1068impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { 1145impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
1069 fn is_set_high(&self) -> Result<bool, Self::Error> { 1146 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1070 Ok(self.is_set_high()) 1147 Ok(self.is_set_high())
1071 } 1148 }
1072 1149
1073 fn is_set_low(&self) -> Result<bool, Self::Error> { 1150 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1074 Ok(self.is_set_low()) 1151 Ok(self.is_set_low())
1075 } 1152 }
1076} 1153}
@@ -1096,11 +1173,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> {
1096} 1173}
1097 1174
1098impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { 1175impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> {
1099 fn is_set_high(&self) -> Result<bool, Self::Error> { 1176 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1100 Ok(self.is_set_high()) 1177 Ok(self.is_set_high())
1101 } 1178 }
1102 1179
1103 fn is_set_low(&self) -> Result<bool, Self::Error> { 1180 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1104 Ok(self.is_set_low()) 1181 Ok(self.is_set_low())
1105 } 1182 }
1106} 1183}
@@ -1112,11 +1189,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrai
1112} 1189}
1113 1190
1114impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { 1191impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> {
1115 fn is_high(&self) -> Result<bool, Self::Error> { 1192 fn is_high(&mut self) -> Result<bool, Self::Error> {
1116 Ok(self.is_high()) 1193 Ok(self.is_high())
1117 } 1194 }
1118 1195
1119 fn is_low(&self) -> Result<bool, Self::Error> { 1196 fn is_low(&mut self) -> Result<bool, Self::Error> {
1120 Ok(self.is_low()) 1197 Ok(self.is_low())
1121 } 1198 }
1122} 1199}
@@ -1126,11 +1203,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
1126} 1203}
1127 1204
1128impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { 1205impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
1129 fn is_high(&self) -> Result<bool, Self::Error> { 1206 fn is_high(&mut self) -> Result<bool, Self::Error> {
1130 Ok(self.is_high()) 1207 Ok(self.is_high())
1131 } 1208 }
1132 1209
1133 fn is_low(&self) -> Result<bool, Self::Error> { 1210 fn is_low(&mut self) -> Result<bool, Self::Error> {
1134 Ok(self.is_low()) 1211 Ok(self.is_low())
1135 } 1212 }
1136} 1213}
@@ -1146,11 +1223,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
1146} 1223}
1147 1224
1148impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { 1225impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
1149 fn is_set_high(&self) -> Result<bool, Self::Error> { 1226 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1150 Ok(self.is_set_high()) 1227 Ok(self.is_set_high())
1151 } 1228 }
1152 1229
1153 fn is_set_low(&self) -> Result<bool, Self::Error> { 1230 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1154 Ok(self.is_set_low()) 1231 Ok(self.is_set_low())
1155 } 1232 }
1156} 1233}
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 15095236a..74d015792 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -1,3 +1,4 @@
1//! I2C driver.
1use core::future; 2use core::future;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::task::Poll; 4use core::task::Poll;
@@ -22,6 +23,7 @@ pub enum AbortReason {
22 ArbitrationLoss, 23 ArbitrationLoss,
23 /// Transmit ended with data still in fifo 24 /// Transmit ended with data still in fifo
24 TxNotEmpty(u16), 25 TxNotEmpty(u16),
26 /// Other reason.
25 Other(u32), 27 Other(u32),
26} 28}
27 29
@@ -41,9 +43,11 @@ pub enum Error {
41 AddressReserved(u16), 43 AddressReserved(u16),
42} 44}
43 45
46/// I2C config.
44#[non_exhaustive] 47#[non_exhaustive]
45#[derive(Copy, Clone)] 48#[derive(Copy, Clone)]
46pub struct Config { 49pub struct Config {
50 /// Frequency.
47 pub frequency: u32, 51 pub frequency: u32,
48} 52}
49 53
@@ -53,13 +57,16 @@ impl Default for Config {
53 } 57 }
54} 58}
55 59
60/// Size of I2C FIFO.
56pub const FIFO_SIZE: u8 = 16; 61pub const FIFO_SIZE: u8 = 16;
57 62
63/// I2C driver.
58pub struct I2c<'d, T: Instance, M: Mode> { 64pub struct I2c<'d, T: Instance, M: Mode> {
59 phantom: PhantomData<(&'d mut T, M)>, 65 phantom: PhantomData<(&'d mut T, M)>,
60} 66}
61 67
62impl<'d, T: Instance> I2c<'d, T, Blocking> { 68impl<'d, T: Instance> I2c<'d, T, Blocking> {
69 /// Create a new driver instance in blocking mode.
63 pub fn new_blocking( 70 pub fn new_blocking(
64 peri: impl Peripheral<P = T> + 'd, 71 peri: impl Peripheral<P = T> + 'd,
65 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 72 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
@@ -72,6 +79,7 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> {
72} 79}
73 80
74impl<'d, T: Instance> I2c<'d, T, Async> { 81impl<'d, T: Instance> I2c<'d, T, Async> {
82 /// Create a new driver instance in async mode.
75 pub fn new_async( 83 pub fn new_async(
76 peri: impl Peripheral<P = T> + 'd, 84 peri: impl Peripheral<P = T> + 'd,
77 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 85 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
@@ -292,16 +300,19 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
292 } 300 }
293 } 301 }
294 302
303 /// Read from address into buffer using DMA.
295 pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { 304 pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {
296 Self::setup(addr)?; 305 Self::setup(addr)?;
297 self.read_async_internal(buffer, true, true).await 306 self.read_async_internal(buffer, true, true).await
298 } 307 }
299 308
309 /// Write to address from buffer using DMA.
300 pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> { 310 pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> {
301 Self::setup(addr)?; 311 Self::setup(addr)?;
302 self.write_async_internal(bytes, true).await 312 self.write_async_internal(bytes, true).await
303 } 313 }
304 314
315 /// Write to address from bytes and read from address into buffer using DMA.
305 pub async fn write_read_async( 316 pub async fn write_read_async(
306 &mut self, 317 &mut self,
307 addr: u16, 318 addr: u16,
@@ -314,6 +325,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
314 } 325 }
315} 326}
316 327
328/// Interrupt handler.
317pub struct InterruptHandler<T: Instance> { 329pub struct InterruptHandler<T: Instance> {
318 _uart: PhantomData<T>, 330 _uart: PhantomData<T>,
319} 331}
@@ -569,17 +581,20 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
569 // Blocking public API 581 // Blocking public API
570 // ========================= 582 // =========================
571 583
584 /// Read from address into buffer blocking caller until done.
572 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { 585 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
573 Self::setup(address.into())?; 586 Self::setup(address.into())?;
574 self.read_blocking_internal(read, true, true) 587 self.read_blocking_internal(read, true, true)
575 // Automatic Stop 588 // Automatic Stop
576 } 589 }
577 590
591 /// Write to address from buffer blocking caller until done.
578 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 592 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
579 Self::setup(address.into())?; 593 Self::setup(address.into())?;
580 self.write_blocking_internal(write, true) 594 self.write_blocking_internal(write, true)
581 } 595 }
582 596
597 /// Write to address from bytes and read from address into buffer blocking caller until done.
583 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 598 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
584 Self::setup(address.into())?; 599 Self::setup(address.into())?;
585 self.write_blocking_internal(write, false)?; 600 self.write_blocking_internal(write, false)?;
@@ -742,6 +757,7 @@ where
742 } 757 }
743} 758}
744 759
760/// Check if address is reserved.
745pub fn i2c_reserved_addr(addr: u16) -> bool { 761pub fn i2c_reserved_addr(addr: u16) -> bool {
746 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 762 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0
747} 763}
@@ -768,6 +784,7 @@ mod sealed {
768 pub trait SclPin<T: Instance> {} 784 pub trait SclPin<T: Instance> {}
769} 785}
770 786
787/// Driver mode.
771pub trait Mode: sealed::Mode {} 788pub trait Mode: sealed::Mode {}
772 789
773macro_rules! impl_mode { 790macro_rules! impl_mode {
@@ -777,12 +794,15 @@ macro_rules! impl_mode {
777 }; 794 };
778} 795}
779 796
797/// Blocking mode.
780pub struct Blocking; 798pub struct Blocking;
799/// Async mode.
781pub struct Async; 800pub struct Async;
782 801
783impl_mode!(Blocking); 802impl_mode!(Blocking);
784impl_mode!(Async); 803impl_mode!(Async);
785 804
805/// I2C instance.
786pub trait Instance: sealed::Instance {} 806pub trait Instance: sealed::Instance {}
787 807
788macro_rules! impl_instance { 808macro_rules! impl_instance {
@@ -819,7 +839,9 @@ macro_rules! impl_instance {
819impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); 839impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33);
820impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); 840impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35);
821 841
842/// SDA pin.
822pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} 843pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {}
844/// SCL pin.
823pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} 845pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {}
824 846
825macro_rules! impl_pin { 847macro_rules! impl_pin {
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs
index 9271ede3a..721b7a1f6 100644
--- a/embassy-rp/src/i2c_slave.rs
+++ b/embassy-rp/src/i2c_slave.rs
@@ -1,3 +1,4 @@
1//! I2C slave driver.
1use core::future; 2use core::future;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::task::Poll; 4use core::task::Poll;
@@ -63,11 +64,13 @@ impl Default for Config {
63 } 64 }
64} 65}
65 66
67/// I2CSlave driver.
66pub struct I2cSlave<'d, T: Instance> { 68pub struct I2cSlave<'d, T: Instance> {
67 phantom: PhantomData<&'d mut T>, 69 phantom: PhantomData<&'d mut T>,
68} 70}
69 71
70impl<'d, T: Instance> I2cSlave<'d, T> { 72impl<'d, T: Instance> I2cSlave<'d, T> {
73 /// Create a new instance.
71 pub fn new( 74 pub fn new(
72 _peri: impl Peripheral<P = T> + 'd, 75 _peri: impl Peripheral<P = T> + 'd,
73 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 76 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 5151323a9..0a3714777 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -1,5 +1,10 @@
1#![no_std] 1#![no_std]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
5
6//! ## Feature flags
7#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
3 8
4// This mod MUST go first, so that the others see its macros. 9// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 10pub(crate) mod fmt;
@@ -31,9 +36,7 @@ pub mod usb;
31pub mod watchdog; 36pub mod watchdog;
32 37
33// PIO 38// PIO
34// TODO: move `pio_instr_util` and `relocate` to inside `pio`
35pub mod pio; 39pub mod pio;
36pub mod pio_instr_util;
37pub(crate) mod relocate; 40pub(crate) mod relocate;
38 41
39// Reexports 42// Reexports
@@ -247,7 +250,6 @@ select_bootloader! {
247/// # Usage 250/// # Usage
248/// 251///
249/// ```no_run 252/// ```no_run
250/// #![feature(type_alias_impl_trait)]
251/// use embassy_rp::install_core0_stack_guard; 253/// use embassy_rp::install_core0_stack_guard;
252/// use embassy_executor::{Executor, Spawner}; 254/// use embassy_executor::{Executor, Spawner};
253/// 255///
@@ -302,11 +304,14 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
302 Ok(()) 304 Ok(())
303} 305}
304 306
307/// HAL configuration for RP.
305pub mod config { 308pub mod config {
306 use crate::clocks::ClockConfig; 309 use crate::clocks::ClockConfig;
307 310
311 /// HAL configuration passed when initializing.
308 #[non_exhaustive] 312 #[non_exhaustive]
309 pub struct Config { 313 pub struct Config {
314 /// Clock configuration.
310 pub clocks: ClockConfig, 315 pub clocks: ClockConfig,
311 } 316 }
312 317
@@ -319,12 +324,18 @@ pub mod config {
319 } 324 }
320 325
321 impl Config { 326 impl Config {
327 /// Create a new configuration with the provided clock config.
322 pub fn new(clocks: ClockConfig) -> Self { 328 pub fn new(clocks: ClockConfig) -> Self {
323 Self { clocks } 329 Self { clocks }
324 } 330 }
325 } 331 }
326} 332}
327 333
334/// Initialize the `embassy-rp` HAL with the provided configuration.
335///
336/// This returns the peripheral singletons that can be used for creating drivers.
337///
338/// This should only be called once at startup, otherwise it panics.
328pub fn init(config: config::Config) -> Peripherals { 339pub fn init(config: config::Config) -> Peripherals {
329 // Do this first, so that it panics if user is calling `init` a second time 340 // Do this first, so that it panics if user is calling `init` a second time
330 // before doing anything important. 341 // before doing anything important.
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index 915761801..252f30dc1 100644
--- a/embassy-rp/src/multicore.rs
+++ b/embassy-rp/src/multicore.rs
@@ -11,7 +11,6 @@
11//! # Usage 11//! # Usage
12//! 12//!
13//! ```no_run 13//! ```no_run
14//! # #![feature(type_alias_impl_trait)]
15//! use embassy_rp::multicore::Stack; 14//! use embassy_rp::multicore::Stack;
16//! use static_cell::StaticCell; 15//! use static_cell::StaticCell;
17//! use embassy_executor::Executor; 16//! use embassy_executor::Executor;
diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio/instr.rs
index 25393b476..9a44088c6 100644
--- a/embassy-rp/src/pio_instr_util.rs
+++ b/embassy-rp/src/pio/instr.rs
@@ -1,7 +1,9 @@
1//! Instructions controlling the PIO.
1use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; 2use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination};
2 3
3use crate::pio::{Instance, StateMachine}; 4use crate::pio::{Instance, StateMachine};
4 5
6/// Set value of scratch register X.
5pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) { 7pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
6 const OUT: u16 = InstructionOperands::OUT { 8 const OUT: u16 = InstructionOperands::OUT {
7 destination: OutDestination::X, 9 destination: OutDestination::X,
@@ -12,6 +14,7 @@ pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
12 sm.exec_instr(OUT); 14 sm.exec_instr(OUT);
13} 15}
14 16
17/// Get value of scratch register X.
15pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 { 18pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
16 const IN: u16 = InstructionOperands::IN { 19 const IN: u16 = InstructionOperands::IN {
17 source: InSource::X, 20 source: InSource::X,
@@ -22,6 +25,7 @@ pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
22 sm.rx().pull() 25 sm.rx().pull()
23} 26}
24 27
28/// Set value of scratch register Y.
25pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) { 29pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
26 const OUT: u16 = InstructionOperands::OUT { 30 const OUT: u16 = InstructionOperands::OUT {
27 destination: OutDestination::Y, 31 destination: OutDestination::Y,
@@ -32,6 +36,7 @@ pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
32 sm.exec_instr(OUT); 36 sm.exec_instr(OUT);
33} 37}
34 38
39/// Get value of scratch register Y.
35pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 { 40pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
36 const IN: u16 = InstructionOperands::IN { 41 const IN: u16 = InstructionOperands::IN {
37 source: InSource::Y, 42 source: InSource::Y,
@@ -43,6 +48,7 @@ pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
43 sm.rx().pull() 48 sm.rx().pull()
44} 49}
45 50
51/// Set instruction for pindir destination.
46pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) { 52pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
47 let set: u16 = InstructionOperands::SET { 53 let set: u16 = InstructionOperands::SET {
48 destination: SetDestination::PINDIRS, 54 destination: SetDestination::PINDIRS,
@@ -52,6 +58,7 @@ pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<P
52 sm.exec_instr(set); 58 sm.exec_instr(set);
53} 59}
54 60
61/// Set instruction for pin destination.
55pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) { 62pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
56 let set: u16 = InstructionOperands::SET { 63 let set: u16 = InstructionOperands::SET {
57 destination: SetDestination::PINS, 64 destination: SetDestination::PINS,
@@ -61,6 +68,7 @@ pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO,
61 sm.exec_instr(set); 68 sm.exec_instr(set);
62} 69}
63 70
71/// Out instruction for pin destination.
64pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) { 72pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
65 const OUT: u16 = InstructionOperands::OUT { 73 const OUT: u16 = InstructionOperands::OUT {
66 destination: OutDestination::PINS, 74 destination: OutDestination::PINS,
@@ -70,6 +78,8 @@ pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<
70 sm.tx().push(data); 78 sm.tx().push(data);
71 sm.exec_instr(OUT); 79 sm.exec_instr(OUT);
72} 80}
81
82/// Out instruction for pindir destination.
73pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) { 83pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
74 const OUT: u16 = InstructionOperands::OUT { 84 const OUT: u16 = InstructionOperands::OUT {
75 destination: OutDestination::PINDIRS, 85 destination: OutDestination::PINDIRS,
@@ -80,6 +90,7 @@ pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachi
80 sm.exec_instr(OUT); 90 sm.exec_instr(OUT);
81} 91}
82 92
93/// Jump instruction to address.
83pub unsafe fn exec_jmp<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, to_addr: u8) { 94pub unsafe fn exec_jmp<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, to_addr: u8) {
84 let jmp: u16 = InstructionOperands::JMP { 95 let jmp: u16 = InstructionOperands::JMP {
85 address: to_addr, 96 address: to_addr,
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio/mod.rs
index 97dfce2e6..ca9795024 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio/mod.rs
@@ -1,3 +1,4 @@
1//! PIO driver.
1use core::future::Future; 2use core::future::Future;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::pin::Pin as FuturePin; 4use core::pin::Pin as FuturePin;
@@ -19,8 +20,11 @@ use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
19use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; 20use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
20use crate::pac::dma::vals::TreqSel; 21use crate::pac::dma::vals::TreqSel;
21use crate::relocate::RelocatedProgram; 22use crate::relocate::RelocatedProgram;
22use crate::{pac, peripherals, pio_instr_util, RegExt}; 23use crate::{pac, peripherals, RegExt};
23 24
25pub mod instr;
26
27/// Wakers for interrupts and FIFOs.
24pub struct Wakers([AtomicWaker; 12]); 28pub struct Wakers([AtomicWaker; 12]);
25 29
26impl Wakers { 30impl Wakers {
@@ -38,6 +42,7 @@ impl Wakers {
38 } 42 }
39} 43}
40 44
45/// FIFO config.
41#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] 46#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))] 47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43#[repr(u8)] 48#[repr(u8)]
@@ -51,6 +56,8 @@ pub enum FifoJoin {
51 TxOnly, 56 TxOnly,
52} 57}
53 58
59/// Shift direction.
60#[allow(missing_docs)]
54#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] 61#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))] 62#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56#[repr(u8)] 63#[repr(u8)]
@@ -60,6 +67,8 @@ pub enum ShiftDirection {
60 Left = 0, 67 Left = 0,
61} 68}
62 69
70/// Pin direction.
71#[allow(missing_docs)]
63#[derive(Clone, Copy, PartialEq, Eq, Debug)] 72#[derive(Clone, Copy, PartialEq, Eq, Debug)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))] 73#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65#[repr(u8)] 74#[repr(u8)]
@@ -68,12 +77,15 @@ pub enum Direction {
68 Out = 1, 77 Out = 1,
69} 78}
70 79
80/// Which fifo level to use in status check.
71#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] 81#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))] 82#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[repr(u8)] 83#[repr(u8)]
74pub enum StatusSource { 84pub enum StatusSource {
75 #[default] 85 #[default]
86 /// All-ones if TX FIFO level < N, otherwise all-zeroes.
76 TxFifoLevel = 0, 87 TxFifoLevel = 0,
88 /// All-ones if RX FIFO level < N, otherwise all-zeroes.
77 RxFifoLevel = 1, 89 RxFifoLevel = 1,
78} 90}
79 91
@@ -81,6 +93,7 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
81const TXNFULL_MASK: u32 = 1 << 4; 93const TXNFULL_MASK: u32 = 1 << 4;
82const SMIRQ_MASK: u32 = 1 << 8; 94const SMIRQ_MASK: u32 = 1 << 8;
83 95
96/// Interrupt handler for PIO.
84pub struct InterruptHandler<PIO: Instance> { 97pub struct InterruptHandler<PIO: Instance> {
85 _pio: PhantomData<PIO>, 98 _pio: PhantomData<PIO>,
86} 99}
@@ -105,6 +118,7 @@ pub struct FifoOutFuture<'a, 'd, PIO: Instance, const SM: usize> {
105} 118}
106 119
107impl<'a, 'd, PIO: Instance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> { 120impl<'a, 'd, PIO: Instance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> {
121 /// Create a new future waiting for TX-FIFO to become writable.
108 pub fn new(sm: &'a mut StateMachineTx<'d, PIO, SM>, value: u32) -> Self { 122 pub fn new(sm: &'a mut StateMachineTx<'d, PIO, SM>, value: u32) -> Self {
109 FifoOutFuture { sm_tx: sm, value } 123 FifoOutFuture { sm_tx: sm, value }
110 } 124 }
@@ -136,13 +150,14 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO,
136 } 150 }
137} 151}
138 152
139/// Future that waits for RX-FIFO to become readable 153/// Future that waits for RX-FIFO to become readable.
140#[must_use = "futures do nothing unless you `.await` or poll them"] 154#[must_use = "futures do nothing unless you `.await` or poll them"]
141pub struct FifoInFuture<'a, 'd, PIO: Instance, const SM: usize> { 155pub struct FifoInFuture<'a, 'd, PIO: Instance, const SM: usize> {
142 sm_rx: &'a mut StateMachineRx<'d, PIO, SM>, 156 sm_rx: &'a mut StateMachineRx<'d, PIO, SM>,
143} 157}
144 158
145impl<'a, 'd, PIO: Instance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> { 159impl<'a, 'd, PIO: Instance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> {
160 /// Create future that waits for RX-FIFO to become readable.
146 pub fn new(sm: &'a mut StateMachineRx<'d, PIO, SM>) -> Self { 161 pub fn new(sm: &'a mut StateMachineRx<'d, PIO, SM>) -> Self {
147 FifoInFuture { sm_rx: sm } 162 FifoInFuture { sm_rx: sm }
148 } 163 }
@@ -207,6 +222,7 @@ impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
207 } 222 }
208} 223}
209 224
225/// Type representing a PIO pin.
210pub struct Pin<'l, PIO: Instance> { 226pub struct Pin<'l, PIO: Instance> {
211 pin: PeripheralRef<'l, AnyPin>, 227 pin: PeripheralRef<'l, AnyPin>,
212 pio: PhantomData<PIO>, 228 pio: PhantomData<PIO>,
@@ -226,7 +242,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
226 }); 242 });
227 } 243 }
228 244
229 // Set the pin's slew rate. 245 /// Set the pin's slew rate.
230 #[inline] 246 #[inline]
231 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 247 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
232 self.pin.pad_ctrl().modify(|w| { 248 self.pin.pad_ctrl().modify(|w| {
@@ -251,6 +267,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
251 }); 267 });
252 } 268 }
253 269
270 /// Set the pin's input sync bypass.
254 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { 271 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
255 let mask = 1 << self.pin(); 272 let mask = 1 << self.pin();
256 if bypass { 273 if bypass {
@@ -260,28 +277,34 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
260 } 277 }
261 } 278 }
262 279
280 /// Get the underlying pin number.
263 pub fn pin(&self) -> u8 { 281 pub fn pin(&self) -> u8 {
264 self.pin._pin() 282 self.pin._pin()
265 } 283 }
266} 284}
267 285
286/// Type representing a state machine RX FIFO.
268pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> { 287pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> {
269 pio: PhantomData<&'d mut PIO>, 288 pio: PhantomData<&'d mut PIO>,
270} 289}
271 290
272impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { 291impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
292 /// Check if RX FIFO is empty.
273 pub fn empty(&self) -> bool { 293 pub fn empty(&self) -> bool {
274 PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 294 PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0
275 } 295 }
276 296
297 /// Check if RX FIFO is full.
277 pub fn full(&self) -> bool { 298 pub fn full(&self) -> bool {
278 PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 299 PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0
279 } 300 }
280 301
302 /// Check RX FIFO level.
281 pub fn level(&self) -> u8 { 303 pub fn level(&self) -> u8 {
282 (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f 304 (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f
283 } 305 }
284 306
307 /// Check if state machine has stalled on full RX FIFO.
285 pub fn stalled(&self) -> bool { 308 pub fn stalled(&self) -> bool {
286 let fdebug = PIO::PIO.fdebug(); 309 let fdebug = PIO::PIO.fdebug();
287 let ret = fdebug.read().rxstall() & (1 << SM) != 0; 310 let ret = fdebug.read().rxstall() & (1 << SM) != 0;
@@ -291,6 +314,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
291 ret 314 ret
292 } 315 }
293 316
317 /// Check if RX FIFO underflow (i.e. read-on-empty by the system) has occurred.
294 pub fn underflowed(&self) -> bool { 318 pub fn underflowed(&self) -> bool {
295 let fdebug = PIO::PIO.fdebug(); 319 let fdebug = PIO::PIO.fdebug();
296 let ret = fdebug.read().rxunder() & (1 << SM) != 0; 320 let ret = fdebug.read().rxunder() & (1 << SM) != 0;
@@ -300,10 +324,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
300 ret 324 ret
301 } 325 }
302 326
327 /// Pull data from RX FIFO.
303 pub fn pull(&mut self) -> u32 { 328 pub fn pull(&mut self) -> u32 {
304 PIO::PIO.rxf(SM).read() 329 PIO::PIO.rxf(SM).read()
305 } 330 }
306 331
332 /// Attempt pulling data from RX FIFO.
307 pub fn try_pull(&mut self) -> Option<u32> { 333 pub fn try_pull(&mut self) -> Option<u32> {
308 if self.empty() { 334 if self.empty() {
309 return None; 335 return None;
@@ -311,10 +337,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
311 Some(self.pull()) 337 Some(self.pull())
312 } 338 }
313 339
340 /// Wait for RX FIFO readable.
314 pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> { 341 pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> {
315 FifoInFuture::new(self) 342 FifoInFuture::new(self)
316 } 343 }
317 344
345 /// Prepare DMA transfer from RX FIFO.
318 pub fn dma_pull<'a, C: Channel, W: Word>( 346 pub fn dma_pull<'a, C: Channel, W: Word>(
319 &'a mut self, 347 &'a mut self,
320 ch: PeripheralRef<'a, C>, 348 ch: PeripheralRef<'a, C>,
@@ -340,22 +368,28 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
340 } 368 }
341} 369}
342 370
371/// Type representing a state machine TX FIFO.
343pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> { 372pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> {
344 pio: PhantomData<&'d mut PIO>, 373 pio: PhantomData<&'d mut PIO>,
345} 374}
346 375
347impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { 376impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
377 /// Check if TX FIFO is empty.
348 pub fn empty(&self) -> bool { 378 pub fn empty(&self) -> bool {
349 PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 379 PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0
350 } 380 }
381
382 /// Check if TX FIFO is full.
351 pub fn full(&self) -> bool { 383 pub fn full(&self) -> bool {
352 PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 384 PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0
353 } 385 }
354 386
387 /// Check TX FIFO level.
355 pub fn level(&self) -> u8 { 388 pub fn level(&self) -> u8 {
356 (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f 389 (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f
357 } 390 }
358 391
392 /// Check state machine has stalled on empty TX FIFO.
359 pub fn stalled(&self) -> bool { 393 pub fn stalled(&self) -> bool {
360 let fdebug = PIO::PIO.fdebug(); 394 let fdebug = PIO::PIO.fdebug();
361 let ret = fdebug.read().txstall() & (1 << SM) != 0; 395 let ret = fdebug.read().txstall() & (1 << SM) != 0;
@@ -365,6 +399,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
365 ret 399 ret
366 } 400 }
367 401
402 /// Check if FIFO overflowed.
368 pub fn overflowed(&self) -> bool { 403 pub fn overflowed(&self) -> bool {
369 let fdebug = PIO::PIO.fdebug(); 404 let fdebug = PIO::PIO.fdebug();
370 let ret = fdebug.read().txover() & (1 << SM) != 0; 405 let ret = fdebug.read().txover() & (1 << SM) != 0;
@@ -374,10 +409,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
374 ret 409 ret
375 } 410 }
376 411
412 /// Force push data to TX FIFO.
377 pub fn push(&mut self, v: u32) { 413 pub fn push(&mut self, v: u32) {
378 PIO::PIO.txf(SM).write_value(v); 414 PIO::PIO.txf(SM).write_value(v);
379 } 415 }
380 416
417 /// Attempt to push data to TX FIFO.
381 pub fn try_push(&mut self, v: u32) -> bool { 418 pub fn try_push(&mut self, v: u32) -> bool {
382 if self.full() { 419 if self.full() {
383 return false; 420 return false;
@@ -386,10 +423,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
386 true 423 true
387 } 424 }
388 425
426 /// Wait until FIFO is ready for writing.
389 pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> { 427 pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> {
390 FifoOutFuture::new(self, value) 428 FifoOutFuture::new(self, value)
391 } 429 }
392 430
431 /// Prepare a DMA transfer to TX FIFO.
393 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { 432 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
394 let pio_no = PIO::PIO_NO; 433 let pio_no = PIO::PIO_NO;
395 let p = ch.regs(); 434 let p = ch.regs();
@@ -411,6 +450,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
411 } 450 }
412} 451}
413 452
453/// A type representing a single PIO state machine.
414pub struct StateMachine<'d, PIO: Instance, const SM: usize> { 454pub struct StateMachine<'d, PIO: Instance, const SM: usize> {
415 rx: StateMachineRx<'d, PIO, SM>, 455 rx: StateMachineRx<'d, PIO, SM>,
416 tx: StateMachineTx<'d, PIO, SM>, 456 tx: StateMachineTx<'d, PIO, SM>,
@@ -430,52 +470,78 @@ fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) {
430 } 470 }
431} 471}
432 472
473/// PIO Execution config.
433#[derive(Clone, Copy, Default, Debug)] 474#[derive(Clone, Copy, Default, Debug)]
434#[cfg_attr(feature = "defmt", derive(defmt::Format))] 475#[cfg_attr(feature = "defmt", derive(defmt::Format))]
435#[non_exhaustive] 476#[non_exhaustive]
436pub struct ExecConfig { 477pub struct ExecConfig {
478 /// If true, the MSB of the Delay/Side-set instruction field is used as side-set enable, rather than a side-set data bit.
437 pub side_en: bool, 479 pub side_en: bool,
480 /// If true, side-set data is asserted to pin directions, instead of pin values.
438 pub side_pindir: bool, 481 pub side_pindir: bool,
482 /// Pin to trigger jump.
439 pub jmp_pin: u8, 483 pub jmp_pin: u8,
484 /// After reaching this address, execution is wrapped to wrap_bottom.
440 pub wrap_top: u8, 485 pub wrap_top: u8,
486 /// After reaching wrap_top, execution is wrapped to this address.
441 pub wrap_bottom: u8, 487 pub wrap_bottom: u8,
442} 488}
443 489
490/// PIO shift register config for input or output.
444#[derive(Clone, Copy, Default, Debug)] 491#[derive(Clone, Copy, Default, Debug)]
445#[cfg_attr(feature = "defmt", derive(defmt::Format))] 492#[cfg_attr(feature = "defmt", derive(defmt::Format))]
446pub struct ShiftConfig { 493pub struct ShiftConfig {
494 /// Number of bits shifted out of OSR before autopull.
447 pub threshold: u8, 495 pub threshold: u8,
496 /// Shift direction.
448 pub direction: ShiftDirection, 497 pub direction: ShiftDirection,
498 /// For output: Pull automatically output shift register is emptied.
499 /// For input: Push automatically when the input shift register is filled.
449 pub auto_fill: bool, 500 pub auto_fill: bool,
450} 501}
451 502
503/// PIO pin config.
452#[derive(Clone, Copy, Default, Debug)] 504#[derive(Clone, Copy, Default, Debug)]
453#[cfg_attr(feature = "defmt", derive(defmt::Format))] 505#[cfg_attr(feature = "defmt", derive(defmt::Format))]
454pub struct PinConfig { 506pub struct PinConfig {
507 /// The number of MSBs of the Delay/Side-set instruction field which are used for side-set.
455 pub sideset_count: u8, 508 pub sideset_count: u8,
509 /// The number of pins asserted by a SET. In the range 0 to 5 inclusive.
456 pub set_count: u8, 510 pub set_count: u8,
511 /// The number of pins asserted by an OUT PINS, OUT PINDIRS or MOV PINS instruction. In the range 0 to 32 inclusive.
457 pub out_count: u8, 512 pub out_count: u8,
513 /// The pin which is mapped to the least-significant bit of a state machine's IN data bus.
458 pub in_base: u8, 514 pub in_base: u8,
515 /// The lowest-numbered pin that will be affected by a side-set operation.
459 pub sideset_base: u8, 516 pub sideset_base: u8,
517 /// The lowest-numbered pin that will be affected by a SET PINS or SET PINDIRS instruction.
460 pub set_base: u8, 518 pub set_base: u8,
519 /// The lowest-numbered pin that will be affected by an OUT PINS, OUT PINDIRS or MOV PINS instruction.
461 pub out_base: u8, 520 pub out_base: u8,
462} 521}
463 522
523/// PIO config.
464#[derive(Clone, Copy, Debug)] 524#[derive(Clone, Copy, Debug)]
465pub struct Config<'d, PIO: Instance> { 525pub struct Config<'d, PIO: Instance> {
466 // CLKDIV 526 /// Clock divisor register for state machines.
467 pub clock_divider: FixedU32<U8>, 527 pub clock_divider: FixedU32<U8>,
468 // EXECCTRL 528 /// Which data bit to use for inline OUT enable.
469 pub out_en_sel: u8, 529 pub out_en_sel: u8,
530 /// Use a bit of OUT data as an auxiliary write enable When used in conjunction with OUT_STICKY.
470 pub inline_out_en: bool, 531 pub inline_out_en: bool,
532 /// Continuously assert the most recent OUT/SET to the pins.
471 pub out_sticky: bool, 533 pub out_sticky: bool,
534 /// Which source to use for checking status.
472 pub status_sel: StatusSource, 535 pub status_sel: StatusSource,
536 /// Status comparison level.
473 pub status_n: u8, 537 pub status_n: u8,
474 exec: ExecConfig, 538 exec: ExecConfig,
475 origin: Option<u8>, 539 origin: Option<u8>,
476 // SHIFTCTRL 540 /// Configure FIFO allocation.
477 pub fifo_join: FifoJoin, 541 pub fifo_join: FifoJoin,
542 /// Input shifting config.
478 pub shift_in: ShiftConfig, 543 pub shift_in: ShiftConfig,
544 /// Output shifting config.
479 pub shift_out: ShiftConfig, 545 pub shift_out: ShiftConfig,
480 // PINCTRL 546 // PINCTRL
481 pins: PinConfig, 547 pins: PinConfig,
@@ -505,16 +571,22 @@ impl<'d, PIO: Instance> Default for Config<'d, PIO> {
505} 571}
506 572
507impl<'d, PIO: Instance> Config<'d, PIO> { 573impl<'d, PIO: Instance> Config<'d, PIO> {
574 /// Get execution configuration.
508 pub fn get_exec(&self) -> ExecConfig { 575 pub fn get_exec(&self) -> ExecConfig {
509 self.exec 576 self.exec
510 } 577 }
578
579 /// Update execution configuration.
511 pub unsafe fn set_exec(&mut self, e: ExecConfig) { 580 pub unsafe fn set_exec(&mut self, e: ExecConfig) {
512 self.exec = e; 581 self.exec = e;
513 } 582 }
514 583
584 /// Get pin configuration.
515 pub fn get_pins(&self) -> PinConfig { 585 pub fn get_pins(&self) -> PinConfig {
516 self.pins 586 self.pins
517 } 587 }
588
589 /// Update pin configuration.
518 pub unsafe fn set_pins(&mut self, p: PinConfig) { 590 pub unsafe fn set_pins(&mut self, p: PinConfig) {
519 self.pins = p; 591 self.pins = p;
520 } 592 }
@@ -537,6 +609,7 @@ impl<'d, PIO: Instance> Config<'d, PIO> {
537 self.origin = Some(prog.origin); 609 self.origin = Some(prog.origin);
538 } 610 }
539 611
612 /// Set pin used to signal jump.
540 pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { 613 pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) {
541 self.exec.jmp_pin = pin.pin(); 614 self.exec.jmp_pin = pin.pin();
542 } 615 }
@@ -571,6 +644,7 @@ impl<'d, PIO: Instance> Config<'d, PIO> {
571} 644}
572 645
573impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { 646impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
647 /// Set the config for a given PIO state machine.
574 pub fn set_config(&mut self, config: &Config<'d, PIO>) { 648 pub fn set_config(&mut self, config: &Config<'d, PIO>) {
575 // sm expects 0 for 65536, truncation makes that happen 649 // sm expects 0 for 65536, truncation makes that happen
576 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536"); 650 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536");
@@ -617,7 +691,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
617 w.set_out_base(config.pins.out_base); 691 w.set_out_base(config.pins.out_base);
618 }); 692 });
619 if let Some(origin) = config.origin { 693 if let Some(origin) = config.origin {
620 unsafe { pio_instr_util::exec_jmp(self, origin) } 694 unsafe { instr::exec_jmp(self, origin) }
621 } 695 }
622 } 696 }
623 697
@@ -626,10 +700,13 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
626 PIO::PIO.sm(SM) 700 PIO::PIO.sm(SM)
627 } 701 }
628 702
703 /// Restart this state machine.
629 pub fn restart(&mut self) { 704 pub fn restart(&mut self) {
630 let mask = 1u8 << SM; 705 let mask = 1u8 << SM;
631 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); 706 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
632 } 707 }
708
709 /// Enable state machine.
633 pub fn set_enable(&mut self, enable: bool) { 710 pub fn set_enable(&mut self, enable: bool) {
634 let mask = 1u8 << SM; 711 let mask = 1u8 << SM;
635 if enable { 712 if enable {
@@ -639,10 +716,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
639 } 716 }
640 } 717 }
641 718
719 /// Check if state machine is enabled.
642 pub fn is_enabled(&self) -> bool { 720 pub fn is_enabled(&self) -> bool {
643 PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 721 PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0
644 } 722 }
645 723
724 /// Restart a state machine's clock divider from an initial phase of 0.
646 pub fn clkdiv_restart(&mut self) { 725 pub fn clkdiv_restart(&mut self) {
647 let mask = 1u8 << SM; 726 let mask = 1u8 << SM;
648 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); 727 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
@@ -690,6 +769,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
690 }); 769 });
691 } 770 }
692 771
772 /// Flush FIFOs for state machine.
693 pub fn clear_fifos(&mut self) { 773 pub fn clear_fifos(&mut self) {
694 // Toggle FJOIN_RX to flush FIFOs 774 // Toggle FJOIN_RX to flush FIFOs
695 let shiftctrl = Self::this_sm().shiftctrl(); 775 let shiftctrl = Self::this_sm().shiftctrl();
@@ -701,21 +781,31 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
701 }); 781 });
702 } 782 }
703 783
784 /// Instruct state machine to execute a given instructions
785 ///
786 /// SAFETY: The state machine must be in a state where executing
787 /// an arbitrary instruction does not crash it.
704 pub unsafe fn exec_instr(&mut self, instr: u16) { 788 pub unsafe fn exec_instr(&mut self, instr: u16) {
705 Self::this_sm().instr().write(|w| w.set_instr(instr)); 789 Self::this_sm().instr().write(|w| w.set_instr(instr));
706 } 790 }
707 791
792 /// Return a read handle for reading state machine outputs.
708 pub fn rx(&mut self) -> &mut StateMachineRx<'d, PIO, SM> { 793 pub fn rx(&mut self) -> &mut StateMachineRx<'d, PIO, SM> {
709 &mut self.rx 794 &mut self.rx
710 } 795 }
796
797 /// Return a handle for writing to inputs.
711 pub fn tx(&mut self) -> &mut StateMachineTx<'d, PIO, SM> { 798 pub fn tx(&mut self) -> &mut StateMachineTx<'d, PIO, SM> {
712 &mut self.tx 799 &mut self.tx
713 } 800 }
801
802 /// Return both read and write handles for the state machine.
714 pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) { 803 pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) {
715 (&mut self.rx, &mut self.tx) 804 (&mut self.rx, &mut self.tx)
716 } 805 }
717} 806}
718 807
808/// PIO handle.
719pub struct Common<'d, PIO: Instance> { 809pub struct Common<'d, PIO: Instance> {
720 instructions_used: u32, 810 instructions_used: u32,
721 pio: PhantomData<&'d mut PIO>, 811 pio: PhantomData<&'d mut PIO>,
@@ -727,18 +817,25 @@ impl<'d, PIO: Instance> Drop for Common<'d, PIO> {
727 } 817 }
728} 818}
729 819
820/// Memory of PIO instance.
730pub struct InstanceMemory<'d, PIO: Instance> { 821pub struct InstanceMemory<'d, PIO: Instance> {
731 used_mask: u32, 822 used_mask: u32,
732 pio: PhantomData<&'d mut PIO>, 823 pio: PhantomData<&'d mut PIO>,
733} 824}
734 825
826/// A loaded PIO program.
735pub struct LoadedProgram<'d, PIO: Instance> { 827pub struct LoadedProgram<'d, PIO: Instance> {
828 /// Memory used by program.
736 pub used_memory: InstanceMemory<'d, PIO>, 829 pub used_memory: InstanceMemory<'d, PIO>,
830 /// Program origin for loading.
737 pub origin: u8, 831 pub origin: u8,
832 /// Wrap controls what to do once program is done executing.
738 pub wrap: Wrap, 833 pub wrap: Wrap,
834 /// Data for 'side' set instruction parameters.
739 pub side_set: SideSet, 835 pub side_set: SideSet,
740} 836}
741 837
838/// Errors loading a PIO program.
742#[derive(Clone, Copy, PartialEq, Eq, Debug)] 839#[derive(Clone, Copy, PartialEq, Eq, Debug)]
743#[cfg_attr(feature = "defmt", derive(defmt::Format))] 840#[cfg_attr(feature = "defmt", derive(defmt::Format))]
744pub enum LoadError { 841pub enum LoadError {
@@ -834,6 +931,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
834 self.instructions_used &= !instrs.used_mask; 931 self.instructions_used &= !instrs.used_mask;
835 } 932 }
836 933
934 /// Bypass flipflop synchronizer on GPIO inputs.
837 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { 935 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
838 // this can interfere with per-pin bypass functions. splitting the 936 // this can interfere with per-pin bypass functions. splitting the
839 // modification is going to be fine since nothing that relies on 937 // modification is going to be fine since nothing that relies on
@@ -842,6 +940,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
842 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); 940 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
843 } 941 }
844 942
943 /// Get bypass configuration.
845 pub fn get_input_sync_bypass(&self) -> u32 { 944 pub fn get_input_sync_bypass(&self) -> u32 {
846 PIO::PIO.input_sync_bypass().read() 945 PIO::PIO.input_sync_bypass().read()
847 } 946 }
@@ -861,6 +960,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
861 } 960 }
862 } 961 }
863 962
963 /// Apply changes to all state machines in a batch.
864 pub fn apply_sm_batch(&mut self, f: impl FnOnce(&mut PioBatch<'d, PIO>)) { 964 pub fn apply_sm_batch(&mut self, f: impl FnOnce(&mut PioBatch<'d, PIO>)) {
865 let mut batch = PioBatch { 965 let mut batch = PioBatch {
866 clkdiv_restart: 0, 966 clkdiv_restart: 0,
@@ -878,6 +978,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
878 } 978 }
879} 979}
880 980
981/// Represents multiple state machines in a single type.
881pub struct PioBatch<'a, PIO: Instance> { 982pub struct PioBatch<'a, PIO: Instance> {
882 clkdiv_restart: u8, 983 clkdiv_restart: u8,
883 sm_restart: u8, 984 sm_restart: u8,
@@ -887,25 +988,25 @@ pub struct PioBatch<'a, PIO: Instance> {
887} 988}
888 989
889impl<'a, PIO: Instance> PioBatch<'a, PIO> { 990impl<'a, PIO: Instance> PioBatch<'a, PIO> {
890 pub fn restart_clockdiv<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) { 991 /// Restart a state machine's clock divider from an initial phase of 0.
891 self.clkdiv_restart |= 1 << SM;
892 }
893
894 pub fn restart<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) { 992 pub fn restart<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) {
895 self.clkdiv_restart |= 1 << SM; 993 self.clkdiv_restart |= 1 << SM;
896 } 994 }
897 995
996 /// Enable a specific state machine.
898 pub fn set_enable<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>, enable: bool) { 997 pub fn set_enable<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>, enable: bool) {
899 self.sm_enable_mask |= 1 << SM; 998 self.sm_enable_mask |= 1 << SM;
900 self.sm_enable |= (enable as u8) << SM; 999 self.sm_enable |= (enable as u8) << SM;
901 } 1000 }
902} 1001}
903 1002
1003/// Type representing a PIO interrupt.
904pub struct Irq<'d, PIO: Instance, const N: usize> { 1004pub struct Irq<'d, PIO: Instance, const N: usize> {
905 pio: PhantomData<&'d mut PIO>, 1005 pio: PhantomData<&'d mut PIO>,
906} 1006}
907 1007
908impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> { 1008impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> {
1009 /// Wait for an IRQ to fire.
909 pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> { 1010 pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> {
910 IrqFuture { 1011 IrqFuture {
911 pio: PhantomData, 1012 pio: PhantomData,
@@ -914,59 +1015,79 @@ impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> {
914 } 1015 }
915} 1016}
916 1017
1018/// Interrupt flags for a PIO instance.
917#[derive(Clone)] 1019#[derive(Clone)]
918pub struct IrqFlags<'d, PIO: Instance> { 1020pub struct IrqFlags<'d, PIO: Instance> {
919 pio: PhantomData<&'d mut PIO>, 1021 pio: PhantomData<&'d mut PIO>,
920} 1022}
921 1023
922impl<'d, PIO: Instance> IrqFlags<'d, PIO> { 1024impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
1025 /// Check if interrupt fired.
923 pub fn check(&self, irq_no: u8) -> bool { 1026 pub fn check(&self, irq_no: u8) -> bool {
924 assert!(irq_no < 8); 1027 assert!(irq_no < 8);
925 self.check_any(1 << irq_no) 1028 self.check_any(1 << irq_no)
926 } 1029 }
927 1030
1031 /// Check if any of the interrupts in the bitmap fired.
928 pub fn check_any(&self, irqs: u8) -> bool { 1032 pub fn check_any(&self, irqs: u8) -> bool {
929 PIO::PIO.irq().read().irq() & irqs != 0 1033 PIO::PIO.irq().read().irq() & irqs != 0
930 } 1034 }
931 1035
1036 /// Check if all interrupts have fired.
932 pub fn check_all(&self, irqs: u8) -> bool { 1037 pub fn check_all(&self, irqs: u8) -> bool {
933 PIO::PIO.irq().read().irq() & irqs == irqs 1038 PIO::PIO.irq().read().irq() & irqs == irqs
934 } 1039 }
935 1040
1041 /// Clear interrupt for interrupt number.
936 pub fn clear(&self, irq_no: usize) { 1042 pub fn clear(&self, irq_no: usize) {
937 assert!(irq_no < 8); 1043 assert!(irq_no < 8);
938 self.clear_all(1 << irq_no); 1044 self.clear_all(1 << irq_no);
939 } 1045 }
940 1046
1047 /// Clear all interrupts set in the bitmap.
941 pub fn clear_all(&self, irqs: u8) { 1048 pub fn clear_all(&self, irqs: u8) {
942 PIO::PIO.irq().write(|w| w.set_irq(irqs)) 1049 PIO::PIO.irq().write(|w| w.set_irq(irqs))
943 } 1050 }
944 1051
1052 /// Fire a given interrupt.
945 pub fn set(&self, irq_no: usize) { 1053 pub fn set(&self, irq_no: usize) {
946 assert!(irq_no < 8); 1054 assert!(irq_no < 8);
947 self.set_all(1 << irq_no); 1055 self.set_all(1 << irq_no);
948 } 1056 }
949 1057
1058 /// Fire all interrupts.
950 pub fn set_all(&self, irqs: u8) { 1059 pub fn set_all(&self, irqs: u8) {
951 PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) 1060 PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs))
952 } 1061 }
953} 1062}
954 1063
1064/// An instance of the PIO driver.
955pub struct Pio<'d, PIO: Instance> { 1065pub struct Pio<'d, PIO: Instance> {
1066 /// PIO handle.
956 pub common: Common<'d, PIO>, 1067 pub common: Common<'d, PIO>,
1068 /// PIO IRQ flags.
957 pub irq_flags: IrqFlags<'d, PIO>, 1069 pub irq_flags: IrqFlags<'d, PIO>,
1070 /// IRQ0 configuration.
958 pub irq0: Irq<'d, PIO, 0>, 1071 pub irq0: Irq<'d, PIO, 0>,
1072 /// IRQ1 configuration.
959 pub irq1: Irq<'d, PIO, 1>, 1073 pub irq1: Irq<'d, PIO, 1>,
1074 /// IRQ2 configuration.
960 pub irq2: Irq<'d, PIO, 2>, 1075 pub irq2: Irq<'d, PIO, 2>,
1076 /// IRQ3 configuration.
961 pub irq3: Irq<'d, PIO, 3>, 1077 pub irq3: Irq<'d, PIO, 3>,
1078 /// State machine 0 handle.
962 pub sm0: StateMachine<'d, PIO, 0>, 1079 pub sm0: StateMachine<'d, PIO, 0>,
1080 /// State machine 1 handle.
963 pub sm1: StateMachine<'d, PIO, 1>, 1081 pub sm1: StateMachine<'d, PIO, 1>,
1082 /// State machine 2 handle.
964 pub sm2: StateMachine<'d, PIO, 2>, 1083 pub sm2: StateMachine<'d, PIO, 2>,
1084 /// State machine 3 handle.
965 pub sm3: StateMachine<'d, PIO, 3>, 1085 pub sm3: StateMachine<'d, PIO, 3>,
966 _pio: PhantomData<&'d mut PIO>, 1086 _pio: PhantomData<&'d mut PIO>,
967} 1087}
968 1088
969impl<'d, PIO: Instance> Pio<'d, PIO> { 1089impl<'d, PIO: Instance> Pio<'d, PIO> {
1090 /// Create a new instance of a PIO peripheral.
970 pub fn new(_pio: impl Peripheral<P = PIO> + 'd, _irq: impl Binding<PIO::Interrupt, InterruptHandler<PIO>>) -> Self { 1091 pub fn new(_pio: impl Peripheral<P = PIO> + 'd, _irq: impl Binding<PIO::Interrupt, InterruptHandler<PIO>>) -> Self {
971 PIO::state().users.store(5, Ordering::Release); 1092 PIO::state().users.store(5, Ordering::Release);
972 PIO::state().used_pins.store(0, Ordering::Release); 1093 PIO::state().used_pins.store(0, Ordering::Release);
@@ -1003,9 +1124,10 @@ impl<'d, PIO: Instance> Pio<'d, PIO> {
1003 } 1124 }
1004} 1125}
1005 1126
1006// we need to keep a record of which pins are assigned to each PIO. make_pio_pin 1127/// Representation of the PIO state keeping a record of which pins are assigned to
1007// notionally takes ownership of the pin it is given, but the wrapped pin cannot 1128/// each PIO.
1008// be treated as an owned resource since dropping it would have to deconfigure 1129// make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin
1130// cannot be treated as an owned resource since dropping it would have to deconfigure
1009// the pin, breaking running state machines in the process. pins are also shared 1131// the pin, breaking running state machines in the process. pins are also shared
1010// between all state machines, which makes ownership even messier to track any 1132// between all state machines, which makes ownership even messier to track any
1011// other way. 1133// other way.
@@ -1059,6 +1181,7 @@ mod sealed {
1059 } 1181 }
1060} 1182}
1061 1183
1184/// PIO instance.
1062pub trait Instance: sealed::Instance + Sized + Unpin {} 1185pub trait Instance: sealed::Instance + Sized + Unpin {}
1063 1186
1064macro_rules! impl_pio { 1187macro_rules! impl_pio {
@@ -1076,6 +1199,7 @@ macro_rules! impl_pio {
1076impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0); 1199impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
1077impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); 1200impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
1078 1201
1202/// PIO pin.
1079pub trait PioPin: sealed::PioPin + gpio::Pin {} 1203pub trait PioPin: sealed::PioPin + gpio::Pin {}
1080 1204
1081macro_rules! impl_pio_pin { 1205macro_rules! impl_pio_pin {
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index 516b8254b..784a05f92 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -61,9 +61,13 @@ impl Default for Config {
61 } 61 }
62} 62}
63 63
64/// PWM input mode.
64pub enum InputMode { 65pub enum InputMode {
66 /// Level mode.
65 Level, 67 Level,
68 /// Rising edge mode.
66 RisingEdge, 69 RisingEdge,
70 /// Falling edge mode.
67 FallingEdge, 71 FallingEdge,
68} 72}
69 73
@@ -77,6 +81,7 @@ impl From<InputMode> for Divmode {
77 } 81 }
78} 82}
79 83
84/// PWM driver.
80pub struct Pwm<'d, T: Channel> { 85pub struct Pwm<'d, T: Channel> {
81 inner: PeripheralRef<'d, T>, 86 inner: PeripheralRef<'d, T>,
82 pin_a: Option<PeripheralRef<'d, AnyPin>>, 87 pin_a: Option<PeripheralRef<'d, AnyPin>>,
@@ -114,11 +119,13 @@ impl<'d, T: Channel> Pwm<'d, T> {
114 } 119 }
115 } 120 }
116 121
122 /// Create PWM driver without any configured pins.
117 #[inline] 123 #[inline]
118 pub fn new_free(inner: impl Peripheral<P = T> + 'd, config: Config) -> Self { 124 pub fn new_free(inner: impl Peripheral<P = T> + 'd, config: Config) -> Self {
119 Self::new_inner(inner, None, None, config, Divmode::DIV) 125 Self::new_inner(inner, None, None, config, Divmode::DIV)
120 } 126 }
121 127
128 /// Create PWM driver with a single 'a' as output.
122 #[inline] 129 #[inline]
123 pub fn new_output_a( 130 pub fn new_output_a(
124 inner: impl Peripheral<P = T> + 'd, 131 inner: impl Peripheral<P = T> + 'd,
@@ -129,6 +136,7 @@ impl<'d, T: Channel> Pwm<'d, T> {
129 Self::new_inner(inner, Some(a.map_into()), None, config, Divmode::DIV) 136 Self::new_inner(inner, Some(a.map_into()), None, config, Divmode::DIV)
130 } 137 }
131 138
139 /// Create PWM driver with a single 'b' pin as output.
132 #[inline] 140 #[inline]
133 pub fn new_output_b( 141 pub fn new_output_b(
134 inner: impl Peripheral<P = T> + 'd, 142 inner: impl Peripheral<P = T> + 'd,
@@ -139,6 +147,7 @@ impl<'d, T: Channel> Pwm<'d, T> {
139 Self::new_inner(inner, None, Some(b.map_into()), config, Divmode::DIV) 147 Self::new_inner(inner, None, Some(b.map_into()), config, Divmode::DIV)
140 } 148 }
141 149
150 /// Create PWM driver with a 'a' and 'b' pins as output.
142 #[inline] 151 #[inline]
143 pub fn new_output_ab( 152 pub fn new_output_ab(
144 inner: impl Peripheral<P = T> + 'd, 153 inner: impl Peripheral<P = T> + 'd,
@@ -150,6 +159,7 @@ impl<'d, T: Channel> Pwm<'d, T> {
150 Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, Divmode::DIV) 159 Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, Divmode::DIV)
151 } 160 }
152 161
162 /// Create PWM driver with a single 'b' as input pin.
153 #[inline] 163 #[inline]
154 pub fn new_input( 164 pub fn new_input(
155 inner: impl Peripheral<P = T> + 'd, 165 inner: impl Peripheral<P = T> + 'd,
@@ -161,6 +171,7 @@ impl<'d, T: Channel> Pwm<'d, T> {
161 Self::new_inner(inner, None, Some(b.map_into()), config, mode.into()) 171 Self::new_inner(inner, None, Some(b.map_into()), config, mode.into())
162 } 172 }
163 173
174 /// Create PWM driver with a 'a' and 'b' pins in the desired input mode.
164 #[inline] 175 #[inline]
165 pub fn new_output_input( 176 pub fn new_output_input(
166 inner: impl Peripheral<P = T> + 'd, 177 inner: impl Peripheral<P = T> + 'd,
@@ -173,6 +184,7 @@ impl<'d, T: Channel> Pwm<'d, T> {
173 Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, mode.into()) 184 Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, mode.into())
174 } 185 }
175 186
187 /// Set the PWM config.
176 pub fn set_config(&mut self, config: &Config) { 188 pub fn set_config(&mut self, config: &Config) {
177 Self::configure(self.inner.regs(), config); 189 Self::configure(self.inner.regs(), config);
178 } 190 }
@@ -216,28 +228,33 @@ impl<'d, T: Channel> Pwm<'d, T> {
216 while p.csr().read().ph_ret() {} 228 while p.csr().read().ph_ret() {}
217 } 229 }
218 230
231 /// Read PWM counter.
219 #[inline] 232 #[inline]
220 pub fn counter(&self) -> u16 { 233 pub fn counter(&self) -> u16 {
221 self.inner.regs().ctr().read().ctr() 234 self.inner.regs().ctr().read().ctr()
222 } 235 }
223 236
237 /// Write PWM counter.
224 #[inline] 238 #[inline]
225 pub fn set_counter(&self, ctr: u16) { 239 pub fn set_counter(&self, ctr: u16) {
226 self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) 240 self.inner.regs().ctr().write(|w| w.set_ctr(ctr))
227 } 241 }
228 242
243 /// Wait for channel interrupt.
229 #[inline] 244 #[inline]
230 pub fn wait_for_wrap(&mut self) { 245 pub fn wait_for_wrap(&mut self) {
231 while !self.wrapped() {} 246 while !self.wrapped() {}
232 self.clear_wrapped(); 247 self.clear_wrapped();
233 } 248 }
234 249
250 /// Check if interrupt for channel is set.
235 #[inline] 251 #[inline]
236 pub fn wrapped(&mut self) -> bool { 252 pub fn wrapped(&mut self) -> bool {
237 pac::PWM.intr().read().0 & self.bit() != 0 253 pac::PWM.intr().read().0 & self.bit() != 0
238 } 254 }
239 255
240 #[inline] 256 #[inline]
257 /// Clear interrupt flag.
241 pub fn clear_wrapped(&mut self) { 258 pub fn clear_wrapped(&mut self) {
242 pac::PWM.intr().write_value(Intr(self.bit() as _)); 259 pac::PWM.intr().write_value(Intr(self.bit() as _));
243 } 260 }
@@ -248,15 +265,18 @@ impl<'d, T: Channel> Pwm<'d, T> {
248 } 265 }
249} 266}
250 267
268/// Batch representation of PWM channels.
251pub struct PwmBatch(u32); 269pub struct PwmBatch(u32);
252 270
253impl PwmBatch { 271impl PwmBatch {
254 #[inline] 272 #[inline]
273 /// Enable a PWM channel in this batch.
255 pub fn enable(&mut self, pwm: &Pwm<'_, impl Channel>) { 274 pub fn enable(&mut self, pwm: &Pwm<'_, impl Channel>) {
256 self.0 |= pwm.bit(); 275 self.0 |= pwm.bit();
257 } 276 }
258 277
259 #[inline] 278 #[inline]
279 /// Enable channels in this batch in a PWM.
260 pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { 280 pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) {
261 let mut en = PwmBatch(0); 281 let mut en = PwmBatch(0);
262 batch(&mut en); 282 batch(&mut en);
@@ -284,9 +304,12 @@ mod sealed {
284 pub trait Channel {} 304 pub trait Channel {}
285} 305}
286 306
307/// PWM Channel.
287pub trait Channel: Peripheral<P = Self> + sealed::Channel + Sized + 'static { 308pub trait Channel: Peripheral<P = Self> + sealed::Channel + Sized + 'static {
309 /// Channel number.
288 fn number(&self) -> u8; 310 fn number(&self) -> u8;
289 311
312 /// Channel register block.
290 fn regs(&self) -> pac::pwm::Channel { 313 fn regs(&self) -> pac::pwm::Channel {
291 pac::PWM.ch(self.number() as _) 314 pac::PWM.ch(self.number() as _)
292 } 315 }
@@ -312,7 +335,9 @@ channel!(PWM_CH5, 5);
312channel!(PWM_CH6, 6); 335channel!(PWM_CH6, 6);
313channel!(PWM_CH7, 7); 336channel!(PWM_CH7, 7);
314 337
338/// PWM Pin A.
315pub trait PwmPinA<T: Channel>: GpioPin {} 339pub trait PwmPinA<T: Channel>: GpioPin {}
340/// PWM Pin B.
316pub trait PwmPinB<T: Channel>: GpioPin {} 341pub trait PwmPinB<T: Channel>: GpioPin {}
317 342
318macro_rules! impl_pin { 343macro_rules! impl_pin {
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index 60ca8627b..b696989f5 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -1,3 +1,4 @@
1//! RTC driver.
1mod filter; 2mod filter;
2 3
3use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
@@ -194,6 +195,7 @@ mod sealed {
194 } 195 }
195} 196}
196 197
198/// RTC peripheral instance.
197pub trait Instance: sealed::Instance {} 199pub trait Instance: sealed::Instance {}
198 200
199impl sealed::Instance for crate::peripherals::RTC { 201impl sealed::Instance for crate::peripherals::RTC {
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 6ba985a65..a2a22ffe5 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -11,6 +11,7 @@ use crate::gpio::sealed::Pin as _;
11use crate::gpio::{AnyPin, Pin as GpioPin}; 11use crate::gpio::{AnyPin, Pin as GpioPin};
12use crate::{pac, peripherals, Peripheral}; 12use crate::{pac, peripherals, Peripheral};
13 13
14/// SPI errors.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)] 15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))] 16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[non_exhaustive] 17#[non_exhaustive]
@@ -18,11 +19,15 @@ pub enum Error {
18 // No errors for now 19 // No errors for now
19} 20}
20 21
22/// SPI configuration.
21#[non_exhaustive] 23#[non_exhaustive]
22#[derive(Clone)] 24#[derive(Clone)]
23pub struct Config { 25pub struct Config {
26 /// Frequency.
24 pub frequency: u32, 27 pub frequency: u32,
28 /// Phase.
25 pub phase: Phase, 29 pub phase: Phase,
30 /// Polarity.
26 pub polarity: Polarity, 31 pub polarity: Polarity,
27} 32}
28 33
@@ -36,6 +41,7 @@ impl Default for Config {
36 } 41 }
37} 42}
38 43
44/// SPI driver.
39pub struct Spi<'d, T: Instance, M: Mode> { 45pub struct Spi<'d, T: Instance, M: Mode> {
40 inner: PeripheralRef<'d, T>, 46 inner: PeripheralRef<'d, T>,
41 tx_dma: Option<PeripheralRef<'d, AnyChannel>>, 47 tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
@@ -119,6 +125,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
119 } 125 }
120 } 126 }
121 127
128 /// Write data to SPI blocking execution until done.
122 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { 129 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
123 let p = self.inner.regs(); 130 let p = self.inner.regs();
124 for &b in data { 131 for &b in data {
@@ -131,6 +138,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
131 Ok(()) 138 Ok(())
132 } 139 }
133 140
141 /// Transfer data in place to SPI blocking execution until done.
134 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { 142 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
135 let p = self.inner.regs(); 143 let p = self.inner.regs();
136 for b in data { 144 for b in data {
@@ -143,6 +151,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
143 Ok(()) 151 Ok(())
144 } 152 }
145 153
154 /// Read data from SPI blocking execution until done.
146 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { 155 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
147 let p = self.inner.regs(); 156 let p = self.inner.regs();
148 for b in data { 157 for b in data {
@@ -155,6 +164,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
155 Ok(()) 164 Ok(())
156 } 165 }
157 166
167 /// Transfer data to SPI blocking execution until done.
158 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { 168 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
159 let p = self.inner.regs(); 169 let p = self.inner.regs();
160 let len = read.len().max(write.len()); 170 let len = read.len().max(write.len());
@@ -172,12 +182,14 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
172 Ok(()) 182 Ok(())
173 } 183 }
174 184
185 /// Block execution until SPI is done.
175 pub fn flush(&mut self) -> Result<(), Error> { 186 pub fn flush(&mut self) -> Result<(), Error> {
176 let p = self.inner.regs(); 187 let p = self.inner.regs();
177 while p.sr().read().bsy() {} 188 while p.sr().read().bsy() {}
178 Ok(()) 189 Ok(())
179 } 190 }
180 191
192 /// Set SPI frequency.
181 pub fn set_frequency(&mut self, freq: u32) { 193 pub fn set_frequency(&mut self, freq: u32) {
182 let (presc, postdiv) = calc_prescs(freq); 194 let (presc, postdiv) = calc_prescs(freq);
183 let p = self.inner.regs(); 195 let p = self.inner.regs();
@@ -196,6 +208,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
196} 208}
197 209
198impl<'d, T: Instance> Spi<'d, T, Blocking> { 210impl<'d, T: Instance> Spi<'d, T, Blocking> {
211 /// Create an SPI driver in blocking mode.
199 pub fn new_blocking( 212 pub fn new_blocking(
200 inner: impl Peripheral<P = T> + 'd, 213 inner: impl Peripheral<P = T> + 'd,
201 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 214 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -216,6 +229,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
216 ) 229 )
217 } 230 }
218 231
232 /// Create an SPI driver in blocking mode supporting writes only.
219 pub fn new_blocking_txonly( 233 pub fn new_blocking_txonly(
220 inner: impl Peripheral<P = T> + 'd, 234 inner: impl Peripheral<P = T> + 'd,
221 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 235 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -235,6 +249,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
235 ) 249 )
236 } 250 }
237 251
252 /// Create an SPI driver in blocking mode supporting reads only.
238 pub fn new_blocking_rxonly( 253 pub fn new_blocking_rxonly(
239 inner: impl Peripheral<P = T> + 'd, 254 inner: impl Peripheral<P = T> + 'd,
240 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 255 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -256,6 +271,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
256} 271}
257 272
258impl<'d, T: Instance> Spi<'d, T, Async> { 273impl<'d, T: Instance> Spi<'d, T, Async> {
274 /// Create an SPI driver in async mode supporting DMA operations.
259 pub fn new( 275 pub fn new(
260 inner: impl Peripheral<P = T> + 'd, 276 inner: impl Peripheral<P = T> + 'd,
261 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 277 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -278,6 +294,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
278 ) 294 )
279 } 295 }
280 296
297 /// Create an SPI driver in async mode supporting DMA write operations only.
281 pub fn new_txonly( 298 pub fn new_txonly(
282 inner: impl Peripheral<P = T> + 'd, 299 inner: impl Peripheral<P = T> + 'd,
283 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 300 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -298,6 +315,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
298 ) 315 )
299 } 316 }
300 317
318 /// Create an SPI driver in async mode supporting DMA read operations only.
301 pub fn new_rxonly( 319 pub fn new_rxonly(
302 inner: impl Peripheral<P = T> + 'd, 320 inner: impl Peripheral<P = T> + 'd,
303 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 321 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -318,6 +336,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
318 ) 336 )
319 } 337 }
320 338
339 /// Write data to SPI using DMA.
321 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 340 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
322 let tx_ch = self.tx_dma.as_mut().unwrap(); 341 let tx_ch = self.tx_dma.as_mut().unwrap();
323 let tx_transfer = unsafe { 342 let tx_transfer = unsafe {
@@ -340,6 +359,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
340 Ok(()) 359 Ok(())
341 } 360 }
342 361
362 /// Read data from SPI using DMA.
343 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 363 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
344 // Start RX first. Transfer starts when TX starts, if RX 364 // Start RX first. Transfer starts when TX starts, if RX
345 // is not started yet we might lose bytes. 365 // is not started yet we might lose bytes.
@@ -365,10 +385,12 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
365 Ok(()) 385 Ok(())
366 } 386 }
367 387
388 /// Transfer data to SPI using DMA.
368 pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> { 389 pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> {
369 self.transfer_inner(rx_buffer, tx_buffer).await 390 self.transfer_inner(rx_buffer, tx_buffer).await
370 } 391 }
371 392
393 /// Transfer data in place to SPI using DMA.
372 pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> { 394 pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
373 self.transfer_inner(words, words).await 395 self.transfer_inner(words, words).await
374 } 396 }
@@ -434,7 +456,10 @@ mod sealed {
434 } 456 }
435} 457}
436 458
459/// Mode.
437pub trait Mode: sealed::Mode {} 460pub trait Mode: sealed::Mode {}
461
462/// SPI instance trait.
438pub trait Instance: sealed::Instance {} 463pub trait Instance: sealed::Instance {}
439 464
440macro_rules! impl_instance { 465macro_rules! impl_instance {
@@ -454,9 +479,13 @@ macro_rules! impl_instance {
454impl_instance!(SPI0, Spi0, 16, 17); 479impl_instance!(SPI0, Spi0, 16, 17);
455impl_instance!(SPI1, Spi1, 18, 19); 480impl_instance!(SPI1, Spi1, 18, 19);
456 481
482/// CLK pin.
457pub trait ClkPin<T: Instance>: GpioPin {} 483pub trait ClkPin<T: Instance>: GpioPin {}
484/// CS pin.
458pub trait CsPin<T: Instance>: GpioPin {} 485pub trait CsPin<T: Instance>: GpioPin {}
486/// MOSI pin.
459pub trait MosiPin<T: Instance>: GpioPin {} 487pub trait MosiPin<T: Instance>: GpioPin {}
488/// MISO pin.
460pub trait MisoPin<T: Instance>: GpioPin {} 489pub trait MisoPin<T: Instance>: GpioPin {}
461 490
462macro_rules! impl_pin { 491macro_rules! impl_pin {
@@ -503,7 +532,9 @@ macro_rules! impl_mode {
503 }; 532 };
504} 533}
505 534
535/// Blocking mode.
506pub struct Blocking; 536pub struct Blocking;
537/// Async mode.
507pub struct Async; 538pub struct Async;
508 539
509impl_mode!(Blocking); 540impl_mode!(Blocking);
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index faa8df037..69c0c85b1 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -1,3 +1,4 @@
1//! Timer driver.
1use core::cell::Cell; 2use core::cell::Cell;
2 3
3use atomic_polyfill::{AtomicU8, Ordering}; 4use atomic_polyfill::{AtomicU8, Ordering};
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index ca030f560..99c958129 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -1,3 +1,4 @@
1//! Buffered UART driver.
1use core::future::{poll_fn, Future}; 2use core::future::{poll_fn, Future};
2use core::slice; 3use core::slice;
3use core::task::Poll; 4use core::task::Poll;
@@ -38,15 +39,18 @@ impl State {
38 } 39 }
39} 40}
40 41
42/// Buffered UART driver.
41pub struct BufferedUart<'d, T: Instance> { 43pub struct BufferedUart<'d, T: Instance> {
42 pub(crate) rx: BufferedUartRx<'d, T>, 44 pub(crate) rx: BufferedUartRx<'d, T>,
43 pub(crate) tx: BufferedUartTx<'d, T>, 45 pub(crate) tx: BufferedUartTx<'d, T>,
44} 46}
45 47
48/// Buffered UART RX handle.
46pub struct BufferedUartRx<'d, T: Instance> { 49pub struct BufferedUartRx<'d, T: Instance> {
47 pub(crate) phantom: PhantomData<&'d mut T>, 50 pub(crate) phantom: PhantomData<&'d mut T>,
48} 51}
49 52
53/// Buffered UART TX handle.
50pub struct BufferedUartTx<'d, T: Instance> { 54pub struct BufferedUartTx<'d, T: Instance> {
51 pub(crate) phantom: PhantomData<&'d mut T>, 55 pub(crate) phantom: PhantomData<&'d mut T>,
52} 56}
@@ -84,6 +88,7 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
84} 88}
85 89
86impl<'d, T: Instance> BufferedUart<'d, T> { 90impl<'d, T: Instance> BufferedUart<'d, T> {
91 /// Create a buffered UART instance.
87 pub fn new( 92 pub fn new(
88 _uart: impl Peripheral<P = T> + 'd, 93 _uart: impl Peripheral<P = T> + 'd,
89 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 94 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -104,6 +109,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
104 } 109 }
105 } 110 }
106 111
112 /// Create a buffered UART instance with flow control.
107 pub fn new_with_rtscts( 113 pub fn new_with_rtscts(
108 _uart: impl Peripheral<P = T> + 'd, 114 _uart: impl Peripheral<P = T> + 'd,
109 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 115 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -132,32 +138,39 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
132 } 138 }
133 } 139 }
134 140
141 /// Write to UART TX buffer blocking execution until done.
135 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<usize, Error> { 142 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<usize, Error> {
136 self.tx.blocking_write(buffer) 143 self.tx.blocking_write(buffer)
137 } 144 }
138 145
146 /// Flush UART TX blocking execution until done.
139 pub fn blocking_flush(&mut self) -> Result<(), Error> { 147 pub fn blocking_flush(&mut self) -> Result<(), Error> {
140 self.tx.blocking_flush() 148 self.tx.blocking_flush()
141 } 149 }
142 150
151 /// Read from UART RX buffer blocking execution until done.
143 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 152 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
144 self.rx.blocking_read(buffer) 153 self.rx.blocking_read(buffer)
145 } 154 }
146 155
156 /// Check if UART is busy transmitting.
147 pub fn busy(&self) -> bool { 157 pub fn busy(&self) -> bool {
148 self.tx.busy() 158 self.tx.busy()
149 } 159 }
150 160
161 /// Wait until TX is empty and send break condition.
151 pub async fn send_break(&mut self, bits: u32) { 162 pub async fn send_break(&mut self, bits: u32) {
152 self.tx.send_break(bits).await 163 self.tx.send_break(bits).await
153 } 164 }
154 165
166 /// Split into separate RX and TX handles.
155 pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { 167 pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) {
156 (self.rx, self.tx) 168 (self.rx, self.tx)
157 } 169 }
158} 170}
159 171
160impl<'d, T: Instance> BufferedUartRx<'d, T> { 172impl<'d, T: Instance> BufferedUartRx<'d, T> {
173 /// Create a new buffered UART RX.
161 pub fn new( 174 pub fn new(
162 _uart: impl Peripheral<P = T> + 'd, 175 _uart: impl Peripheral<P = T> + 'd,
163 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 176 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -173,6 +186,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
173 Self { phantom: PhantomData } 186 Self { phantom: PhantomData }
174 } 187 }
175 188
189 /// Create a new buffered UART RX with flow control.
176 pub fn new_with_rts( 190 pub fn new_with_rts(
177 _uart: impl Peripheral<P = T> + 'd, 191 _uart: impl Peripheral<P = T> + 'd,
178 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 192 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -253,6 +267,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
253 Poll::Ready(result) 267 Poll::Ready(result)
254 } 268 }
255 269
270 /// Read from UART RX buffer blocking execution until done.
256 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 271 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
257 loop { 272 loop {
258 match Self::try_read(buf) { 273 match Self::try_read(buf) {
@@ -303,6 +318,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
303} 318}
304 319
305impl<'d, T: Instance> BufferedUartTx<'d, T> { 320impl<'d, T: Instance> BufferedUartTx<'d, T> {
321 /// Create a new buffered UART TX.
306 pub fn new( 322 pub fn new(
307 _uart: impl Peripheral<P = T> + 'd, 323 _uart: impl Peripheral<P = T> + 'd,
308 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 324 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -318,6 +334,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
318 Self { phantom: PhantomData } 334 Self { phantom: PhantomData }
319 } 335 }
320 336
337 /// Create a new buffered UART TX with flow control.
321 pub fn new_with_cts( 338 pub fn new_with_cts(
322 _uart: impl Peripheral<P = T> + 'd, 339 _uart: impl Peripheral<P = T> + 'd,
323 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 340 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -373,6 +390,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
373 }) 390 })
374 } 391 }
375 392
393 /// Write to UART TX buffer blocking execution until done.
376 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<usize, Error> { 394 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
377 if buf.is_empty() { 395 if buf.is_empty() {
378 return Ok(0); 396 return Ok(0);
@@ -398,6 +416,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
398 } 416 }
399 } 417 }
400 418
419 /// Flush UART TX blocking execution until done.
401 pub fn blocking_flush(&mut self) -> Result<(), Error> { 420 pub fn blocking_flush(&mut self) -> Result<(), Error> {
402 loop { 421 loop {
403 let state = T::buffered_state(); 422 let state = T::buffered_state();
@@ -407,6 +426,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
407 } 426 }
408 } 427 }
409 428
429 /// Check if UART is busy.
410 pub fn busy(&self) -> bool { 430 pub fn busy(&self) -> bool {
411 T::regs().uartfr().read().busy() 431 T::regs().uartfr().read().busy()
412 } 432 }
@@ -466,6 +486,7 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
466 } 486 }
467} 487}
468 488
489/// Interrupt handler.
469pub struct BufferedInterruptHandler<T: Instance> { 490pub struct BufferedInterruptHandler<T: Instance> {
470 _uart: PhantomData<T>, 491 _uart: PhantomData<T>,
471} 492}
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 18705b141..99fce0fc9 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -1,3 +1,4 @@
1//! UART driver.
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::task::Poll; 4use core::task::Poll;
@@ -20,11 +21,16 @@ use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
20mod buffered; 21mod buffered;
21pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx}; 22pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx};
22 23
24/// Word length.
23#[derive(Clone, Copy, PartialEq, Eq, Debug)] 25#[derive(Clone, Copy, PartialEq, Eq, Debug)]
24pub enum DataBits { 26pub enum DataBits {
27 /// 5 bits.
25 DataBits5, 28 DataBits5,
29 /// 6 bits.
26 DataBits6, 30 DataBits6,
31 /// 7 bits.
27 DataBits7, 32 DataBits7,
33 /// 8 bits.
28 DataBits8, 34 DataBits8,
29} 35}
30 36
@@ -39,13 +45,18 @@ impl DataBits {
39 } 45 }
40} 46}
41 47
48/// Parity bit.
42#[derive(Clone, Copy, PartialEq, Eq, Debug)] 49#[derive(Clone, Copy, PartialEq, Eq, Debug)]
43pub enum Parity { 50pub enum Parity {
51 /// No parity.
44 ParityNone, 52 ParityNone,
53 /// Even parity.
45 ParityEven, 54 ParityEven,
55 /// Odd parity.
46 ParityOdd, 56 ParityOdd,
47} 57}
48 58
59/// Stop bits.
49#[derive(Clone, Copy, PartialEq, Eq, Debug)] 60#[derive(Clone, Copy, PartialEq, Eq, Debug)]
50pub enum StopBits { 61pub enum StopBits {
51 #[doc = "1 stop bit"] 62 #[doc = "1 stop bit"]
@@ -54,20 +65,25 @@ pub enum StopBits {
54 STOP2, 65 STOP2,
55} 66}
56 67
68/// UART config.
57#[non_exhaustive] 69#[non_exhaustive]
58#[derive(Clone, Copy, PartialEq, Eq, Debug)] 70#[derive(Clone, Copy, PartialEq, Eq, Debug)]
59pub struct Config { 71pub struct Config {
72 /// Baud rate.
60 pub baudrate: u32, 73 pub baudrate: u32,
74 /// Word length.
61 pub data_bits: DataBits, 75 pub data_bits: DataBits,
76 /// Stop bits.
62 pub stop_bits: StopBits, 77 pub stop_bits: StopBits,
78 /// Parity bit.
63 pub parity: Parity, 79 pub parity: Parity,
64 /// Invert the tx pin output 80 /// Invert the tx pin output
65 pub invert_tx: bool, 81 pub invert_tx: bool,
66 /// Invert the rx pin input 82 /// Invert the rx pin input
67 pub invert_rx: bool, 83 pub invert_rx: bool,
68 // Invert the rts pin 84 /// Invert the rts pin
69 pub invert_rts: bool, 85 pub invert_rts: bool,
70 // Invert the cts pin 86 /// Invert the cts pin
71 pub invert_cts: bool, 87 pub invert_cts: bool,
72} 88}
73 89
@@ -102,21 +118,25 @@ pub enum Error {
102 Framing, 118 Framing,
103} 119}
104 120
121/// Internal DMA state of UART RX.
105pub struct DmaState { 122pub struct DmaState {
106 rx_err_waker: AtomicWaker, 123 rx_err_waker: AtomicWaker,
107 rx_errs: AtomicU16, 124 rx_errs: AtomicU16,
108} 125}
109 126
127/// UART driver.
110pub struct Uart<'d, T: Instance, M: Mode> { 128pub struct Uart<'d, T: Instance, M: Mode> {
111 tx: UartTx<'d, T, M>, 129 tx: UartTx<'d, T, M>,
112 rx: UartRx<'d, T, M>, 130 rx: UartRx<'d, T, M>,
113} 131}
114 132
133/// UART TX driver.
115pub struct UartTx<'d, T: Instance, M: Mode> { 134pub struct UartTx<'d, T: Instance, M: Mode> {
116 tx_dma: Option<PeripheralRef<'d, AnyChannel>>, 135 tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
117 phantom: PhantomData<(&'d mut T, M)>, 136 phantom: PhantomData<(&'d mut T, M)>,
118} 137}
119 138
139/// UART RX driver.
120pub struct UartRx<'d, T: Instance, M: Mode> { 140pub struct UartRx<'d, T: Instance, M: Mode> {
121 rx_dma: Option<PeripheralRef<'d, AnyChannel>>, 141 rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
122 phantom: PhantomData<(&'d mut T, M)>, 142 phantom: PhantomData<(&'d mut T, M)>,
@@ -142,6 +162,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
142 } 162 }
143 } 163 }
144 164
165 /// Transmit the provided buffer blocking execution until done.
145 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 166 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
146 let r = T::regs(); 167 let r = T::regs();
147 for &b in buffer { 168 for &b in buffer {
@@ -151,12 +172,14 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
151 Ok(()) 172 Ok(())
152 } 173 }
153 174
175 /// Flush UART TX blocking execution until done.
154 pub fn blocking_flush(&mut self) -> Result<(), Error> { 176 pub fn blocking_flush(&mut self) -> Result<(), Error> {
155 let r = T::regs(); 177 let r = T::regs();
156 while !r.uartfr().read().txfe() {} 178 while !r.uartfr().read().txfe() {}
157 Ok(()) 179 Ok(())
158 } 180 }
159 181
182 /// Check if UART is busy transmitting.
160 pub fn busy(&self) -> bool { 183 pub fn busy(&self) -> bool {
161 T::regs().uartfr().read().busy() 184 T::regs().uartfr().read().busy()
162 } 185 }
@@ -191,6 +214,8 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
191} 214}
192 215
193impl<'d, T: Instance> UartTx<'d, T, Blocking> { 216impl<'d, T: Instance> UartTx<'d, T, Blocking> {
217 /// Convert this uart TX instance into a buffered uart using the provided
218 /// irq and transmit buffer.
194 pub fn into_buffered( 219 pub fn into_buffered(
195 self, 220 self,
196 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 221 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -203,6 +228,7 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> {
203} 228}
204 229
205impl<'d, T: Instance> UartTx<'d, T, Async> { 230impl<'d, T: Instance> UartTx<'d, T, Async> {
231 /// Write to UART TX from the provided buffer using DMA.
206 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 232 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
207 let ch = self.tx_dma.as_mut().unwrap(); 233 let ch = self.tx_dma.as_mut().unwrap();
208 let transfer = unsafe { 234 let transfer = unsafe {
@@ -246,6 +272,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
246 } 272 }
247 } 273 }
248 274
275 /// Read from UART RX blocking execution until done.
249 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 276 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
250 while buffer.len() > 0 { 277 while buffer.len() > 0 {
251 let received = self.drain_fifo(buffer)?; 278 let received = self.drain_fifo(buffer)?;
@@ -294,6 +321,7 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
294} 321}
295 322
296impl<'d, T: Instance> UartRx<'d, T, Blocking> { 323impl<'d, T: Instance> UartRx<'d, T, Blocking> {
324 /// Create a new UART RX instance for blocking mode operations.
297 pub fn new_blocking( 325 pub fn new_blocking(
298 _uart: impl Peripheral<P = T> + 'd, 326 _uart: impl Peripheral<P = T> + 'd,
299 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 327 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -304,6 +332,8 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
304 Self::new_inner(false, None) 332 Self::new_inner(false, None)
305 } 333 }
306 334
335 /// Convert this uart RX instance into a buffered uart using the provided
336 /// irq and receive buffer.
307 pub fn into_buffered( 337 pub fn into_buffered(
308 self, 338 self,
309 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 339 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -315,6 +345,7 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
315 } 345 }
316} 346}
317 347
348/// Interrupt handler.
318pub struct InterruptHandler<T: Instance> { 349pub struct InterruptHandler<T: Instance> {
319 _uart: PhantomData<T>, 350 _uart: PhantomData<T>,
320} 351}
@@ -338,6 +369,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
338} 369}
339 370
340impl<'d, T: Instance> UartRx<'d, T, Async> { 371impl<'d, T: Instance> UartRx<'d, T, Async> {
372 /// Read from UART RX into the provided buffer.
341 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 373 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
342 // clear error flags before we drain the fifo. errors that have accumulated 374 // clear error flags before we drain the fifo. errors that have accumulated
343 // in the flags will also be present in the fifo. 375 // in the flags will also be present in the fifo.
@@ -458,6 +490,8 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
458 ) 490 )
459 } 491 }
460 492
493 /// Convert this uart instance into a buffered uart using the provided
494 /// irq, transmit and receive buffers.
461 pub fn into_buffered( 495 pub fn into_buffered(
462 self, 496 self,
463 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 497 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -667,22 +701,27 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
667} 701}
668 702
669impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { 703impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
704 /// Transmit the provided buffer blocking execution until done.
670 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 705 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
671 self.tx.blocking_write(buffer) 706 self.tx.blocking_write(buffer)
672 } 707 }
673 708
709 /// Flush UART TX blocking execution until done.
674 pub fn blocking_flush(&mut self) -> Result<(), Error> { 710 pub fn blocking_flush(&mut self) -> Result<(), Error> {
675 self.tx.blocking_flush() 711 self.tx.blocking_flush()
676 } 712 }
677 713
714 /// Read from UART RX blocking execution until done.
678 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 715 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
679 self.rx.blocking_read(buffer) 716 self.rx.blocking_read(buffer)
680 } 717 }
681 718
719 /// Check if UART is busy transmitting.
682 pub fn busy(&self) -> bool { 720 pub fn busy(&self) -> bool {
683 self.tx.busy() 721 self.tx.busy()
684 } 722 }
685 723
724 /// Wait until TX is empty and send break condition.
686 pub async fn send_break(&mut self, bits: u32) { 725 pub async fn send_break(&mut self, bits: u32) {
687 self.tx.send_break(bits).await 726 self.tx.send_break(bits).await
688 } 727 }
@@ -695,10 +734,12 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
695} 734}
696 735
697impl<'d, T: Instance> Uart<'d, T, Async> { 736impl<'d, T: Instance> Uart<'d, T, Async> {
737 /// Write to UART TX from the provided buffer.
698 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 738 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
699 self.tx.write(buffer).await 739 self.tx.write(buffer).await
700 } 740 }
701 741
742 /// Read from UART RX into the provided buffer.
702 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 743 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
703 self.rx.read(buffer).await 744 self.rx.read(buffer).await
704 } 745 }
@@ -820,6 +861,10 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T
820impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { 861impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
821 fn read(&mut self) -> nb::Result<u8, Self::Error> { 862 fn read(&mut self) -> nb::Result<u8, Self::Error> {
822 let r = T::regs(); 863 let r = T::regs();
864 if r.uartfr().read().rxfe() {
865 return Err(nb::Error::WouldBlock);
866 }
867
823 let dr = r.uartdr().read(); 868 let dr = r.uartdr().read();
824 869
825 if dr.oe() { 870 if dr.oe() {
@@ -830,10 +875,8 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M
830 Err(nb::Error::Other(Error::Parity)) 875 Err(nb::Error::Other(Error::Parity))
831 } else if dr.fe() { 876 } else if dr.fe() {
832 Err(nb::Error::Other(Error::Framing)) 877 Err(nb::Error::Other(Error::Framing))
833 } else if dr.fe() {
834 Ok(dr.data())
835 } else { 878 } else {
836 Err(nb::Error::WouldBlock) 879 Ok(dr.data())
837 } 880 }
838 } 881 }
839} 882}
@@ -887,6 +930,7 @@ mod sealed {
887 pub trait RtsPin<T: Instance> {} 930 pub trait RtsPin<T: Instance> {}
888} 931}
889 932
933/// UART mode.
890pub trait Mode: sealed::Mode {} 934pub trait Mode: sealed::Mode {}
891 935
892macro_rules! impl_mode { 936macro_rules! impl_mode {
@@ -896,12 +940,15 @@ macro_rules! impl_mode {
896 }; 940 };
897} 941}
898 942
943/// Blocking mode.
899pub struct Blocking; 944pub struct Blocking;
945/// Async mode.
900pub struct Async; 946pub struct Async;
901 947
902impl_mode!(Blocking); 948impl_mode!(Blocking);
903impl_mode!(Async); 949impl_mode!(Async);
904 950
951/// UART instance.
905pub trait Instance: sealed::Instance {} 952pub trait Instance: sealed::Instance {}
906 953
907macro_rules! impl_instance { 954macro_rules! impl_instance {
@@ -936,9 +983,13 @@ macro_rules! impl_instance {
936impl_instance!(UART0, UART0_IRQ, 20, 21); 983impl_instance!(UART0, UART0_IRQ, 20, 21);
937impl_instance!(UART1, UART1_IRQ, 22, 23); 984impl_instance!(UART1, UART1_IRQ, 22, 23);
938 985
986/// Trait for TX pins.
939pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} 987pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
988/// Trait for RX pins.
940pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} 989pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
990/// Trait for Clear To Send (CTS) pins.
941pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {} 991pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {}
992/// Trait for Request To Send (RTS) pins.
942pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {} 993pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {}
943 994
944macro_rules! impl_pin { 995macro_rules! impl_pin {
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 4ab881f6e..905661d64 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -1,3 +1,4 @@
1//! USB driver.
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::slice; 4use core::slice;
@@ -20,7 +21,9 @@ pub(crate) mod sealed {
20 } 21 }
21} 22}
22 23
24/// USB peripheral instance.
23pub trait Instance: sealed::Instance + 'static { 25pub trait Instance: sealed::Instance + 'static {
26 /// Interrupt for this peripheral.
24 type Interrupt: interrupt::typelevel::Interrupt; 27 type Interrupt: interrupt::typelevel::Interrupt;
25} 28}
26 29
@@ -96,6 +99,7 @@ impl EndpointData {
96 } 99 }
97} 100}
98 101
102/// RP2040 USB driver handle.
99pub struct Driver<'d, T: Instance> { 103pub struct Driver<'d, T: Instance> {
100 phantom: PhantomData<&'d mut T>, 104 phantom: PhantomData<&'d mut T>,
101 ep_in: [EndpointData; EP_COUNT], 105 ep_in: [EndpointData; EP_COUNT],
@@ -104,6 +108,7 @@ pub struct Driver<'d, T: Instance> {
104} 108}
105 109
106impl<'d, T: Instance> Driver<'d, T> { 110impl<'d, T: Instance> Driver<'d, T> {
111 /// Create a new USB driver.
107 pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self { 112 pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
108 T::Interrupt::unpend(); 113 T::Interrupt::unpend();
109 unsafe { T::Interrupt::enable() }; 114 unsafe { T::Interrupt::enable() };
@@ -240,6 +245,7 @@ impl<'d, T: Instance> Driver<'d, T> {
240 } 245 }
241} 246}
242 247
248/// USB interrupt handler.
243pub struct InterruptHandler<T: Instance> { 249pub struct InterruptHandler<T: Instance> {
244 _uart: PhantomData<T>, 250 _uart: PhantomData<T>,
245} 251}
@@ -342,6 +348,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
342 } 348 }
343} 349}
344 350
351/// Type representing the RP USB bus.
345pub struct Bus<'d, T: Instance> { 352pub struct Bus<'d, T: Instance> {
346 phantom: PhantomData<&'d mut T>, 353 phantom: PhantomData<&'d mut T>,
347 ep_out: [EndpointData; EP_COUNT], 354 ep_out: [EndpointData; EP_COUNT],
@@ -363,7 +370,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
363 let siestatus = regs.sie_status().read(); 370 let siestatus = regs.sie_status().read();
364 let intrstatus = regs.intr().read(); 371 let intrstatus = regs.intr().read();
365 372
366 if siestatus.resume() { 373 if siestatus.resume() || intrstatus.dev_resume_from_host() {
367 regs.sie_status().write(|w| w.set_resume(true)); 374 regs.sie_status().write(|w| w.set_resume(true));
368 return Poll::Ready(Event::Resume); 375 return Poll::Ready(Event::Resume);
369 } 376 }
@@ -461,6 +468,7 @@ trait Dir {
461 fn waker(i: usize) -> &'static AtomicWaker; 468 fn waker(i: usize) -> &'static AtomicWaker;
462} 469}
463 470
471/// Type for In direction.
464pub enum In {} 472pub enum In {}
465impl Dir for In { 473impl Dir for In {
466 fn dir() -> Direction { 474 fn dir() -> Direction {
@@ -473,6 +481,7 @@ impl Dir for In {
473 } 481 }
474} 482}
475 483
484/// Type for Out direction.
476pub enum Out {} 485pub enum Out {}
477impl Dir for Out { 486impl Dir for Out {
478 fn dir() -> Direction { 487 fn dir() -> Direction {
@@ -485,6 +494,7 @@ impl Dir for Out {
485 } 494 }
486} 495}
487 496
497/// Endpoint for RP USB driver.
488pub struct Endpoint<'d, T: Instance, D> { 498pub struct Endpoint<'d, T: Instance, D> {
489 _phantom: PhantomData<(&'d mut T, D)>, 499 _phantom: PhantomData<(&'d mut T, D)>,
490 info: EndpointInfo, 500 info: EndpointInfo,
@@ -616,6 +626,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
616 } 626 }
617} 627}
618 628
629/// Control pipe for RP USB driver.
619pub struct ControlPipe<'d, T: Instance> { 630pub struct ControlPipe<'d, T: Instance> {
620 _phantom: PhantomData<&'d mut T>, 631 _phantom: PhantomData<&'d mut T>,
621 max_packet_size: u16, 632 max_packet_size: u16,
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index f887b8171..1780688cd 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -26,7 +26,7 @@ aligned = "0.4.1"
26 26
27bit_field = "0.10.2" 27bit_field = "0.10.2"
28stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } 28stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
29stm32wb-hci = { version = "0.1.4", optional = true } 29stm32wb-hci = { git = "https://github.com/Dirbaio/stm32wb-hci", rev = "0aff47e009c30c5fc5d520672625173d75f7505c", optional = true }
30futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 30futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
31bitflags = { version = "2.3.3", optional = true } 31bitflags = { version = "2.3.3", optional = true }
32 32
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index f8c4313e5..16d1cca4c 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -42,9 +42,9 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
42embassy-executor = { version = "0.4.0", path = "../embassy-executor", optional = true } 42embassy-executor = { version = "0.4.0", path = "../embassy-executor", optional = true }
43 43
44embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 44embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
45embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 45embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
46embedded-hal-async = { version = "=1.0.0-rc.2" } 46embedded-hal-async = { version = "=1.0.0-rc.3" }
47embedded-hal-nb = { version = "=1.0.0-rc.2" } 47embedded-hal-nb = { version = "=1.0.0-rc.3" }
48 48
49embedded-storage = "0.3.1" 49embedded-storage = "0.3.1"
50embedded-storage-async = { version = "0.4.1" } 50embedded-storage-async = { version = "0.4.1" }
@@ -56,9 +56,8 @@ cortex-m = "0.7.6"
56futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 56futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
57rand_core = "0.6.3" 57rand_core = "0.6.3"
58sdio-host = "0.5.0" 58sdio-host = "0.5.0"
59embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
60critical-section = "1.1" 59critical-section = "1.1"
61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8f5fcae8c289c1ad481cc3a2bb37db023a61599c" } 60stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8caf2f0bda28baf4393899dc67ba57f058087f5a" }
62vcell = "0.1.3" 61vcell = "0.1.3"
63bxcan = "0.7.0" 62bxcan = "0.7.0"
64nb = "1.0.0" 63nb = "1.0.0"
@@ -76,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] }
76[build-dependencies] 75[build-dependencies]
77proc-macro2 = "1.0.36" 76proc-macro2 = "1.0.36"
78quote = "1.0.15" 77quote = "1.0.15"
79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8f5fcae8c289c1ad481cc3a2bb37db023a61599c", default-features = false, features = ["metadata"]} 78stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8caf2f0bda28baf4393899dc67ba57f058087f5a", default-features = false, features = ["metadata"]}
80 79
81 80
82[features] 81[features]
@@ -120,6 +119,10 @@ time-driver-tim3 = ["_time-driver"]
120time-driver-tim4 = ["_time-driver"] 119time-driver-tim4 = ["_time-driver"]
121## Use TIM5 as time driver 120## Use TIM5 as time driver
122time-driver-tim5 = ["_time-driver"] 121time-driver-tim5 = ["_time-driver"]
122## Use TIM9 as time driver
123time-driver-tim9 = ["_time-driver"]
124## Use TIM11 as time driver
125time-driver-tim11 = ["_time-driver"]
123## Use TIM12 as time driver 126## Use TIM12 as time driver
124time-driver-tim12 = ["_time-driver"] 127time-driver-tim12 = ["_time-driver"]
125## Use TIM15 as time driver 128## Use TIM15 as time driver
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 0eef43ac4..058b8a0fc 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -187,6 +187,8 @@ fn main() {
187 Some("tim3") => "TIM3", 187 Some("tim3") => "TIM3",
188 Some("tim4") => "TIM4", 188 Some("tim4") => "TIM4",
189 Some("tim5") => "TIM5", 189 Some("tim5") => "TIM5",
190 Some("tim9") => "TIM9",
191 Some("tim11") => "TIM11",
190 Some("tim12") => "TIM12", 192 Some("tim12") => "TIM12",
191 Some("tim15") => "TIM15", 193 Some("tim15") => "TIM15",
192 Some("any") => { 194 Some("any") => {
@@ -198,12 +200,16 @@ fn main() {
198 "TIM4" 200 "TIM4"
199 } else if singletons.contains(&"TIM5".to_string()) { 201 } else if singletons.contains(&"TIM5".to_string()) {
200 "TIM5" 202 "TIM5"
203 } else if singletons.contains(&"TIM9".to_string()) {
204 "TIM9"
205 } else if singletons.contains(&"TIM11".to_string()) {
206 "TIM11"
201 } else if singletons.contains(&"TIM12".to_string()) { 207 } else if singletons.contains(&"TIM12".to_string()) {
202 "TIM12" 208 "TIM12"
203 } else if singletons.contains(&"TIM15".to_string()) { 209 } else if singletons.contains(&"TIM15".to_string()) {
204 "TIM15" 210 "TIM15"
205 } else { 211 } else {
206 panic!("time-driver-any requested, but the chip doesn't have TIM2, TIM3, TIM4, TIM5, TIM12 or TIM15.") 212 panic!("time-driver-any requested, but the chip doesn't have TIM2, TIM3, TIM4, TIM5, TIM9, TIM11, TIM12 or TIM15.")
207 } 213 }
208 } 214 }
209 _ => panic!("unknown time_driver {:?}", time_driver), 215 _ => panic!("unknown time_driver {:?}", time_driver),
@@ -666,14 +672,14 @@ fn main() {
666 (("lpuart", "RTS"), quote!(crate::usart::RtsPin)), 672 (("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
667 (("lpuart", "CK"), quote!(crate::usart::CkPin)), 673 (("lpuart", "CK"), quote!(crate::usart::CkPin)),
668 (("lpuart", "DE"), quote!(crate::usart::DePin)), 674 (("lpuart", "DE"), quote!(crate::usart::DePin)),
669 (("sai", "SCK_A"), quote!(crate::sai::SckAPin)), 675 (("sai", "SCK_A"), quote!(crate::sai::SckPin<A>)),
670 (("sai", "SCK_B"), quote!(crate::sai::SckBPin)), 676 (("sai", "SCK_B"), quote!(crate::sai::SckPin<B>)),
671 (("sai", "FS_A"), quote!(crate::sai::FsAPin)), 677 (("sai", "FS_A"), quote!(crate::sai::FsPin<A>)),
672 (("sai", "FS_B"), quote!(crate::sai::FsBPin)), 678 (("sai", "FS_B"), quote!(crate::sai::FsPin<B>)),
673 (("sai", "SD_A"), quote!(crate::sai::SdAPin)), 679 (("sai", "SD_A"), quote!(crate::sai::SdPin<A>)),
674 (("sai", "SD_B"), quote!(crate::sai::SdBPin)), 680 (("sai", "SD_B"), quote!(crate::sai::SdPin<B>)),
675 (("sai", "MCLK_A"), quote!(crate::sai::MclkAPin)), 681 (("sai", "MCLK_A"), quote!(crate::sai::MclkPin<A>)),
676 (("sai", "MCLK_B"), quote!(crate::sai::MclkBPin)), 682 (("sai", "MCLK_B"), quote!(crate::sai::MclkPin<B>)),
677 (("sai", "WS"), quote!(crate::sai::WsPin)), 683 (("sai", "WS"), quote!(crate::sai::WsPin)),
678 (("spi", "SCK"), quote!(crate::spi::SckPin)), 684 (("spi", "SCK"), quote!(crate::spi::SckPin)),
679 (("spi", "MOSI"), quote!(crate::spi::MosiPin)), 685 (("spi", "MOSI"), quote!(crate::spi::MosiPin)),
@@ -989,8 +995,8 @@ fn main() {
989 (("usart", "TX"), quote!(crate::usart::TxDma)), 995 (("usart", "TX"), quote!(crate::usart::TxDma)),
990 (("lpuart", "RX"), quote!(crate::usart::RxDma)), 996 (("lpuart", "RX"), quote!(crate::usart::RxDma)),
991 (("lpuart", "TX"), quote!(crate::usart::TxDma)), 997 (("lpuart", "TX"), quote!(crate::usart::TxDma)),
992 (("sai", "A"), quote!(crate::sai::DmaA)), 998 (("sai", "A"), quote!(crate::sai::Dma<A>)),
993 (("sai", "B"), quote!(crate::sai::DmaB)), 999 (("sai", "B"), quote!(crate::sai::Dma<B>)),
994 (("spi", "RX"), quote!(crate::spi::RxDma)), 1000 (("spi", "RX"), quote!(crate::spi::RxDma)),
995 (("spi", "TX"), quote!(crate::spi::TxDma)), 1001 (("spi", "TX"), quote!(crate::spi::TxDma)),
996 (("i2c", "RX"), quote!(crate::i2c::RxDma)), 1002 (("i2c", "RX"), quote!(crate::i2c::RxDma)),
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index dbe53c807..e4dd35c34 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,4 +1,7 @@
1//! Analog to Digital Converter (ADC)
2
1#![macro_use] 3#![macro_use]
4#![allow(missing_docs)] // TODO
2 5
3#[cfg(not(adc_f3_v2))] 6#[cfg(not(adc_f3_v2))]
4#[cfg_attr(adc_f1, path = "f1.rs")] 7#[cfg_attr(adc_f1, path = "f1.rs")]
@@ -24,6 +27,7 @@ pub use sample_time::SampleTime;
24 27
25use crate::peripherals; 28use crate::peripherals;
26 29
30/// Analog to Digital driver.
27pub struct Adc<'d, T: Instance> { 31pub struct Adc<'d, T: Instance> {
28 #[allow(unused)] 32 #[allow(unused)]
29 adc: crate::PeripheralRef<'d, T>, 33 adc: crate::PeripheralRef<'d, T>,
@@ -75,12 +79,16 @@ pub(crate) mod sealed {
75 } 79 }
76} 80}
77 81
82/// ADC instance.
78#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] 83#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
79pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 84pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
85/// ADC instance.
80#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] 86#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
81pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 87pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
82 88
89/// ADC pin.
83pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 90pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
91/// ADC internal channel.
84pub trait InternalChannel<T>: sealed::InternalChannel<T> {} 92pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
85 93
86foreach_adc!( 94foreach_adc!(
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
index 383980b5a..64c25a776 100644
--- a/embassy-stm32/src/adc/resolution.rs
+++ b/embassy-stm32/src/adc/resolution.rs
@@ -1,3 +1,5 @@
1/// ADC resolution
2#[allow(missing_docs)]
1#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] 3#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
2#[derive(Clone, Copy, Debug, Eq, PartialEq)] 4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -8,6 +10,8 @@ pub enum Resolution {
8 SixBit, 10 SixBit,
9} 11}
10 12
13/// ADC resolution
14#[allow(missing_docs)]
11#[cfg(adc_v4)] 15#[cfg(adc_v4)]
12#[derive(Clone, Copy, Debug, Eq, PartialEq)] 16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))] 17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -49,6 +53,9 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
49} 53}
50 54
51impl Resolution { 55impl Resolution {
56 /// Get the maximum reading value for this resolution.
57 ///
58 /// This is `2**n - 1`.
52 pub fn to_max_count(&self) -> u32 { 59 pub fn to_max_count(&self) -> u32 {
53 match self { 60 match self {
54 #[cfg(adc_v4)] 61 #[cfg(adc_v4)]
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index d74617cb3..048e73184 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -32,6 +32,7 @@ const TEMP_CHANNEL: u8 = 18;
32const VBAT_CHANNEL: u8 = 17; 32const VBAT_CHANNEL: u8 = 17;
33 33
34// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 34// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
35/// Internal voltage reference channel.
35pub struct VrefInt; 36pub struct VrefInt;
36impl<T: Instance> InternalChannel<T> for VrefInt {} 37impl<T: Instance> InternalChannel<T> for VrefInt {}
37impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { 38impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
@@ -40,6 +41,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
40 } 41 }
41} 42}
42 43
44/// Internal temperature channel.
43pub struct Temperature; 45pub struct Temperature;
44impl<T: Instance> InternalChannel<T> for Temperature {} 46impl<T: Instance> InternalChannel<T> for Temperature {}
45impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { 47impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
@@ -48,6 +50,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
48 } 50 }
49} 51}
50 52
53/// Internal battery voltage channel.
51pub struct Vbat; 54pub struct Vbat;
52impl<T: Instance> InternalChannel<T> for Vbat {} 55impl<T: Instance> InternalChannel<T> for Vbat {}
53impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { 56impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
@@ -125,6 +128,7 @@ impl Prescaler {
125} 128}
126 129
127impl<'d, T: Instance> Adc<'d, T> { 130impl<'d, T: Instance> Adc<'d, T> {
131 /// Create a new ADC driver.
128 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self { 132 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
129 embassy_hal_internal::into_ref!(adc); 133 embassy_hal_internal::into_ref!(adc);
130 T::enable_and_reset(); 134 T::enable_and_reset();
@@ -212,6 +216,7 @@ impl<'d, T: Instance> Adc<'d, T> {
212 }); 216 });
213 } 217 }
214 218
219 /// Enable reading the voltage reference internal channel.
215 pub fn enable_vrefint(&self) -> VrefInt { 220 pub fn enable_vrefint(&self) -> VrefInt {
216 T::common_regs().ccr().modify(|reg| { 221 T::common_regs().ccr().modify(|reg| {
217 reg.set_vrefen(true); 222 reg.set_vrefen(true);
@@ -220,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> {
220 VrefInt {} 225 VrefInt {}
221 } 226 }
222 227
228 /// Enable reading the temperature internal channel.
223 pub fn enable_temperature(&self) -> Temperature { 229 pub fn enable_temperature(&self) -> Temperature {
224 T::common_regs().ccr().modify(|reg| { 230 T::common_regs().ccr().modify(|reg| {
225 reg.set_vsenseen(true); 231 reg.set_vsenseen(true);
@@ -228,6 +234,7 @@ impl<'d, T: Instance> Adc<'d, T> {
228 Temperature {} 234 Temperature {}
229 } 235 }
230 236
237 /// Enable reading the vbat internal channel.
231 pub fn enable_vbat(&self) -> Vbat { 238 pub fn enable_vbat(&self) -> Vbat {
232 T::common_regs().ccr().modify(|reg| { 239 T::common_regs().ccr().modify(|reg| {
233 reg.set_vbaten(true); 240 reg.set_vbaten(true);
@@ -236,10 +243,12 @@ impl<'d, T: Instance> Adc<'d, T> {
236 Vbat {} 243 Vbat {}
237 } 244 }
238 245
246 /// Set the ADC sample time.
239 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 247 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
240 self.sample_time = sample_time; 248 self.sample_time = sample_time;
241 } 249 }
242 250
251 /// Set the ADC resolution.
243 pub fn set_resolution(&mut self, resolution: Resolution) { 252 pub fn set_resolution(&mut self, resolution: Resolution) {
244 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 253 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
245 } 254 }
@@ -263,6 +272,7 @@ impl<'d, T: Instance> Adc<'d, T> {
263 T::regs().dr().read().0 as u16 272 T::regs().dr().read().0 as u16
264 } 273 }
265 274
275 /// Read an ADC pin.
266 pub fn read<P>(&mut self, pin: &mut P) -> u16 276 pub fn read<P>(&mut self, pin: &mut P) -> u16
267 where 277 where
268 P: AdcPin<T>, 278 P: AdcPin<T>,
@@ -273,6 +283,7 @@ impl<'d, T: Instance> Adc<'d, T> {
273 self.read_channel(pin.channel()) 283 self.read_channel(pin.channel())
274 } 284 }
275 285
286 /// Read an ADC internal channel.
276 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 287 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
277 self.read_channel(channel.channel()) 288 self.read_channel(channel.channel())
278 } 289 }
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 2f7417340..cc87b2565 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -1,3 +1,4 @@
1use core::convert::AsMut;
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::ops::{Deref, DerefMut}; 4use core::ops::{Deref, DerefMut};
@@ -10,7 +11,7 @@ use futures::FutureExt;
10 11
11use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
12use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
13use crate::pac::can::vals::{Lec, RirIde}; 14use crate::pac::can::vals::{Ide, Lec};
14use crate::rcc::RccPeripheral; 15use crate::rcc::RccPeripheral;
15use crate::time::Hertz; 16use crate::time::Hertz;
16use crate::{interrupt, peripherals, Peripheral}; 17use crate::{interrupt, peripherals, Peripheral};
@@ -21,8 +22,10 @@ use crate::{interrupt, peripherals, Peripheral};
21#[derive(Debug, Clone, PartialEq, Eq)] 22#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))] 23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23pub struct Envelope { 24pub struct Envelope {
25 /// Reception time.
24 #[cfg(feature = "time")] 26 #[cfg(feature = "time")]
25 pub ts: embassy_time::Instant, 27 pub ts: embassy_time::Instant,
28 /// The actual CAN frame.
26 pub frame: bxcan::Frame, 29 pub frame: bxcan::Frame,
27} 30}
28 31
@@ -43,6 +46,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH
43 } 46 }
44} 47}
45 48
49/// RX0 interrupt handler.
46pub struct Rx0InterruptHandler<T: Instance> { 50pub struct Rx0InterruptHandler<T: Instance> {
47 _phantom: PhantomData<T>, 51 _phantom: PhantomData<T>,
48} 52}
@@ -54,6 +58,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0Interrup
54 } 58 }
55} 59}
56 60
61/// RX1 interrupt handler.
57pub struct Rx1InterruptHandler<T: Instance> { 62pub struct Rx1InterruptHandler<T: Instance> {
58 _phantom: PhantomData<T>, 63 _phantom: PhantomData<T>,
59} 64}
@@ -65,6 +70,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1Interrup
65 } 70 }
66} 71}
67 72
73/// SCE interrupt handler.
68pub struct SceInterruptHandler<T: Instance> { 74pub struct SceInterruptHandler<T: Instance> {
69 _phantom: PhantomData<T>, 75 _phantom: PhantomData<T>,
70} 76}
@@ -82,10 +88,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
82 } 88 }
83} 89}
84 90
91/// CAN driver
85pub struct Can<'d, T: Instance> { 92pub struct Can<'d, T: Instance> {
86 pub can: bxcan::Can<BxcanInstance<'d, T>>, 93 can: bxcan::Can<BxcanInstance<'d, T>>,
87} 94}
88 95
96/// CAN bus error
97#[allow(missing_docs)]
89#[derive(Debug)] 98#[derive(Debug)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))] 99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91pub enum BusError { 100pub enum BusError {
@@ -101,6 +110,7 @@ pub enum BusError {
101 BusWarning, 110 BusWarning,
102} 111}
103 112
113/// Error returned by `try_read`
104#[derive(Debug)] 114#[derive(Debug)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))] 115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub enum TryReadError { 116pub enum TryReadError {
@@ -110,6 +120,7 @@ pub enum TryReadError {
110 Empty, 120 Empty,
111} 121}
112 122
123/// Error returned by `try_write`
113#[derive(Debug)] 124#[derive(Debug)]
114#[cfg_attr(feature = "defmt", derive(defmt::Format))] 125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115pub enum TryWriteError { 126pub enum TryWriteError {
@@ -138,15 +149,11 @@ impl<'d, T: Instance> Can<'d, T> {
138 T::enable_and_reset(); 149 T::enable_and_reset();
139 150
140 { 151 {
141 use crate::pac::can::vals::{Errie, Fmpie, Tmeie};
142
143 T::regs().ier().write(|w| { 152 T::regs().ier().write(|w| {
144 // TODO: fix metapac 153 w.set_errie(true);
145 154 w.set_fmpie(0, true);
146 w.set_errie(Errie::from_bits(1)); 155 w.set_fmpie(1, true);
147 w.set_fmpie(0, Fmpie::from_bits(1)); 156 w.set_tmeie(true);
148 w.set_fmpie(1, Fmpie::from_bits(1));
149 w.set_tmeie(Tmeie::from_bits(1));
150 }); 157 });
151 158
152 T::regs().mcr().write(|w| { 159 T::regs().mcr().write(|w| {
@@ -177,6 +184,7 @@ impl<'d, T: Instance> Can<'d, T> {
177 Self { can } 184 Self { can }
178 } 185 }
179 186
187 /// Set CAN bit rate.
180 pub fn set_bitrate(&mut self, bitrate: u32) { 188 pub fn set_bitrate(&mut self, bitrate: u32) {
181 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); 189 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
182 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); 190 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
@@ -194,7 +202,9 @@ impl<'d, T: Instance> Can<'d, T> {
194 } 202 }
195 } 203 }
196 204
197 /// Queues the message to be sent but exerts backpressure 205 /// Queues the message to be sent.
206 ///
207 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
198 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { 208 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
199 self.split().0.write(frame).await 209 self.split().0.write(frame).await
200 } 210 }
@@ -221,12 +231,16 @@ impl<'d, T: Instance> Can<'d, T> {
221 CanTx::<T>::flush_all_inner().await 231 CanTx::<T>::flush_all_inner().await
222 } 232 }
223 233
234 /// Read a CAN frame.
235 ///
236 /// If no CAN frame is in the RX buffer, this will wait until there is one.
237 ///
224 /// Returns a tuple of the time the message was received and the message frame 238 /// Returns a tuple of the time the message was received and the message frame
225 pub async fn read(&mut self) -> Result<Envelope, BusError> { 239 pub async fn read(&mut self) -> Result<Envelope, BusError> {
226 self.split().1.read().await 240 self.split().1.read().await
227 } 241 }
228 242
229 /// Attempts to read a can frame without blocking. 243 /// Attempts to read a CAN frame without blocking.
230 /// 244 ///
231 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. 245 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
232 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { 246 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
@@ -259,7 +273,7 @@ impl<'d, T: Instance> Can<'d, T> {
259 } 273 }
260 274
261 let rir = fifo.rir().read(); 275 let rir = fifo.rir().read();
262 let id = if rir.ide() == RirIde::STANDARD { 276 let id = if rir.ide() == Ide::STANDARD {
263 Id::from(StandardId::new_unchecked(rir.stid())) 277 Id::from(StandardId::new_unchecked(rir.stid()))
264 } else { 278 } else {
265 let stid = (rir.stid() & 0x7FF) as u32; 279 let stid = (rir.stid() & 0x7FF) as u32;
@@ -288,7 +302,7 @@ impl<'d, T: Instance> Can<'d, T> {
288 } 302 }
289 } 303 }
290 304
291 pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { 305 const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
292 const BS1_MAX: u8 = 16; 306 const BS1_MAX: u8 = 16;
293 const BS2_MAX: u8 = 8; 307 const BS2_MAX: u8 = 8;
294 const MAX_SAMPLE_POINT_PERMILL: u16 = 900; 308 const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
@@ -379,21 +393,31 @@ impl<'d, T: Instance> Can<'d, T> {
379 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) 393 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1))
380 } 394 }
381 395
396 /// Split the CAN driver into transmit and receive halves.
397 ///
398 /// Useful for doing separate transmit/receive tasks.
382 pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { 399 pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
383 let (tx, rx0, rx1) = self.can.split_by_ref(); 400 let (tx, rx0, rx1) = self.can.split_by_ref();
384 (CanTx { tx }, CanRx { rx0, rx1 }) 401 (CanTx { tx }, CanRx { rx0, rx1 })
385 } 402 }
403}
386 404
387 pub fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { 405impl<'d, T: Instance> AsMut<bxcan::Can<BxcanInstance<'d, T>>> for Can<'d, T> {
406 /// Get mutable access to the lower-level driver from the `bxcan` crate.
407 fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> {
388 &mut self.can 408 &mut self.can
389 } 409 }
390} 410}
391 411
412/// CAN driver, transmit half.
392pub struct CanTx<'c, 'd, T: Instance> { 413pub struct CanTx<'c, 'd, T: Instance> {
393 tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, 414 tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>,
394} 415}
395 416
396impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { 417impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
418 /// Queues the message to be sent.
419 ///
420 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
397 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { 421 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
398 poll_fn(|cx| { 422 poll_fn(|cx| {
399 T::state().tx_waker.register(cx.waker()); 423 T::state().tx_waker.register(cx.waker());
@@ -475,6 +499,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
475 } 499 }
476} 500}
477 501
502/// CAN driver, receive half.
478#[allow(dead_code)] 503#[allow(dead_code)]
479pub struct CanRx<'c, 'd, T: Instance> { 504pub struct CanRx<'c, 'd, T: Instance> {
480 rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, 505 rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>,
@@ -482,6 +507,11 @@ pub struct CanRx<'c, 'd, T: Instance> {
482} 507}
483 508
484impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { 509impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
510 /// Read a CAN frame.
511 ///
512 /// If no CAN frame is in the RX buffer, this will wait until there is one.
513 ///
514 /// Returns a tuple of the time the message was received and the message frame
485 pub async fn read(&mut self) -> Result<Envelope, BusError> { 515 pub async fn read(&mut self) -> Result<Envelope, BusError> {
486 poll_fn(|cx| { 516 poll_fn(|cx| {
487 T::state().err_waker.register(cx.waker()); 517 T::state().err_waker.register(cx.waker());
@@ -585,30 +615,24 @@ pub(crate) mod sealed {
585 pub trait Instance { 615 pub trait Instance {
586 const REGISTERS: *mut bxcan::RegisterBlock; 616 const REGISTERS: *mut bxcan::RegisterBlock;
587 617
588 fn regs() -> &'static crate::pac::can::Can; 618 fn regs() -> crate::pac::can::Can;
589 fn state() -> &'static State; 619 fn state() -> &'static State;
590 } 620 }
591} 621}
592 622
593pub trait TXInstance { 623/// CAN instance trait.
624pub trait Instance: sealed::Instance + RccPeripheral + 'static {
625 /// TX interrupt for this instance.
594 type TXInterrupt: crate::interrupt::typelevel::Interrupt; 626 type TXInterrupt: crate::interrupt::typelevel::Interrupt;
595} 627 /// RX0 interrupt for this instance.
596
597pub trait RX0Instance {
598 type RX0Interrupt: crate::interrupt::typelevel::Interrupt; 628 type RX0Interrupt: crate::interrupt::typelevel::Interrupt;
599} 629 /// RX1 interrupt for this instance.
600
601pub trait RX1Instance {
602 type RX1Interrupt: crate::interrupt::typelevel::Interrupt; 630 type RX1Interrupt: crate::interrupt::typelevel::Interrupt;
603} 631 /// SCE interrupt for this instance.
604
605pub trait SCEInstance {
606 type SCEInterrupt: crate::interrupt::typelevel::Interrupt; 632 type SCEInterrupt: crate::interrupt::typelevel::Interrupt;
607} 633}
608 634
609pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {} 635/// BXCAN instance newtype.
610pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
611
612pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); 636pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
613 637
614unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { 638unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
@@ -620,8 +644,8 @@ foreach_peripheral!(
620 impl sealed::Instance for peripherals::$inst { 644 impl sealed::Instance for peripherals::$inst {
621 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; 645 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
622 646
623 fn regs() -> &'static crate::pac::can::Can { 647 fn regs() -> crate::pac::can::Can {
624 &crate::pac::$inst 648 crate::pac::$inst
625 } 649 }
626 650
627 fn state() -> &'static sealed::State { 651 fn state() -> &'static sealed::State {
@@ -630,32 +654,12 @@ foreach_peripheral!(
630 } 654 }
631 } 655 }
632 656
633 impl Instance for peripherals::$inst {} 657 impl Instance for peripherals::$inst {
634 658 type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX;
635 foreach_interrupt!( 659 type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0;
636 ($inst,can,CAN,TX,$irq:ident) => { 660 type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1;
637 impl TXInstance for peripherals::$inst { 661 type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE;
638 type TXInterrupt = crate::interrupt::typelevel::$irq; 662 }
639 }
640 };
641 ($inst,can,CAN,RX0,$irq:ident) => {
642 impl RX0Instance for peripherals::$inst {
643 type RX0Interrupt = crate::interrupt::typelevel::$irq;
644 }
645 };
646 ($inst,can,CAN,RX1,$irq:ident) => {
647 impl RX1Instance for peripherals::$inst {
648 type RX1Interrupt = crate::interrupt::typelevel::$irq;
649 }
650 };
651 ($inst,can,CAN,SCE,$irq:ident) => {
652 impl SCEInstance for peripherals::$inst {
653 type SCEInterrupt = crate::interrupt::typelevel::$irq;
654 }
655 };
656 );
657
658 impl InterruptableInstance for peripherals::$inst {}
659 }; 663 };
660); 664);
661 665
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index f77788db3..0cc2559cf 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -1,6 +1,3 @@
1pub use bxcan;
2use embassy_hal_internal::PeripheralRef;
3
4use crate::peripherals; 1use crate::peripherals;
5 2
6pub(crate) mod sealed { 3pub(crate) mod sealed {
@@ -25,27 +22,19 @@ pub(crate) mod sealed {
25 } 22 }
26 23
27 pub trait Instance { 24 pub trait Instance {
28 const REGISTERS: *mut bxcan::RegisterBlock;
29
30 fn regs() -> &'static crate::pac::can::Fdcan; 25 fn regs() -> &'static crate::pac::can::Fdcan;
31 fn state() -> &'static State; 26 fn state() -> &'static State;
32 } 27 }
33} 28}
34 29
30/// Interruptable FDCAN instance.
35pub trait InterruptableInstance {} 31pub trait InterruptableInstance {}
32/// FDCAN instance.
36pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} 33pub trait Instance: sealed::Instance + InterruptableInstance + 'static {}
37 34
38pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
39
40unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
41 const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS;
42}
43
44foreach_peripheral!( 35foreach_peripheral!(
45 (can, $inst:ident) => { 36 (can, $inst:ident) => {
46 impl sealed::Instance for peripherals::$inst { 37 impl sealed::Instance for peripherals::$inst {
47 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
48
49 fn regs() -> &'static crate::pac::can::Fdcan { 38 fn regs() -> &'static crate::pac::can::Fdcan {
50 &crate::pac::$inst 39 &crate::pac::$inst
51 } 40 }
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs
index 425f9ac2e..915edb3a6 100644
--- a/embassy-stm32/src/can/mod.rs
+++ b/embassy-stm32/src/can/mod.rs
@@ -1,3 +1,4 @@
1//! Controller Area Network (CAN)
1#![macro_use] 2#![macro_use]
2 3
3#[cfg_attr(can_bxcan, path = "bxcan.rs")] 4#[cfg_attr(can_bxcan, path = "bxcan.rs")]
diff --git a/embassy-stm32/src/crc/mod.rs b/embassy-stm32/src/crc/mod.rs
index 63f7ad9ba..29523b92d 100644
--- a/embassy-stm32/src/crc/mod.rs
+++ b/embassy-stm32/src/crc/mod.rs
@@ -1,3 +1,4 @@
1//! Cyclic Redundancy Check (CRC)
1#[cfg_attr(crc_v1, path = "v1.rs")] 2#[cfg_attr(crc_v1, path = "v1.rs")]
2#[cfg_attr(crc_v2, path = "v2v3.rs")] 3#[cfg_attr(crc_v2, path = "v2v3.rs")]
3#[cfg_attr(crc_v3, path = "v2v3.rs")] 4#[cfg_attr(crc_v3, path = "v2v3.rs")]
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index c0f580830..0166ab819 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -5,6 +5,7 @@ use crate::peripherals::CRC;
5use crate::rcc::sealed::RccPeripheral; 5use crate::rcc::sealed::RccPeripheral;
6use crate::Peripheral; 6use crate::Peripheral;
7 7
8/// CRC driver.
8pub struct Crc<'d> { 9pub struct Crc<'d> {
9 _peri: PeripheralRef<'d, CRC>, 10 _peri: PeripheralRef<'d, CRC>,
10} 11}
@@ -34,6 +35,7 @@ impl<'d> Crc<'d> {
34 PAC_CRC.dr().write_value(word); 35 PAC_CRC.dr().write_value(word);
35 self.read() 36 self.read()
36 } 37 }
38
37 /// 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.
38 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 40 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
39 for word in words { 41 for word in words {
@@ -42,6 +44,8 @@ impl<'d> Crc<'d> {
42 44
43 self.read() 45 self.read()
44 } 46 }
47
48 /// Read the CRC result value.
45 pub fn read(&self) -> u32 { 49 pub fn read(&self) -> u32 {
46 PAC_CRC.dr().read() 50 PAC_CRC.dr().read()
47 } 51 }
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index b36f6018c..0c4ae55ce 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -6,15 +6,19 @@ use crate::peripherals::CRC;
6use crate::rcc::sealed::RccPeripheral; 6use crate::rcc::sealed::RccPeripheral;
7use crate::Peripheral; 7use crate::Peripheral;
8 8
9/// CRC driver.
9pub struct Crc<'d> { 10pub struct Crc<'d> {
10 _peripheral: PeripheralRef<'d, CRC>, 11 _peripheral: PeripheralRef<'d, CRC>,
11 _config: Config, 12 _config: Config,
12} 13}
13 14
15/// CRC configuration errlr
14pub enum ConfigError { 16pub enum ConfigError {
17 /// The selected polynomial is invalid.
15 InvalidPolynomial, 18 InvalidPolynomial,
16} 19}
17 20
21/// CRC configuration
18pub struct Config { 22pub struct Config {
19 reverse_in: InputReverseConfig, 23 reverse_in: InputReverseConfig,
20 reverse_out: bool, 24 reverse_out: bool,
@@ -25,14 +29,20 @@ pub struct Config {
25 crc_poly: u32, 29 crc_poly: u32,
26} 30}
27 31
32/// Input reverse configuration.
28pub enum InputReverseConfig { 33pub enum InputReverseConfig {
34 /// Don't reverse anything
29 None, 35 None,
36 /// Reverse bytes
30 Byte, 37 Byte,
38 /// Reverse 16-bit halfwords.
31 Halfword, 39 Halfword,
40 /// Reverse 32-bit words.
32 Word, 41 Word,
33} 42}
34 43
35impl Config { 44impl Config {
45 /// Create a new CRC config.
36 pub fn new( 46 pub fn new(
37 reverse_in: InputReverseConfig, 47 reverse_in: InputReverseConfig,
38 reverse_out: bool, 48 reverse_out: bool,
@@ -57,7 +67,9 @@ impl Config {
57 } 67 }
58} 68}
59 69
70/// Polynomial size
60#[cfg(crc_v3)] 71#[cfg(crc_v3)]
72#[allow(missing_docs)]
61pub enum PolySize { 73pub enum PolySize {
62 Width7, 74 Width7,
63 Width8, 75 Width8,
@@ -81,6 +93,7 @@ impl<'d> Crc<'d> {
81 instance 93 instance
82 } 94 }
83 95
96 /// Reset the CRC engine.
84 pub fn reset(&mut self) { 97 pub fn reset(&mut self) {
85 PAC_CRC.cr().modify(|w| w.set_reset(true)); 98 PAC_CRC.cr().modify(|w| w.set_reset(true));
86 } 99 }
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 500eac4c1..31dedf06e 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -1,4 +1,4 @@
1//! Provide access to the STM32 digital-to-analog converter (DAC). 1//! Digital to Analog Converter (DAC)
2#![macro_use] 2#![macro_use]
3 3
4use core::marker::PhantomData; 4use core::marker::PhantomData;
@@ -62,11 +62,11 @@ impl Mode {
62/// 62///
63/// 12-bit values outside the permitted range are silently truncated. 63/// 12-bit values outside the permitted range are silently truncated.
64pub enum Value { 64pub enum Value {
65 // 8 bit value 65 /// 8 bit value
66 Bit8(u8), 66 Bit8(u8),
67 // 12 bit value stored in a u16, left-aligned 67 /// 12 bit value stored in a u16, left-aligned
68 Bit12Left(u16), 68 Bit12Left(u16),
69 // 12 bit value stored in a u16, right-aligned 69 /// 12 bit value stored in a u16, right-aligned
70 Bit12Right(u16), 70 Bit12Right(u16),
71} 71}
72 72
@@ -76,11 +76,11 @@ pub enum Value {
76/// 76///
77/// 12-bit values outside the permitted range are silently truncated. 77/// 12-bit values outside the permitted range are silently truncated.
78pub enum DualValue { 78pub enum DualValue {
79 // 8 bit value 79 /// 8 bit value
80 Bit8(u8, u8), 80 Bit8(u8, u8),
81 // 12 bit value stored in a u16, left-aligned 81 /// 12 bit value stored in a u16, left-aligned
82 Bit12Left(u16, u16), 82 Bit12Left(u16, u16),
83 // 12 bit value stored in a u16, right-aligned 83 /// 12 bit value stored in a u16, right-aligned
84 Bit12Right(u16, u16), 84 Bit12Right(u16, u16),
85} 85}
86 86
@@ -88,11 +88,11 @@ pub enum DualValue {
88#[cfg_attr(feature = "defmt", derive(defmt::Format))] 88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89/// Array variant of [`Value`]. 89/// Array variant of [`Value`].
90pub enum ValueArray<'a> { 90pub enum ValueArray<'a> {
91 // 8 bit values 91 /// 8 bit values
92 Bit8(&'a [u8]), 92 Bit8(&'a [u8]),
93 // 12 bit value stored in a u16, left-aligned 93 /// 12 bit value stored in a u16, left-aligned
94 Bit12Left(&'a [u16]), 94 Bit12Left(&'a [u16]),
95 // 12 bit values stored in a u16, right-aligned 95 /// 12 bit values stored in a u16, right-aligned
96 Bit12Right(&'a [u16]), 96 Bit12Right(&'a [u16]),
97} 97}
98 98
@@ -106,7 +106,9 @@ pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> {
106 dma: PeripheralRef<'d, DMA>, 106 dma: PeripheralRef<'d, DMA>,
107} 107}
108 108
109/// DAC channel 1 type alias.
109pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; 110pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>;
111/// DAC channel 2 type alias.
110pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; 112pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>;
111 113
112impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { 114impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
@@ -492,6 +494,7 @@ pub(crate) mod sealed {
492 } 494 }
493} 495}
494 496
497/// DAC instance.
495pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 498pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
496dma_trait!(DacDma1, Instance); 499dma_trait!(DacDma1, Instance);
497dma_trait!(DacDma2, Instance); 500dma_trait!(DacDma2, Instance);
diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs
index f38dd8fd7..22d8d3dfa 100644
--- a/embassy-stm32/src/dac/tsel.rs
+++ b/embassy-stm32/src/dac/tsel.rs
@@ -1,3 +1,5 @@
1#![allow(missing_docs)]
2
1/// Trigger selection for STM32F0. 3/// Trigger selection for STM32F0.
2#[cfg(stm32f0)] 4#[cfg(stm32f0)]
3#[derive(Debug, Copy, Clone, Eq, PartialEq)] 5#[derive(Debug, Copy, Clone, Eq, PartialEq)]
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index b12230794..4d02284b2 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -1,3 +1,4 @@
1//! Digital Camera Interface (DCMI)
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::task::Poll; 4use core::task::Poll;
@@ -36,6 +37,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
36} 37}
37 38
38/// The level on the VSync pin when the data is not valid on the parallel interface. 39/// The level on the VSync pin when the data is not valid on the parallel interface.
40#[allow(missing_docs)]
39#[derive(Clone, Copy, PartialEq)] 41#[derive(Clone, Copy, PartialEq)]
40pub enum VSyncDataInvalidLevel { 42pub enum VSyncDataInvalidLevel {
41 Low, 43 Low,
@@ -43,6 +45,7 @@ pub enum VSyncDataInvalidLevel {
43} 45}
44 46
45/// The level on the VSync pin when the data is not valid on the parallel interface. 47/// The level on the VSync pin when the data is not valid on the parallel interface.
48#[allow(missing_docs)]
46#[derive(Clone, Copy, PartialEq)] 49#[derive(Clone, Copy, PartialEq)]
47pub enum HSyncDataInvalidLevel { 50pub enum HSyncDataInvalidLevel {
48 Low, 51 Low,
@@ -50,14 +53,16 @@ pub enum HSyncDataInvalidLevel {
50} 53}
51 54
52#[derive(Clone, Copy, PartialEq)] 55#[derive(Clone, Copy, PartialEq)]
56#[allow(missing_docs)]
53pub enum PixelClockPolarity { 57pub enum PixelClockPolarity {
54 RisingEdge, 58 RisingEdge,
55 FallingEdge, 59 FallingEdge,
56} 60}
57 61
58pub struct State { 62struct State {
59 waker: AtomicWaker, 63 waker: AtomicWaker,
60} 64}
65
61impl State { 66impl State {
62 const fn new() -> State { 67 const fn new() -> State {
63 State { 68 State {
@@ -68,18 +73,25 @@ impl State {
68 73
69static STATE: State = State::new(); 74static STATE: State = State::new();
70 75
76/// DCMI error.
71#[derive(Debug, Eq, PartialEq, Copy, Clone)] 77#[derive(Debug, Eq, PartialEq, Copy, Clone)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))] 78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[non_exhaustive] 79#[non_exhaustive]
74pub enum Error { 80pub enum Error {
81 /// Overrun error: the hardware generated data faster than we could read it.
75 Overrun, 82 Overrun,
83 /// Internal peripheral error.
76 PeripheralError, 84 PeripheralError,
77} 85}
78 86
87/// DCMI configuration.
79#[non_exhaustive] 88#[non_exhaustive]
80pub struct Config { 89pub struct Config {
90 /// VSYNC level.
81 pub vsync_level: VSyncDataInvalidLevel, 91 pub vsync_level: VSyncDataInvalidLevel,
92 /// HSYNC level.
82 pub hsync_level: HSyncDataInvalidLevel, 93 pub hsync_level: HSyncDataInvalidLevel,
94 /// PIXCLK polarity.
83 pub pixclk_polarity: PixelClockPolarity, 95 pub pixclk_polarity: PixelClockPolarity,
84} 96}
85 97
@@ -105,6 +117,7 @@ macro_rules! config_pins {
105 }; 117 };
106} 118}
107 119
120/// DCMI driver.
108pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> { 121pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> {
109 inner: PeripheralRef<'d, T>, 122 inner: PeripheralRef<'d, T>,
110 dma: PeripheralRef<'d, Dma>, 123 dma: PeripheralRef<'d, Dma>,
@@ -115,6 +128,7 @@ where
115 T: Instance, 128 T: Instance,
116 Dma: FrameDma<T>, 129 Dma: FrameDma<T>,
117{ 130{
131 /// Create a new DCMI driver with 8 data bits.
118 pub fn new_8bit( 132 pub fn new_8bit(
119 peri: impl Peripheral<P = T> + 'd, 133 peri: impl Peripheral<P = T> + 'd,
120 dma: impl Peripheral<P = Dma> + 'd, 134 dma: impl Peripheral<P = Dma> + 'd,
@@ -139,6 +153,7 @@ where
139 Self::new_inner(peri, dma, config, false, 0b00) 153 Self::new_inner(peri, dma, config, false, 0b00)
140 } 154 }
141 155
156 /// Create a new DCMI driver with 10 data bits.
142 pub fn new_10bit( 157 pub fn new_10bit(
143 peri: impl Peripheral<P = T> + 'd, 158 peri: impl Peripheral<P = T> + 'd,
144 dma: impl Peripheral<P = Dma> + 'd, 159 dma: impl Peripheral<P = Dma> + 'd,
@@ -165,6 +180,7 @@ where
165 Self::new_inner(peri, dma, config, false, 0b01) 180 Self::new_inner(peri, dma, config, false, 0b01)
166 } 181 }
167 182
183 /// Create a new DCMI driver with 12 data bits.
168 pub fn new_12bit( 184 pub fn new_12bit(
169 peri: impl Peripheral<P = T> + 'd, 185 peri: impl Peripheral<P = T> + 'd,
170 dma: impl Peripheral<P = Dma> + 'd, 186 dma: impl Peripheral<P = Dma> + 'd,
@@ -193,6 +209,7 @@ where
193 Self::new_inner(peri, dma, config, false, 0b10) 209 Self::new_inner(peri, dma, config, false, 0b10)
194 } 210 }
195 211
212 /// Create a new DCMI driver with 14 data bits.
196 pub fn new_14bit( 213 pub fn new_14bit(
197 peri: impl Peripheral<P = T> + 'd, 214 peri: impl Peripheral<P = T> + 'd,
198 dma: impl Peripheral<P = Dma> + 'd, 215 dma: impl Peripheral<P = Dma> + 'd,
@@ -223,6 +240,7 @@ where
223 Self::new_inner(peri, dma, config, false, 0b11) 240 Self::new_inner(peri, dma, config, false, 0b11)
224 } 241 }
225 242
243 /// Create a new DCMI driver with 8 data bits, with embedded synchronization.
226 pub fn new_es_8bit( 244 pub fn new_es_8bit(
227 peri: impl Peripheral<P = T> + 'd, 245 peri: impl Peripheral<P = T> + 'd,
228 dma: impl Peripheral<P = Dma> + 'd, 246 dma: impl Peripheral<P = Dma> + 'd,
@@ -245,6 +263,7 @@ where
245 Self::new_inner(peri, dma, config, true, 0b00) 263 Self::new_inner(peri, dma, config, true, 0b00)
246 } 264 }
247 265
266 /// Create a new DCMI driver with 10 data bits, with embedded synchronization.
248 pub fn new_es_10bit( 267 pub fn new_es_10bit(
249 peri: impl Peripheral<P = T> + 'd, 268 peri: impl Peripheral<P = T> + 'd,
250 dma: impl Peripheral<P = Dma> + 'd, 269 dma: impl Peripheral<P = Dma> + 'd,
@@ -269,6 +288,7 @@ where
269 Self::new_inner(peri, dma, config, true, 0b01) 288 Self::new_inner(peri, dma, config, true, 0b01)
270 } 289 }
271 290
291 /// Create a new DCMI driver with 12 data bits, with embedded synchronization.
272 pub fn new_es_12bit( 292 pub fn new_es_12bit(
273 peri: impl Peripheral<P = T> + 'd, 293 peri: impl Peripheral<P = T> + 'd,
274 dma: impl Peripheral<P = Dma> + 'd, 294 dma: impl Peripheral<P = Dma> + 'd,
@@ -295,6 +315,7 @@ where
295 Self::new_inner(peri, dma, config, true, 0b10) 315 Self::new_inner(peri, dma, config, true, 0b10)
296 } 316 }
297 317
318 /// Create a new DCMI driver with 14 data bits, with embedded synchronization.
298 pub fn new_es_14bit( 319 pub fn new_es_14bit(
299 peri: impl Peripheral<P = T> + 'd, 320 peri: impl Peripheral<P = T> + 'd,
300 dma: impl Peripheral<P = Dma> + 'd, 321 dma: impl Peripheral<P = Dma> + 'd,
@@ -538,7 +559,9 @@ mod sealed {
538 } 559 }
539} 560}
540 561
562/// DCMI instance.
541pub trait Instance: sealed::Instance + 'static { 563pub trait Instance: sealed::Instance + 'static {
564 /// Interrupt for this instance.
542 type Interrupt: interrupt::typelevel::Interrupt; 565 type Interrupt: interrupt::typelevel::Interrupt;
543} 566}
544 567
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index a7422f66b..a2b83716d 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -1,4 +1,4 @@
1#![macro_use] 1//! Basic Direct Memory Acccess (BDMA)
2 2
3use core::future::Future; 3use core::future::Future;
4use core::pin::Pin; 4use core::pin::Pin;
@@ -17,11 +17,16 @@ use crate::interrupt::Priority;
17use crate::pac; 17use crate::pac;
18use crate::pac::bdma::{regs, vals}; 18use crate::pac::bdma::{regs, vals};
19 19
20/// BDMA transfer options.
20#[derive(Debug, Copy, Clone, PartialEq, Eq)] 21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))] 22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22#[non_exhaustive] 23#[non_exhaustive]
23pub struct TransferOptions { 24pub struct TransferOptions {
24 /// Enable circular DMA 25 /// Enable circular DMA
26 ///
27 /// Note:
28 /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task.
29 /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever.
25 pub circular: bool, 30 pub circular: bool,
26 /// Enable half transfer interrupt 31 /// Enable half transfer interrupt
27 pub half_transfer_ir: bool, 32 pub half_transfer_ir: bool,
@@ -140,13 +145,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
140 STATE.ch_wakers[index].wake(); 145 STATE.ch_wakers[index].wake();
141} 146}
142 147
148/// DMA request type alias.
143#[cfg(any(bdma_v2, dmamux))] 149#[cfg(any(bdma_v2, dmamux))]
144pub type Request = u8; 150pub type Request = u8;
151/// DMA request type alias.
145#[cfg(not(any(bdma_v2, dmamux)))] 152#[cfg(not(any(bdma_v2, dmamux)))]
146pub type Request = (); 153pub type Request = ();
147 154
155/// DMA channel.
148#[cfg(dmamux)] 156#[cfg(dmamux)]
149pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 157pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
158/// DMA channel.
150#[cfg(not(dmamux))] 159#[cfg(not(dmamux))]
151pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 160pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
152 161
@@ -161,12 +170,14 @@ pub(crate) mod sealed {
161 } 170 }
162} 171}
163 172
173/// DMA transfer.
164#[must_use = "futures do nothing unless you `.await` or poll them"] 174#[must_use = "futures do nothing unless you `.await` or poll them"]
165pub struct Transfer<'a, C: Channel> { 175pub struct Transfer<'a, C: Channel> {
166 channel: PeripheralRef<'a, C>, 176 channel: PeripheralRef<'a, C>,
167} 177}
168 178
169impl<'a, C: Channel> Transfer<'a, C> { 179impl<'a, C: Channel> Transfer<'a, C> {
180 /// Create a new read DMA transfer (peripheral to memory).
170 pub unsafe fn new_read<W: Word>( 181 pub unsafe fn new_read<W: Word>(
171 channel: impl Peripheral<P = C> + 'a, 182 channel: impl Peripheral<P = C> + 'a,
172 request: Request, 183 request: Request,
@@ -177,6 +188,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
177 Self::new_read_raw(channel, request, peri_addr, buf, options) 188 Self::new_read_raw(channel, request, peri_addr, buf, options)
178 } 189 }
179 190
191 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
180 pub unsafe fn new_read_raw<W: Word>( 192 pub unsafe fn new_read_raw<W: Word>(
181 channel: impl Peripheral<P = C> + 'a, 193 channel: impl Peripheral<P = C> + 'a,
182 request: Request, 194 request: Request,
@@ -202,6 +214,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
202 ) 214 )
203 } 215 }
204 216
217 /// Create a new write DMA transfer (memory to peripheral).
205 pub unsafe fn new_write<W: Word>( 218 pub unsafe fn new_write<W: Word>(
206 channel: impl Peripheral<P = C> + 'a, 219 channel: impl Peripheral<P = C> + 'a,
207 request: Request, 220 request: Request,
@@ -212,6 +225,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
212 Self::new_write_raw(channel, request, buf, peri_addr, options) 225 Self::new_write_raw(channel, request, buf, peri_addr, options)
213 } 226 }
214 227
228 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
215 pub unsafe fn new_write_raw<W: Word>( 229 pub unsafe fn new_write_raw<W: Word>(
216 channel: impl Peripheral<P = C> + 'a, 230 channel: impl Peripheral<P = C> + 'a,
217 request: Request, 231 request: Request,
@@ -237,6 +251,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
237 ) 251 )
238 } 252 }
239 253
254 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
240 pub unsafe fn new_write_repeated<W: Word>( 255 pub unsafe fn new_write_repeated<W: Word>(
241 channel: impl Peripheral<P = C> + 'a, 256 channel: impl Peripheral<P = C> + 'a,
242 request: Request, 257 request: Request,
@@ -292,20 +307,14 @@ impl<'a, C: Channel> Transfer<'a, C> {
292 ch.cr().write(|w| { 307 ch.cr().write(|w| {
293 w.set_psize(data_size.into()); 308 w.set_psize(data_size.into());
294 w.set_msize(data_size.into()); 309 w.set_msize(data_size.into());
295 if incr_mem { 310 w.set_minc(incr_mem);
296 w.set_minc(vals::Inc::ENABLED);
297 } else {
298 w.set_minc(vals::Inc::DISABLED);
299 }
300 w.set_dir(dir.into()); 311 w.set_dir(dir.into());
301 w.set_teie(true); 312 w.set_teie(true);
302 w.set_tcie(options.complete_transfer_ir); 313 w.set_tcie(options.complete_transfer_ir);
303 w.set_htie(options.half_transfer_ir); 314 w.set_htie(options.half_transfer_ir);
315 w.set_circ(options.circular);
304 if options.circular { 316 if options.circular {
305 w.set_circ(vals::Circ::ENABLED);
306 debug!("Setting circular mode"); 317 debug!("Setting circular mode");
307 } else {
308 w.set_circ(vals::Circ::DISABLED);
309 } 318 }
310 w.set_pl(vals::Pl::VERYHIGH); 319 w.set_pl(vals::Pl::VERYHIGH);
311 w.set_en(true); 320 w.set_en(true);
@@ -321,6 +330,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
321 }); 330 });
322 } 331 }
323 332
333 /// Request the transfer to stop.
334 ///
335 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
324 pub fn request_stop(&mut self) { 336 pub fn request_stop(&mut self) {
325 let ch = self.channel.regs().ch(self.channel.num()); 337 let ch = self.channel.regs().ch(self.channel.num());
326 338
@@ -331,21 +343,27 @@ impl<'a, C: Channel> Transfer<'a, C> {
331 }); 343 });
332 } 344 }
333 345
346 /// Return whether this transfer is still running.
347 ///
348 /// If this returns `false`, it can be because either the transfer finished, or
349 /// it was requested to stop early with [`request_stop`](Self::request_stop).
334 pub fn is_running(&mut self) -> bool { 350 pub fn is_running(&mut self) -> bool {
335 let ch = self.channel.regs().ch(self.channel.num()); 351 let ch = self.channel.regs().ch(self.channel.num());
336 let en = ch.cr().read().en(); 352 let en = ch.cr().read().en();
337 let circular = ch.cr().read().circ() == vals::Circ::ENABLED; 353 let circular = ch.cr().read().circ();
338 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; 354 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
339 en && (circular || !tcif) 355 en && (circular || !tcif)
340 } 356 }
341 357
342 /// Gets the total remaining transfers for the channel 358 /// Get the total remaining transfers for the channel.
343 /// Note: this will be zero for transfers that completed without cancellation. 359 ///
360 /// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop).
344 pub fn get_remaining_transfers(&self) -> u16 { 361 pub fn get_remaining_transfers(&self) -> u16 {
345 let ch = self.channel.regs().ch(self.channel.num()); 362 let ch = self.channel.regs().ch(self.channel.num());
346 ch.ndtr().read().ndt() 363 ch.ndtr().read().ndt()
347 } 364 }
348 365
366 /// Blocking wait until the transfer finishes.
349 pub fn blocking_wait(mut self) { 367 pub fn blocking_wait(mut self) {
350 while self.is_running() {} 368 while self.is_running() {}
351 self.request_stop(); 369 self.request_stop();
@@ -411,6 +429,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
411 } 429 }
412} 430}
413 431
432/// Ringbuffer for reading data using DMA circular mode.
414pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 433pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
415 cr: regs::Cr, 434 cr: regs::Cr,
416 channel: PeripheralRef<'a, C>, 435 channel: PeripheralRef<'a, C>,
@@ -418,7 +437,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
418} 437}
419 438
420impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { 439impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
421 pub unsafe fn new_read( 440 /// Create a new ring buffer.
441 pub unsafe fn new(
422 channel: impl Peripheral<P = C> + 'a, 442 channel: impl Peripheral<P = C> + 'a,
423 _request: Request, 443 _request: Request,
424 peri_addr: *mut W, 444 peri_addr: *mut W,
@@ -445,12 +465,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
445 let mut w = regs::Cr(0); 465 let mut w = regs::Cr(0);
446 w.set_psize(data_size.into()); 466 w.set_psize(data_size.into());
447 w.set_msize(data_size.into()); 467 w.set_msize(data_size.into());
448 w.set_minc(vals::Inc::ENABLED); 468 w.set_minc(true);
449 w.set_dir(dir.into()); 469 w.set_dir(dir.into());
450 w.set_teie(true); 470 w.set_teie(true);
451 w.set_htie(true); 471 w.set_htie(true);
452 w.set_tcie(true); 472 w.set_tcie(true);
453 w.set_circ(vals::Circ::ENABLED); 473 w.set_circ(true);
454 w.set_pl(vals::Pl::VERYHIGH); 474 w.set_pl(vals::Pl::VERYHIGH);
455 w.set_en(true); 475 w.set_en(true);
456 476
@@ -473,11 +493,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
473 this 493 this
474 } 494 }
475 495
496 /// Start the ring buffer operation.
497 ///
498 /// You must call this after creating it for it to work.
476 pub fn start(&mut self) { 499 pub fn start(&mut self) {
477 let ch = self.channel.regs().ch(self.channel.num()); 500 let ch = self.channel.regs().ch(self.channel.num());
478 ch.cr().write_value(self.cr) 501 ch.cr().write_value(self.cr)
479 } 502 }
480 503
504 /// Clear all data in the ring buffer.
481 pub fn clear(&mut self) { 505 pub fn clear(&mut self) {
482 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 506 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
483 } 507 }
@@ -509,10 +533,11 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
509 } 533 }
510 534
511 /// The capacity of the ringbuffer. 535 /// The capacity of the ringbuffer.
512 pub const fn cap(&self) -> usize { 536 pub const fn capacity(&self) -> usize {
513 self.ringbuf.cap() 537 self.ringbuf.cap()
514 } 538 }
515 539
540 /// Set a waker to be woken when at least one byte is received.
516 pub fn set_waker(&mut self, waker: &Waker) { 541 pub fn set_waker(&mut self, waker: &Waker) {
517 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 542 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
518 } 543 }
@@ -526,6 +551,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
526 }); 551 });
527 } 552 }
528 553
554 /// Request DMA to stop.
555 ///
556 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
529 pub fn request_stop(&mut self) { 557 pub fn request_stop(&mut self) {
530 let ch = self.channel.regs().ch(self.channel.num()); 558 let ch = self.channel.regs().ch(self.channel.num());
531 559
@@ -539,6 +567,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
539 }); 567 });
540 } 568 }
541 569
570 /// Return whether DMA is still running.
571 ///
572 /// If this returns `false`, it can be because either the transfer finished, or
573 /// it was requested to stop early with [`request_stop`](Self::request_stop).
542 pub fn is_running(&mut self) -> bool { 574 pub fn is_running(&mut self) -> bool {
543 let ch = self.channel.regs().ch(self.channel.num()); 575 let ch = self.channel.regs().ch(self.channel.num());
544 ch.cr().read().en() 576 ch.cr().read().en()
@@ -555,6 +587,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
555 } 587 }
556} 588}
557 589
590/// Ringbuffer for writing data using DMA circular mode.
558pub struct WritableRingBuffer<'a, C: Channel, W: Word> { 591pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
559 cr: regs::Cr, 592 cr: regs::Cr,
560 channel: PeripheralRef<'a, C>, 593 channel: PeripheralRef<'a, C>,
@@ -562,7 +595,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
562} 595}
563 596
564impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { 597impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
565 pub unsafe fn new_write( 598 /// Create a new ring buffer.
599 pub unsafe fn new(
566 channel: impl Peripheral<P = C> + 'a, 600 channel: impl Peripheral<P = C> + 'a,
567 _request: Request, 601 _request: Request,
568 peri_addr: *mut W, 602 peri_addr: *mut W,
@@ -589,12 +623,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
589 let mut w = regs::Cr(0); 623 let mut w = regs::Cr(0);
590 w.set_psize(data_size.into()); 624 w.set_psize(data_size.into());
591 w.set_msize(data_size.into()); 625 w.set_msize(data_size.into());
592 w.set_minc(vals::Inc::ENABLED); 626 w.set_minc(true);
593 w.set_dir(dir.into()); 627 w.set_dir(dir.into());
594 w.set_teie(true); 628 w.set_teie(true);
595 w.set_htie(true); 629 w.set_htie(true);
596 w.set_tcie(true); 630 w.set_tcie(true);
597 w.set_circ(vals::Circ::ENABLED); 631 w.set_circ(true);
598 w.set_pl(vals::Pl::VERYHIGH); 632 w.set_pl(vals::Pl::VERYHIGH);
599 w.set_en(true); 633 w.set_en(true);
600 634
@@ -617,11 +651,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
617 this 651 this
618 } 652 }
619 653
654 /// Start the ring buffer operation.
655 ///
656 /// You must call this after creating it for it to work.
620 pub fn start(&mut self) { 657 pub fn start(&mut self) {
621 let ch = self.channel.regs().ch(self.channel.num()); 658 let ch = self.channel.regs().ch(self.channel.num());
622 ch.cr().write_value(self.cr) 659 ch.cr().write_value(self.cr)
623 } 660 }
624 661
662 /// Clear all data in the ring buffer.
625 pub fn clear(&mut self) { 663 pub fn clear(&mut self) {
626 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 664 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
627 } 665 }
@@ -640,10 +678,11 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
640 } 678 }
641 679
642 /// The capacity of the ringbuffer. 680 /// The capacity of the ringbuffer.
643 pub const fn cap(&self) -> usize { 681 pub const fn capacity(&self) -> usize {
644 self.ringbuf.cap() 682 self.ringbuf.cap()
645 } 683 }
646 684
685 /// Set a waker to be woken when at least one byte is sent.
647 pub fn set_waker(&mut self, waker: &Waker) { 686 pub fn set_waker(&mut self, waker: &Waker) {
648 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 687 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
649 } 688 }
@@ -657,6 +696,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
657 }); 696 });
658 } 697 }
659 698
699 /// Request DMA to stop.
700 ///
701 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
660 pub fn request_stop(&mut self) { 702 pub fn request_stop(&mut self) {
661 let ch = self.channel.regs().ch(self.channel.num()); 703 let ch = self.channel.regs().ch(self.channel.num());
662 704
@@ -670,6 +712,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
670 }); 712 });
671 } 713 }
672 714
715 /// Return whether DMA is still running.
716 ///
717 /// If this returns `false`, it can be because either the transfer finished, or
718 /// it was requested to stop early with [`request_stop`](Self::request_stop).
673 pub fn is_running(&mut self) -> bool { 719 pub fn is_running(&mut self) -> bool {
674 let ch = self.channel.regs().ch(self.channel.num()); 720 let ch = self.channel.regs().ch(self.channel.num());
675 ch.cr().read().en() 721 ch.cr().read().en()
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index cce0407c1..16d02f273 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -16,6 +16,7 @@ use crate::interrupt::Priority;
16use crate::pac::dma::{regs, vals}; 16use crate::pac::dma::{regs, vals};
17use crate::{interrupt, pac}; 17use crate::{interrupt, pac};
18 18
19/// DMA transfer options.
19#[derive(Debug, Copy, Clone, PartialEq, Eq)] 20#[derive(Debug, Copy, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[non_exhaustive] 22#[non_exhaustive]
@@ -29,6 +30,10 @@ pub struct TransferOptions {
29 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. 30 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
30 pub fifo_threshold: Option<FifoThreshold>, 31 pub fifo_threshold: Option<FifoThreshold>,
31 /// Enable circular DMA 32 /// Enable circular DMA
33 ///
34 /// Note:
35 /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task.
36 /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever.
32 pub circular: bool, 37 pub circular: bool,
33 /// Enable half transfer interrupt 38 /// Enable half transfer interrupt
34 pub half_transfer_ir: bool, 39 pub half_transfer_ir: bool,
@@ -69,6 +74,7 @@ impl From<Dir> for vals::Dir {
69 } 74 }
70} 75}
71 76
77/// DMA transfer burst setting.
72#[derive(Debug, Copy, Clone, PartialEq, Eq)] 78#[derive(Debug, Copy, Clone, PartialEq, Eq)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))] 79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub enum Burst { 80pub enum Burst {
@@ -93,6 +99,7 @@ impl From<Burst> for vals::Burst {
93 } 99 }
94} 100}
95 101
102/// DMA flow control setting.
96#[derive(Debug, Copy, Clone, PartialEq, Eq)] 103#[derive(Debug, Copy, Clone, PartialEq, Eq)]
97#[cfg_attr(feature = "defmt", derive(defmt::Format))] 104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98pub enum FlowControl { 105pub enum FlowControl {
@@ -111,6 +118,7 @@ impl From<FlowControl> for vals::Pfctrl {
111 } 118 }
112} 119}
113 120
121/// DMA FIFO threshold.
114#[derive(Debug, Copy, Clone, PartialEq, Eq)] 122#[derive(Debug, Copy, Clone, PartialEq, Eq)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))] 123#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub enum FifoThreshold { 124pub enum FifoThreshold {
@@ -208,13 +216,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
208 STATE.ch_wakers[index].wake(); 216 STATE.ch_wakers[index].wake();
209} 217}
210 218
219/// DMA request type alias. (also known as DMA channel number in some chips)
211#[cfg(any(dma_v2, dmamux))] 220#[cfg(any(dma_v2, dmamux))]
212pub type Request = u8; 221pub type Request = u8;
222/// DMA request type alias. (also known as DMA channel number in some chips)
213#[cfg(not(any(dma_v2, dmamux)))] 223#[cfg(not(any(dma_v2, dmamux)))]
214pub type Request = (); 224pub type Request = ();
215 225
226/// DMA channel.
216#[cfg(dmamux)] 227#[cfg(dmamux)]
217pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 228pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
229/// DMA channel.
218#[cfg(not(dmamux))] 230#[cfg(not(dmamux))]
219pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 231pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
220 232
@@ -229,12 +241,14 @@ pub(crate) mod sealed {
229 } 241 }
230} 242}
231 243
244/// DMA transfer.
232#[must_use = "futures do nothing unless you `.await` or poll them"] 245#[must_use = "futures do nothing unless you `.await` or poll them"]
233pub struct Transfer<'a, C: Channel> { 246pub struct Transfer<'a, C: Channel> {
234 channel: PeripheralRef<'a, C>, 247 channel: PeripheralRef<'a, C>,
235} 248}
236 249
237impl<'a, C: Channel> Transfer<'a, C> { 250impl<'a, C: Channel> Transfer<'a, C> {
251 /// Create a new read DMA transfer (peripheral to memory).
238 pub unsafe fn new_read<W: Word>( 252 pub unsafe fn new_read<W: Word>(
239 channel: impl Peripheral<P = C> + 'a, 253 channel: impl Peripheral<P = C> + 'a,
240 request: Request, 254 request: Request,
@@ -245,6 +259,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
245 Self::new_read_raw(channel, request, peri_addr, buf, options) 259 Self::new_read_raw(channel, request, peri_addr, buf, options)
246 } 260 }
247 261
262 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
248 pub unsafe fn new_read_raw<W: Word>( 263 pub unsafe fn new_read_raw<W: Word>(
249 channel: impl Peripheral<P = C> + 'a, 264 channel: impl Peripheral<P = C> + 'a,
250 request: Request, 265 request: Request,
@@ -270,6 +285,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
270 ) 285 )
271 } 286 }
272 287
288 /// Create a new write DMA transfer (memory to peripheral).
273 pub unsafe fn new_write<W: Word>( 289 pub unsafe fn new_write<W: Word>(
274 channel: impl Peripheral<P = C> + 'a, 290 channel: impl Peripheral<P = C> + 'a,
275 request: Request, 291 request: Request,
@@ -280,6 +296,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
280 Self::new_write_raw(channel, request, buf, peri_addr, options) 296 Self::new_write_raw(channel, request, buf, peri_addr, options)
281 } 297 }
282 298
299 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
283 pub unsafe fn new_write_raw<W: Word>( 300 pub unsafe fn new_write_raw<W: Word>(
284 channel: impl Peripheral<P = C> + 'a, 301 channel: impl Peripheral<P = C> + 'a,
285 request: Request, 302 request: Request,
@@ -305,6 +322,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
305 ) 322 )
306 } 323 }
307 324
325 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
308 pub unsafe fn new_write_repeated<W: Word>( 326 pub unsafe fn new_write_repeated<W: Word>(
309 channel: impl Peripheral<P = C> + 'a, 327 channel: impl Peripheral<P = C> + 'a,
310 request: Request, 328 request: Request,
@@ -368,18 +386,13 @@ impl<'a, C: Channel> Transfer<'a, C> {
368 w.set_msize(data_size.into()); 386 w.set_msize(data_size.into());
369 w.set_psize(data_size.into()); 387 w.set_psize(data_size.into());
370 w.set_pl(vals::Pl::VERYHIGH); 388 w.set_pl(vals::Pl::VERYHIGH);
371 w.set_minc(match incr_mem { 389 w.set_minc(incr_mem);
372 true => vals::Inc::INCREMENTED, 390 w.set_pinc(false);
373 false => vals::Inc::FIXED,
374 });
375 w.set_pinc(vals::Inc::FIXED);
376 w.set_teie(true); 391 w.set_teie(true);
377 w.set_tcie(options.complete_transfer_ir); 392 w.set_tcie(options.complete_transfer_ir);
393 w.set_circ(options.circular);
378 if options.circular { 394 if options.circular {
379 w.set_circ(vals::Circ::ENABLED);
380 debug!("Setting circular mode"); 395 debug!("Setting circular mode");
381 } else {
382 w.set_circ(vals::Circ::DISABLED);
383 } 396 }
384 #[cfg(dma_v1)] 397 #[cfg(dma_v1)]
385 w.set_trbuff(true); 398 w.set_trbuff(true);
@@ -407,6 +420,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
407 }); 420 });
408 } 421 }
409 422
423 /// Request the transfer to stop.
424 ///
425 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
410 pub fn request_stop(&mut self) { 426 pub fn request_stop(&mut self) {
411 let ch = self.channel.regs().st(self.channel.num()); 427 let ch = self.channel.regs().st(self.channel.num());
412 428
@@ -417,6 +433,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
417 }); 433 });
418 } 434 }
419 435
436 /// Return whether this transfer is still running.
437 ///
438 /// If this returns `false`, it can be because either the transfer finished, or
439 /// it was requested to stop early with [`request_stop`](Self::request_stop).
420 pub fn is_running(&mut self) -> bool { 440 pub fn is_running(&mut self) -> bool {
421 let ch = self.channel.regs().st(self.channel.num()); 441 let ch = self.channel.regs().st(self.channel.num());
422 ch.cr().read().en() 442 ch.cr().read().en()
@@ -429,6 +449,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
429 ch.ndtr().read().ndt() 449 ch.ndtr().read().ndt()
430 } 450 }
431 451
452 /// Blocking wait until the transfer finishes.
432 pub fn blocking_wait(mut self) { 453 pub fn blocking_wait(mut self) {
433 while self.is_running() {} 454 while self.is_running() {}
434 455
@@ -465,12 +486,14 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
465 486
466// ================================== 487// ==================================
467 488
489/// Double-buffered DMA transfer.
468pub struct DoubleBuffered<'a, C: Channel, W: Word> { 490pub struct DoubleBuffered<'a, C: Channel, W: Word> {
469 channel: PeripheralRef<'a, C>, 491 channel: PeripheralRef<'a, C>,
470 _phantom: PhantomData<W>, 492 _phantom: PhantomData<W>,
471} 493}
472 494
473impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { 495impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
496 /// Create a new read DMA transfer (peripheral to memory).
474 pub unsafe fn new_read( 497 pub unsafe fn new_read(
475 channel: impl Peripheral<P = C> + 'a, 498 channel: impl Peripheral<P = C> + 'a,
476 _request: Request, 499 _request: Request,
@@ -521,8 +544,8 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
521 w.set_msize(data_size.into()); 544 w.set_msize(data_size.into());
522 w.set_psize(data_size.into()); 545 w.set_psize(data_size.into());
523 w.set_pl(vals::Pl::VERYHIGH); 546 w.set_pl(vals::Pl::VERYHIGH);
524 w.set_minc(vals::Inc::INCREMENTED); 547 w.set_minc(true);
525 w.set_pinc(vals::Inc::FIXED); 548 w.set_pinc(false);
526 w.set_teie(true); 549 w.set_teie(true);
527 w.set_tcie(true); 550 w.set_tcie(true);
528 #[cfg(dma_v1)] 551 #[cfg(dma_v1)]
@@ -554,25 +577,36 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
554 }); 577 });
555 } 578 }
556 579
580 /// Set the first buffer address.
581 ///
582 /// You may call this while DMA is transferring the other buffer.
557 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { 583 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
558 let ch = self.channel.regs().st(self.channel.num()); 584 let ch = self.channel.regs().st(self.channel.num());
559 ch.m0ar().write_value(buffer as _); 585 ch.m0ar().write_value(buffer as _);
560 } 586 }
561 587
588 /// Set the second buffer address.
589 ///
590 /// You may call this while DMA is transferring the other buffer.
562 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { 591 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) {
563 let ch = self.channel.regs().st(self.channel.num()); 592 let ch = self.channel.regs().st(self.channel.num());
564 ch.m1ar().write_value(buffer as _); 593 ch.m1ar().write_value(buffer as _);
565 } 594 }
566 595
596 /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now)
567 pub fn is_buffer0_accessible(&mut self) -> bool { 597 pub fn is_buffer0_accessible(&mut self) -> bool {
568 let ch = self.channel.regs().st(self.channel.num()); 598 let ch = self.channel.regs().st(self.channel.num());
569 ch.cr().read().ct() == vals::Ct::MEMORY1 599 ch.cr().read().ct() == vals::Ct::MEMORY1
570 } 600 }
571 601
602 /// Set a waker to be woken when one of the buffers is being transferred.
572 pub fn set_waker(&mut self, waker: &Waker) { 603 pub fn set_waker(&mut self, waker: &Waker) {
573 STATE.ch_wakers[self.channel.index()].register(waker); 604 STATE.ch_wakers[self.channel.index()].register(waker);
574 } 605 }
575 606
607 /// Request the transfer to stop.
608 ///
609 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
576 pub fn request_stop(&mut self) { 610 pub fn request_stop(&mut self) {
577 let ch = self.channel.regs().st(self.channel.num()); 611 let ch = self.channel.regs().st(self.channel.num());
578 612
@@ -583,6 +617,10 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
583 }); 617 });
584 } 618 }
585 619
620 /// Return whether this transfer is still running.
621 ///
622 /// If this returns `false`, it can be because either the transfer finished, or
623 /// it was requested to stop early with [`request_stop`](Self::request_stop).
586 pub fn is_running(&mut self) -> bool { 624 pub fn is_running(&mut self) -> bool {
587 let ch = self.channel.regs().st(self.channel.num()); 625 let ch = self.channel.regs().st(self.channel.num());
588 ch.cr().read().en() 626 ch.cr().read().en()
@@ -629,6 +667,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
629 } 667 }
630} 668}
631 669
670/// Ringbuffer for receiving data using DMA circular mode.
632pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 671pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
633 cr: regs::Cr, 672 cr: regs::Cr,
634 channel: PeripheralRef<'a, C>, 673 channel: PeripheralRef<'a, C>,
@@ -636,7 +675,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
636} 675}
637 676
638impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { 677impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
639 pub unsafe fn new_read( 678 /// Create a new ring buffer.
679 pub unsafe fn new(
640 channel: impl Peripheral<P = C> + 'a, 680 channel: impl Peripheral<P = C> + 'a,
641 _request: Request, 681 _request: Request,
642 peri_addr: *mut W, 682 peri_addr: *mut W,
@@ -662,12 +702,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
662 w.set_msize(data_size.into()); 702 w.set_msize(data_size.into());
663 w.set_psize(data_size.into()); 703 w.set_psize(data_size.into());
664 w.set_pl(vals::Pl::VERYHIGH); 704 w.set_pl(vals::Pl::VERYHIGH);
665 w.set_minc(vals::Inc::INCREMENTED); 705 w.set_minc(true);
666 w.set_pinc(vals::Inc::FIXED); 706 w.set_pinc(false);
667 w.set_teie(true); 707 w.set_teie(true);
668 w.set_htie(options.half_transfer_ir); 708 w.set_htie(options.half_transfer_ir);
669 w.set_tcie(true); 709 w.set_tcie(true);
670 w.set_circ(vals::Circ::ENABLED); 710 w.set_circ(true);
671 #[cfg(dma_v1)] 711 #[cfg(dma_v1)]
672 w.set_trbuff(true); 712 w.set_trbuff(true);
673 #[cfg(dma_v2)] 713 #[cfg(dma_v2)]
@@ -706,11 +746,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
706 this 746 this
707 } 747 }
708 748
749 /// Start the ring buffer operation.
750 ///
751 /// You must call this after creating it for it to work.
709 pub fn start(&mut self) { 752 pub fn start(&mut self) {
710 let ch = self.channel.regs().st(self.channel.num()); 753 let ch = self.channel.regs().st(self.channel.num());
711 ch.cr().write_value(self.cr); 754 ch.cr().write_value(self.cr);
712 } 755 }
713 756
757 /// Clear all data in the ring buffer.
714 pub fn clear(&mut self) { 758 pub fn clear(&mut self) {
715 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 759 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
716 } 760 }
@@ -741,11 +785,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
741 .await 785 .await
742 } 786 }
743 787
744 // The capacity of the ringbuffer 788 /// The capacity of the ringbuffer
745 pub const fn cap(&self) -> usize { 789 pub const fn capacity(&self) -> usize {
746 self.ringbuf.cap() 790 self.ringbuf.cap()
747 } 791 }
748 792
793 /// Set a waker to be woken when at least one byte is received.
749 pub fn set_waker(&mut self, waker: &Waker) { 794 pub fn set_waker(&mut self, waker: &Waker) {
750 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 795 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
751 } 796 }
@@ -763,6 +808,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
763 }); 808 });
764 } 809 }
765 810
811 /// Request DMA to stop.
812 ///
813 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
766 pub fn request_stop(&mut self) { 814 pub fn request_stop(&mut self) {
767 let ch = self.channel.regs().st(self.channel.num()); 815 let ch = self.channel.regs().st(self.channel.num());
768 816
@@ -774,6 +822,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
774 }); 822 });
775 } 823 }
776 824
825 /// Return whether DMA is still running.
826 ///
827 /// If this returns `false`, it can be because either the transfer finished, or
828 /// it was requested to stop early with [`request_stop`](Self::request_stop).
777 pub fn is_running(&mut self) -> bool { 829 pub fn is_running(&mut self) -> bool {
778 let ch = self.channel.regs().st(self.channel.num()); 830 let ch = self.channel.regs().st(self.channel.num());
779 ch.cr().read().en() 831 ch.cr().read().en()
@@ -790,6 +842,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
790 } 842 }
791} 843}
792 844
845/// Ringbuffer for writing data using DMA circular mode.
793pub struct WritableRingBuffer<'a, C: Channel, W: Word> { 846pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
794 cr: regs::Cr, 847 cr: regs::Cr,
795 channel: PeripheralRef<'a, C>, 848 channel: PeripheralRef<'a, C>,
@@ -797,7 +850,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
797} 850}
798 851
799impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { 852impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
800 pub unsafe fn new_write( 853 /// Create a new ring buffer.
854 pub unsafe fn new(
801 channel: impl Peripheral<P = C> + 'a, 855 channel: impl Peripheral<P = C> + 'a,
802 _request: Request, 856 _request: Request,
803 peri_addr: *mut W, 857 peri_addr: *mut W,
@@ -823,12 +877,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
823 w.set_msize(data_size.into()); 877 w.set_msize(data_size.into());
824 w.set_psize(data_size.into()); 878 w.set_psize(data_size.into());
825 w.set_pl(vals::Pl::VERYHIGH); 879 w.set_pl(vals::Pl::VERYHIGH);
826 w.set_minc(vals::Inc::INCREMENTED); 880 w.set_minc(true);
827 w.set_pinc(vals::Inc::FIXED); 881 w.set_pinc(false);
828 w.set_teie(true); 882 w.set_teie(true);
829 w.set_htie(options.half_transfer_ir); 883 w.set_htie(options.half_transfer_ir);
830 w.set_tcie(true); 884 w.set_tcie(true);
831 w.set_circ(vals::Circ::ENABLED); 885 w.set_circ(true);
832 #[cfg(dma_v1)] 886 #[cfg(dma_v1)]
833 w.set_trbuff(true); 887 w.set_trbuff(true);
834 #[cfg(dma_v2)] 888 #[cfg(dma_v2)]
@@ -867,11 +921,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
867 this 921 this
868 } 922 }
869 923
924 /// Start the ring buffer operation.
925 ///
926 /// You must call this after creating it for it to work.
870 pub fn start(&mut self) { 927 pub fn start(&mut self) {
871 let ch = self.channel.regs().st(self.channel.num()); 928 let ch = self.channel.regs().st(self.channel.num());
872 ch.cr().write_value(self.cr); 929 ch.cr().write_value(self.cr);
873 } 930 }
874 931
932 /// Clear all data in the ring buffer.
875 pub fn clear(&mut self) { 933 pub fn clear(&mut self) {
876 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 934 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
877 } 935 }
@@ -889,11 +947,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
889 .await 947 .await
890 } 948 }
891 949
892 // The capacity of the ringbuffer 950 /// The capacity of the ringbuffer
893 pub const fn cap(&self) -> usize { 951 pub const fn capacity(&self) -> usize {
894 self.ringbuf.cap() 952 self.ringbuf.cap()
895 } 953 }
896 954
955 /// Set a waker to be woken when at least one byte is received.
897 pub fn set_waker(&mut self, waker: &Waker) { 956 pub fn set_waker(&mut self, waker: &Waker) {
898 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 957 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
899 } 958 }
@@ -911,6 +970,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
911 }); 970 });
912 } 971 }
913 972
973 /// Request DMA to stop.
974 ///
975 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
914 pub fn request_stop(&mut self) { 976 pub fn request_stop(&mut self) {
915 let ch = self.channel.regs().st(self.channel.num()); 977 let ch = self.channel.regs().st(self.channel.num());
916 978
@@ -922,6 +984,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
922 }); 984 });
923 } 985 }
924 986
987 /// Return whether DMA is still running.
988 ///
989 /// If this returns `false`, it can be because either the transfer finished, or
990 /// it was requested to stop early with [`request_stop`](Self::request_stop).
925 pub fn is_running(&mut self) -> bool { 991 pub fn is_running(&mut self) -> bool {
926 let ch = self.channel.regs().st(self.channel.num()); 992 let ch = self.channel.regs().st(self.channel.num());
927 ch.cr().read().en() 993 ch.cr().read().en()
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
index 20601dc86..9cd494724 100644
--- a/embassy-stm32/src/dma/dmamux.rs
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -22,11 +22,15 @@ pub(crate) mod dmamux_sealed {
22 } 22 }
23} 23}
24 24
25/// DMAMUX1 instance.
25pub struct DMAMUX1; 26pub struct DMAMUX1;
27/// DMAMUX2 instance.
26#[cfg(stm32h7)] 28#[cfg(stm32h7)]
27pub struct DMAMUX2; 29pub struct DMAMUX2;
28 30
31/// DMAMUX channel trait.
29pub trait MuxChannel: dmamux_sealed::MuxChannel { 32pub trait MuxChannel: dmamux_sealed::MuxChannel {
33 /// DMAMUX instance this channel is on.
30 type Mux; 34 type Mux;
31} 35}
32 36
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index b061415eb..34b2426b9 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -16,6 +16,7 @@ use crate::interrupt::Priority;
16use crate::pac; 16use crate::pac;
17use crate::pac::gpdma::vals; 17use crate::pac::gpdma::vals;
18 18
19/// GPDMA transfer options.
19#[derive(Debug, Copy, Clone, PartialEq, Eq)] 20#[derive(Debug, Copy, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[non_exhaustive] 22#[non_exhaustive]
@@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
113 } 114 }
114} 115}
115 116
117/// DMA request type alias. (also known as DMA channel number in some chips)
116pub type Request = u8; 118pub type Request = u8;
117 119
120/// DMA channel.
118#[cfg(dmamux)] 121#[cfg(dmamux)]
119pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 122pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
123/// DMA channel.
120#[cfg(not(dmamux))] 124#[cfg(not(dmamux))]
121pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 125pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
122 126
@@ -131,12 +135,14 @@ pub(crate) mod sealed {
131 } 135 }
132} 136}
133 137
138/// DMA transfer.
134#[must_use = "futures do nothing unless you `.await` or poll them"] 139#[must_use = "futures do nothing unless you `.await` or poll them"]
135pub struct Transfer<'a, C: Channel> { 140pub struct Transfer<'a, C: Channel> {
136 channel: PeripheralRef<'a, C>, 141 channel: PeripheralRef<'a, C>,
137} 142}
138 143
139impl<'a, C: Channel> Transfer<'a, C> { 144impl<'a, C: Channel> Transfer<'a, C> {
145 /// Create a new read DMA transfer (peripheral to memory).
140 pub unsafe fn new_read<W: Word>( 146 pub unsafe fn new_read<W: Word>(
141 channel: impl Peripheral<P = C> + 'a, 147 channel: impl Peripheral<P = C> + 'a,
142 request: Request, 148 request: Request,
@@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
147 Self::new_read_raw(channel, request, peri_addr, buf, options) 153 Self::new_read_raw(channel, request, peri_addr, buf, options)
148 } 154 }
149 155
156 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
150 pub unsafe fn new_read_raw<W: Word>( 157 pub unsafe fn new_read_raw<W: Word>(
151 channel: impl Peripheral<P = C> + 'a, 158 channel: impl Peripheral<P = C> + 'a,
152 request: Request, 159 request: Request,
@@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
172 ) 179 )
173 } 180 }
174 181
182 /// Create a new write DMA transfer (memory to peripheral).
175 pub unsafe fn new_write<W: Word>( 183 pub unsafe fn new_write<W: Word>(
176 channel: impl Peripheral<P = C> + 'a, 184 channel: impl Peripheral<P = C> + 'a,
177 request: Request, 185 request: Request,
@@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
182 Self::new_write_raw(channel, request, buf, peri_addr, options) 190 Self::new_write_raw(channel, request, buf, peri_addr, options)
183 } 191 }
184 192
193 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
185 pub unsafe fn new_write_raw<W: Word>( 194 pub unsafe fn new_write_raw<W: Word>(
186 channel: impl Peripheral<P = C> + 'a, 195 channel: impl Peripheral<P = C> + 'a,
187 request: Request, 196 request: Request,
@@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
207 ) 216 )
208 } 217 }
209 218
219 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
210 pub unsafe fn new_write_repeated<W: Word>( 220 pub unsafe fn new_write_repeated<W: Word>(
211 channel: impl Peripheral<P = C> + 'a, 221 channel: impl Peripheral<P = C> + 'a,
212 request: Request, 222 request: Request,
@@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
297 this 307 this
298 } 308 }
299 309
310 /// Request the transfer to stop.
311 ///
312 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
300 pub fn request_stop(&mut self) { 313 pub fn request_stop(&mut self) {
301 let ch = self.channel.regs().ch(self.channel.num()); 314 let ch = self.channel.regs().ch(self.channel.num());
302 ch.cr().modify(|w| { 315 ch.cr().modify(|w| {
@@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
304 }) 317 })
305 } 318 }
306 319
320 /// Return whether this transfer is still running.
321 ///
322 /// If this returns `false`, it can be because either the transfer finished, or
323 /// it was requested to stop early with [`request_stop`](Self::request_stop).
307 pub fn is_running(&mut self) -> bool { 324 pub fn is_running(&mut self) -> bool {
308 let ch = self.channel.regs().ch(self.channel.num()); 325 let ch = self.channel.regs().ch(self.channel.num());
309 let sr = ch.sr().read(); 326 let sr = ch.sr().read();
@@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
317 ch.br1().read().bndt() 334 ch.br1().read().bndt()
318 } 335 }
319 336
337 /// Blocking wait until the transfer finishes.
320 pub fn blocking_wait(mut self) { 338 pub fn blocking_wait(mut self) {
321 while self.is_running() {} 339 while self.is_running() {}
322 340
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 29fced8fc..38945ac33 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -1,3 +1,5 @@
1//! Direct Memory Access (DMA)
2
1#[cfg(dma)] 3#[cfg(dma)]
2pub(crate) mod dma; 4pub(crate) mod dma;
3#[cfg(dma)] 5#[cfg(dma)]
@@ -39,6 +41,13 @@ enum Dir {
39 PeripheralToMemory, 41 PeripheralToMemory,
40} 42}
41 43
44/// "No DMA" placeholder.
45///
46/// You may pass this in place of a real DMA channel when creating a driver
47/// to indicate it should not use DMA.
48///
49/// This often causes async functionality to not be available on the instance,
50/// leaving only blocking functionality.
42pub struct NoDma; 51pub struct NoDma;
43 52
44impl_peripheral!(NoDma); 53impl_peripheral!(NoDma);
diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs
index aef6e9700..a72c4b7d9 100644
--- a/embassy-stm32/src/dma/word.rs
+++ b/embassy-stm32/src/dma/word.rs
@@ -1,3 +1,6 @@
1//! DMA word sizes.
2
3#[allow(missing_docs)]
1#[derive(Debug, Copy, Clone, PartialEq, Eq)] 4#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
3pub enum WordSize { 6pub enum WordSize {
@@ -7,6 +10,7 @@ pub enum WordSize {
7} 10}
8 11
9impl WordSize { 12impl WordSize {
13 /// Amount of bytes of this word size.
10 pub fn bytes(&self) -> usize { 14 pub fn bytes(&self) -> usize {
11 match self { 15 match self {
12 Self::OneByte => 1, 16 Self::OneByte => 1,
@@ -20,8 +24,13 @@ mod sealed {
20 pub trait Word {} 24 pub trait Word {}
21} 25}
22 26
27/// DMA word trait.
28///
29/// This is implemented for u8, u16, u32, etc.
23pub trait Word: sealed::Word + Default + Copy + 'static { 30pub trait Word: sealed::Word + Default + Copy + 'static {
31 /// Word size
24 fn size() -> WordSize; 32 fn size() -> WordSize;
33 /// Amount of bits of this word size.
25 fn bits() -> usize; 34 fn bits() -> usize;
26} 35}
27 36
@@ -40,6 +49,7 @@ macro_rules! impl_word {
40 ($T:ident, $uX:ident, $bits:literal, $size:ident) => { 49 ($T:ident, $uX:ident, $bits:literal, $size:ident) => {
41 #[repr(transparent)] 50 #[repr(transparent)]
42 #[derive(Copy, Clone, Default)] 51 #[derive(Copy, Clone, Default)]
52 #[doc = concat!(stringify!($T), " word size")]
43 pub struct $T(pub $uX); 53 pub struct $T(pub $uX);
44 impl_word!(_, $T, $bits, $size); 54 impl_word!(_, $T, $bits, $size);
45 }; 55 };
diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs
index 1e1094a1c..9c26e90f1 100644
--- a/embassy-stm32/src/eth/generic_smi.rs
+++ b/embassy-stm32/src/eth/generic_smi.rs
@@ -102,6 +102,7 @@ unsafe impl PHY for GenericSMI {
102 102
103/// Public functions for the PHY 103/// Public functions for the PHY
104impl GenericSMI { 104impl GenericSMI {
105 /// Set the SMI polling interval.
105 #[cfg(feature = "time")] 106 #[cfg(feature = "time")]
106 pub fn set_poll_interval(&mut self, poll_interval: Duration) { 107 pub fn set_poll_interval(&mut self, poll_interval: Duration) {
107 self.poll_interval = poll_interval 108 self.poll_interval = poll_interval
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 556aadd73..448405507 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -1,3 +1,4 @@
1//! Ethernet (ETH)
1#![macro_use] 2#![macro_use]
2 3
3#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] 4#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
@@ -22,6 +23,14 @@ const RX_BUFFER_SIZE: usize = 1536;
22#[derive(Copy, Clone)] 23#[derive(Copy, Clone)]
23pub(crate) struct Packet<const N: usize>([u8; N]); 24pub(crate) struct Packet<const N: usize>([u8; N]);
24 25
26/// Ethernet packet queue.
27///
28/// This struct owns the memory used for reading and writing packets.
29///
30/// `TX` is the number of packets in the transmit queue, `RX` in the receive
31/// queue. A bigger queue allows the hardware to receive more packets while the
32/// CPU is busy doing other things, which may increase performance (especially for RX)
33/// at the cost of more RAM usage.
25pub struct PacketQueue<const TX: usize, const RX: usize> { 34pub struct PacketQueue<const TX: usize, const RX: usize> {
26 tx_desc: [TDes; TX], 35 tx_desc: [TDes; TX],
27 rx_desc: [RDes; RX], 36 rx_desc: [RDes; RX],
@@ -30,6 +39,7 @@ pub struct PacketQueue<const TX: usize, const RX: usize> {
30} 39}
31 40
32impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { 41impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
42 /// Create a new packet queue.
33 pub const fn new() -> Self { 43 pub const fn new() -> Self {
34 const NEW_TDES: TDes = TDes::new(); 44 const NEW_TDES: TDes = TDes::new();
35 const NEW_RDES: RDes = RDes::new(); 45 const NEW_RDES: RDes = RDes::new();
@@ -41,7 +51,18 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
41 } 51 }
42 } 52 }
43 53
44 // Allow to initialize a Self without requiring it to go on the stack 54 /// Initialize a packet queue in-place.
55 ///
56 /// This can be helpful to avoid accidentally stack-allocating the packet queue in the stack. The
57 /// Rust compiler can sometimes be a bit dumb when working with large owned values: if you call `new()`
58 /// and then store the returned PacketQueue in its final place (like a `static`), the compiler might
59 /// place it temporarily on the stack then move it. Since this struct is quite big, it may result
60 /// in a stack overflow.
61 ///
62 /// With this function, you can create an uninitialized `static` with type `MaybeUninit<PacketQueue<...>>`
63 /// and initialize it in-place, guaranteeing no stack usage.
64 ///
65 /// After calling this function, calling `assume_init` on the MaybeUninit is guaranteed safe.
45 pub fn init(this: &mut MaybeUninit<Self>) { 66 pub fn init(this: &mut MaybeUninit<Self>) {
46 unsafe { 67 unsafe {
47 this.as_mut_ptr().write_bytes(0u8, 1); 68 this.as_mut_ptr().write_bytes(0u8, 1);
@@ -93,6 +114,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P>
93 } 114 }
94} 115}
95 116
117/// `embassy-net` RX token.
96pub struct RxToken<'a, 'd> { 118pub struct RxToken<'a, 'd> {
97 rx: &'a mut RDesRing<'d>, 119 rx: &'a mut RDesRing<'d>,
98} 120}
@@ -110,6 +132,7 @@ impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> {
110 } 132 }
111} 133}
112 134
135/// `embassy-net` TX token.
113pub struct TxToken<'a, 'd> { 136pub struct TxToken<'a, 'd> {
114 tx: &'a mut TDesRing<'d>, 137 tx: &'a mut TDesRing<'d>,
115} 138}
@@ -159,6 +182,7 @@ pub(crate) mod sealed {
159 } 182 }
160} 183}
161 184
185/// Ethernet instance.
162pub trait Instance: sealed::Instance + Send + 'static {} 186pub trait Instance: sealed::Instance + Send + 'static {}
163 187
164impl sealed::Instance for crate::peripherals::ETH { 188impl sealed::Instance for crate::peripherals::ETH {
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 13e53f687..2ce5b3927 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -43,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
43 } 43 }
44} 44}
45 45
46/// Ethernet driver.
46pub struct Ethernet<'d, T: Instance, P: PHY> { 47pub struct Ethernet<'d, T: Instance, P: PHY> {
47 _peri: PeripheralRef<'d, T>, 48 _peri: PeripheralRef<'d, T>,
48 pub(crate) tx: TDesRing<'d>, 49 pub(crate) tx: TDesRing<'d>,
@@ -266,6 +267,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
266 } 267 }
267} 268}
268 269
270/// Ethernet station management interface.
269pub struct EthernetStationManagement<T: Instance> { 271pub struct EthernetStationManagement<T: Instance> {
270 peri: PhantomData<T>, 272 peri: PhantomData<T>,
271 clock_range: Cr, 273 clock_range: Cr,
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index c77155fea..59745cba0 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -34,6 +34,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
34 } 34 }
35} 35}
36 36
37/// Ethernet driver.
37pub struct Ethernet<'d, T: Instance, P: PHY> { 38pub struct Ethernet<'d, T: Instance, P: PHY> {
38 _peri: PeripheralRef<'d, T>, 39 _peri: PeripheralRef<'d, T>,
39 pub(crate) tx: TDesRing<'d>, 40 pub(crate) tx: TDesRing<'d>,
@@ -56,6 +57,7 @@ macro_rules! config_pins {
56} 57}
57 58
58impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { 59impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
60 /// Create a new Ethernet driver.
59 pub fn new<const TX: usize, const RX: usize>( 61 pub fn new<const TX: usize, const RX: usize>(
60 queue: &'d mut PacketQueue<TX, RX>, 62 queue: &'d mut PacketQueue<TX, RX>,
61 peri: impl Peripheral<P = T> + 'd, 63 peri: impl Peripheral<P = T> + 'd,
@@ -237,6 +239,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
237 } 239 }
238} 240}
239 241
242/// Ethernet SMI driver.
240pub struct EthernetStationManagement<T: Instance> { 243pub struct EthernetStationManagement<T: Instance> {
241 peri: PhantomData<T>, 244 peri: PhantomData<T>,
242 clock_range: u8, 245 clock_range: u8,
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index dbd24804f..f83bae3ff 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -1,3 +1,4 @@
1//! External Interrupts (EXTI)
1use core::convert::Infallible; 2use core::convert::Infallible;
2use core::future::Future; 3use core::future::Future;
3use core::marker::PhantomData; 4use core::marker::PhantomData;
@@ -39,7 +40,7 @@ fn exticr_regs() -> pac::afio::Afio {
39 pac::AFIO 40 pac::AFIO
40} 41}
41 42
42pub unsafe fn on_irq() { 43unsafe fn on_irq() {
43 #[cfg(feature = "low-power")] 44 #[cfg(feature = "low-power")]
44 crate::low_power::on_wakeup_irq(); 45 crate::low_power::on_wakeup_irq();
45 46
@@ -85,7 +86,13 @@ impl Iterator for BitIter {
85 } 86 }
86} 87}
87 88
88/// EXTI input driver 89/// EXTI input driver.
90///
91/// This driver augments a GPIO `Input` with EXTI functionality. EXTI is not
92/// built into `Input` itself because it needs to take ownership of the corresponding
93/// EXTI channel, which is a limited resource.
94///
95/// Pins PA5, PB5, PC5... all use EXTI channel 5, so you can't use EXTI on, say, PA5 and PC5 at the same time.
89pub struct ExtiInput<'d, T: GpioPin> { 96pub struct ExtiInput<'d, T: GpioPin> {
90 pin: Input<'d, T>, 97 pin: Input<'d, T>,
91} 98}
@@ -93,23 +100,30 @@ pub struct ExtiInput<'d, T: GpioPin> {
93impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} 100impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
94 101
95impl<'d, T: GpioPin> ExtiInput<'d, T> { 102impl<'d, T: GpioPin> ExtiInput<'d, T> {
103 /// Create an EXTI input.
96 pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self { 104 pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self {
97 Self { pin } 105 Self { pin }
98 } 106 }
99 107
100 pub fn is_high(&self) -> bool { 108 /// Get whether the pin is high.
109 pub fn is_high(&mut self) -> bool {
101 self.pin.is_high() 110 self.pin.is_high()
102 } 111 }
103 112
104 pub fn is_low(&self) -> bool { 113 /// Get whether the pin is low.
114 pub fn is_low(&mut self) -> bool {
105 self.pin.is_low() 115 self.pin.is_low()
106 } 116 }
107 117
108 pub fn get_level(&self) -> Level { 118 /// Get the pin level.
119 pub fn get_level(&mut self) -> Level {
109 self.pin.get_level() 120 self.pin.get_level()
110 } 121 }
111 122
112 pub async fn wait_for_high<'a>(&'a mut self) { 123 /// Asynchronously wait until the pin is high.
124 ///
125 /// This returns immediately if the pin is already high.
126 pub async fn wait_for_high(&mut self) {
113 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); 127 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
114 if self.is_high() { 128 if self.is_high() {
115 return; 129 return;
@@ -117,7 +131,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
117 fut.await 131 fut.await
118 } 132 }
119 133
120 pub async fn wait_for_low<'a>(&'a mut self) { 134 /// Asynchronously wait until the pin is low.
135 ///
136 /// This returns immediately if the pin is already low.
137 pub async fn wait_for_low(&mut self) {
121 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); 138 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
122 if self.is_low() { 139 if self.is_low() {
123 return; 140 return;
@@ -125,15 +142,22 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
125 fut.await 142 fut.await
126 } 143 }
127 144
128 pub async fn wait_for_rising_edge<'a>(&'a mut self) { 145 /// Asynchronously wait until the pin sees a rising edge.
146 ///
147 /// If the pin is already high, it will wait for it to go low then back high.
148 pub async fn wait_for_rising_edge(&mut self) {
129 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await 149 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
130 } 150 }
131 151
132 pub async fn wait_for_falling_edge<'a>(&'a mut self) { 152 /// Asynchronously wait until the pin sees a falling edge.
153 ///
154 /// If the pin is already low, it will wait for it to go high then back low.
155 pub async fn wait_for_falling_edge(&mut self) {
133 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await 156 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
134 } 157 }
135 158
136 pub async fn wait_for_any_edge<'a>(&'a mut self) { 159 /// Asynchronously wait until the pin sees any edge (either rising or falling).
160 pub async fn wait_for_any_edge(&mut self) {
137 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await 161 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
138 } 162 }
139} 163}
@@ -142,11 +166,11 @@ impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T>
142 type Error = Infallible; 166 type Error = Infallible;
143 167
144 fn is_high(&self) -> Result<bool, Self::Error> { 168 fn is_high(&self) -> Result<bool, Self::Error> {
145 Ok(self.is_high()) 169 Ok(!self.pin.pin.ref_is_low())
146 } 170 }
147 171
148 fn is_low(&self) -> Result<bool, Self::Error> { 172 fn is_low(&self) -> Result<bool, Self::Error> {
149 Ok(self.is_low()) 173 Ok(self.pin.pin.ref_is_low())
150 } 174 }
151} 175}
152 176
@@ -155,11 +179,11 @@ impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> {
155} 179}
156 180
157impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { 181impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> {
158 fn is_high(&self) -> Result<bool, Self::Error> { 182 fn is_high(&mut self) -> Result<bool, Self::Error> {
159 Ok(self.is_high()) 183 Ok(self.is_high())
160 } 184 }
161 185
162 fn is_low(&self) -> Result<bool, Self::Error> { 186 fn is_low(&mut self) -> Result<bool, Self::Error> {
163 Ok(self.is_low()) 187 Ok(self.is_low())
164 } 188 }
165} 189}
@@ -284,6 +308,7 @@ macro_rules! foreach_exti_irq {
284 308
285macro_rules! impl_irq { 309macro_rules! impl_irq {
286 ($e:ident) => { 310 ($e:ident) => {
311 #[allow(non_snake_case)]
287 #[cfg(feature = "rt")] 312 #[cfg(feature = "rt")]
288 #[interrupt] 313 #[interrupt]
289 unsafe fn $e() { 314 unsafe fn $e() {
@@ -298,8 +323,16 @@ pub(crate) mod sealed {
298 pub trait Channel {} 323 pub trait Channel {}
299} 324}
300 325
326/// EXTI channel trait.
301pub trait Channel: sealed::Channel + Sized { 327pub trait Channel: sealed::Channel + Sized {
328 /// Get the EXTI channel number.
302 fn number(&self) -> usize; 329 fn number(&self) -> usize;
330
331 /// Type-erase (degrade) this channel into an `AnyChannel`.
332 ///
333 /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which
334 /// are all different types, into the same type. It is useful for
335 /// creating arrays of channels, or avoiding generics.
303 fn degrade(self) -> AnyChannel { 336 fn degrade(self) -> AnyChannel {
304 AnyChannel { 337 AnyChannel {
305 number: self.number() as u8, 338 number: self.number() as u8,
@@ -307,9 +340,13 @@ pub trait Channel: sealed::Channel + Sized {
307 } 340 }
308} 341}
309 342
343/// Type-erased (degraded) EXTI channel.
344///
345/// This represents ownership over any EXTI channel, known at runtime.
310pub struct AnyChannel { 346pub struct AnyChannel {
311 number: u8, 347 number: u8,
312} 348}
349
313impl_peripheral!(AnyChannel); 350impl_peripheral!(AnyChannel);
314impl sealed::Channel for AnyChannel {} 351impl sealed::Channel for AnyChannel {}
315impl Channel for AnyChannel { 352impl Channel for AnyChannel {
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index eae40c7ec..97eaece81 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -17,6 +17,7 @@ use crate::{interrupt, Peripheral};
17pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); 17pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
18 18
19impl<'d> Flash<'d, Async> { 19impl<'d> Flash<'d, Async> {
20 /// Create a new flash driver with async capabilities.
20 pub fn new( 21 pub fn new(
21 p: impl Peripheral<P = FLASH> + 'd, 22 p: impl Peripheral<P = FLASH> + 'd,
22 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd, 23 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd,
@@ -32,15 +33,26 @@ impl<'d> Flash<'d, Async> {
32 } 33 }
33 } 34 }
34 35
36 /// Split this flash driver into one instance per flash memory region.
37 ///
38 /// See module-level documentation for details on how memory regions work.
35 pub fn into_regions(self) -> FlashLayout<'d, Async> { 39 pub fn into_regions(self) -> FlashLayout<'d, Async> {
36 assert!(family::is_default_layout()); 40 assert!(family::is_default_layout());
37 FlashLayout::new(self.inner) 41 FlashLayout::new(self.inner)
38 } 42 }
39 43
44 /// Async write.
45 ///
46 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
47 /// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
40 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 48 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
41 unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } 49 unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await }
42 } 50 }
43 51
52 /// Async erase.
53 ///
54 /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
55 /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
44 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 56 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
45 unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } 57 unsafe { erase_sectored(FLASH_BASE as u32, from, to).await }
46 } 58 }
@@ -59,7 +71,7 @@ impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> {
59 const READ_SIZE: usize = super::READ_SIZE; 71 const READ_SIZE: usize = super::READ_SIZE;
60 72
61 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 73 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
62 self.read(offset, bytes) 74 self.blocking_read(offset, bytes)
63 } 75 }
64 76
65 fn capacity(&self) -> usize { 77 fn capacity(&self) -> usize {
@@ -141,15 +153,20 @@ pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Resu
141foreach_flash_region! { 153foreach_flash_region! {
142 ($type_name:ident, $write_size:literal, $erase_size:literal) => { 154 ($type_name:ident, $write_size:literal, $erase_size:literal) => {
143 impl crate::_generated::flash_regions::$type_name<'_, Async> { 155 impl crate::_generated::flash_regions::$type_name<'_, Async> {
156 /// Async read.
157 ///
158 /// Note: reading from flash can't actually block, so this is the same as `blocking_read`.
144 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 159 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
145 blocking_read(self.0.base, self.0.size, offset, bytes) 160 blocking_read(self.0.base, self.0.size, offset, bytes)
146 } 161 }
147 162
163 /// Async write.
148 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 164 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
149 let _guard = REGION_ACCESS.lock().await; 165 let _guard = REGION_ACCESS.lock().await;
150 unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } 166 unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await }
151 } 167 }
152 168
169 /// Async erase.
153 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 170 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
154 let _guard = REGION_ACCESS.lock().await; 171 let _guard = REGION_ACCESS.lock().await;
155 unsafe { erase_sectored(self.0.base, from, to).await } 172 unsafe { erase_sectored(self.0.base, from, to).await }
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 8acad1c7c..f8561edb3 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -12,12 +12,14 @@ use super::{
12use crate::peripherals::FLASH; 12use crate::peripherals::FLASH;
13use crate::Peripheral; 13use crate::Peripheral;
14 14
15/// Internal flash memory driver.
15pub struct Flash<'d, MODE = Async> { 16pub struct Flash<'d, MODE = Async> {
16 pub(crate) inner: PeripheralRef<'d, FLASH>, 17 pub(crate) inner: PeripheralRef<'d, FLASH>,
17 pub(crate) _mode: PhantomData<MODE>, 18 pub(crate) _mode: PhantomData<MODE>,
18} 19}
19 20
20impl<'d> Flash<'d, Blocking> { 21impl<'d> Flash<'d, Blocking> {
22 /// Create a new flash driver, usable in blocking mode.
21 pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self { 23 pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self {
22 into_ref!(p); 24 into_ref!(p);
23 25
@@ -29,15 +31,26 @@ impl<'d> Flash<'d, Blocking> {
29} 31}
30 32
31impl<'d, MODE> Flash<'d, MODE> { 33impl<'d, MODE> Flash<'d, MODE> {
34 /// Split this flash driver into one instance per flash memory region.
35 ///
36 /// See module-level documentation for details on how memory regions work.
32 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { 37 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> {
33 assert!(family::is_default_layout()); 38 assert!(family::is_default_layout());
34 FlashLayout::new(self.inner) 39 FlashLayout::new(self.inner)
35 } 40 }
36 41
37 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 42 /// Blocking read.
43 ///
44 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
45 /// For example, to read address `0x0800_1234` you have to use offset `0x1234`.
46 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
38 blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) 47 blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
39 } 48 }
40 49
50 /// Blocking write.
51 ///
52 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
53 /// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
41 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 54 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
42 unsafe { 55 unsafe {
43 blocking_write( 56 blocking_write(
@@ -50,6 +63,10 @@ impl<'d, MODE> Flash<'d, MODE> {
50 } 63 }
51 } 64 }
52 65
66 /// Blocking erase.
67 ///
68 /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
69 /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
53 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 70 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
54 unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) } 71 unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) }
55 } 72 }
@@ -206,7 +223,7 @@ impl<MODE> embedded_storage::nor_flash::ReadNorFlash for Flash<'_, MODE> {
206 const READ_SIZE: usize = READ_SIZE; 223 const READ_SIZE: usize = READ_SIZE;
207 224
208 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 225 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
209 self.read(offset, bytes) 226 self.blocking_read(offset, bytes)
210 } 227 }
211 228
212 fn capacity(&self) -> usize { 229 fn capacity(&self) -> usize {
@@ -230,16 +247,28 @@ impl<MODE> embedded_storage::nor_flash::NorFlash for Flash<'_, MODE> {
230foreach_flash_region! { 247foreach_flash_region! {
231 ($type_name:ident, $write_size:literal, $erase_size:literal) => { 248 ($type_name:ident, $write_size:literal, $erase_size:literal) => {
232 impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> { 249 impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> {
250 /// Blocking read.
251 ///
252 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
253 /// For example, to read address `0x0800_1234` you have to use offset `0x1234`.
233 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 254 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
234 blocking_read(self.0.base, self.0.size, offset, bytes) 255 blocking_read(self.0.base, self.0.size, offset, bytes)
235 } 256 }
236 } 257 }
237 258
238 impl crate::_generated::flash_regions::$type_name<'_, Blocking> { 259 impl crate::_generated::flash_regions::$type_name<'_, Blocking> {
260 /// Blocking write.
261 ///
262 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
263 /// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
239 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 264 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
240 unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } 265 unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) }
241 } 266 }
242 267
268 /// Blocking erase.
269 ///
270 /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
271 /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
243 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 272 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
244 unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } 273 unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) }
245 } 274 }
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 1ab8435a0..c0a8d7022 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
13pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 13pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14 &FLASH_REGIONS 14 &FLASH_REGIONS
15} 15}
16 16
@@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
79 79
80pub(crate) unsafe fn clear_all_err() { 80pub(crate) unsafe fn clear_all_err() {
81 // read and write back the same value. 81 // read and write back the same value.
82 // This clears all "write 0 to clear" bits. 82 // This clears all "write 1 to clear" bits.
83 pac::FLASH.sr().modify(|_| {}); 83 pac::FLASH.sr().modify(|_| {});
84} 84}
85 85
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index 7e6d7ca26..817ccef4d 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
13pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 13pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14 &FLASH_REGIONS 14 &FLASH_REGIONS
15} 15}
16 16
@@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
79 79
80pub(crate) unsafe fn clear_all_err() { 80pub(crate) unsafe fn clear_all_err() {
81 // read and write back the same value. 81 // read and write back the same value.
82 // This clears all "write 0 to clear" bits. 82 // This clears all "write 1 to clear" bits.
83 pac::FLASH.sr().modify(|_| {}); 83 pac::FLASH.sr().modify(|_| {});
84} 84}
85 85
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 5d07020ce..2671dfb04 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -9,7 +9,7 @@ use pac::FLASH_SIZE;
9use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 9use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
10use crate::flash::Error; 10use crate::flash::Error;
11use crate::pac; 11use crate::pac;
12 12#[allow(missing_docs)] // TODO
13#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] 13#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
14mod alt_regions { 14mod alt_regions {
15 use core::marker::PhantomData; 15 use core::marker::PhantomData;
@@ -337,7 +337,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
337 337
338pub(crate) fn clear_all_err() { 338pub(crate) fn clear_all_err() {
339 // read and write back the same value. 339 // read and write back the same value.
340 // This clears all "write 0 to clear" bits. 340 // This clears all "write 1 to clear" bits.
341 pac::FLASH.sr().modify(|_| {}); 341 pac::FLASH.sr().modify(|_| {});
342} 342}
343 343
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index b52231ca8..6b3e66ac6 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
13pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 13pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14 &FLASH_REGIONS 14 &FLASH_REGIONS
15} 15}
16 16
@@ -69,7 +69,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
69 69
70pub(crate) unsafe fn clear_all_err() { 70pub(crate) unsafe fn clear_all_err() {
71 // read and write back the same value. 71 // read and write back the same value.
72 // This clears all "write 0 to clear" bits. 72 // This clears all "write 1 to clear" bits.
73 pac::FLASH.sr().modify(|_| {}); 73 pac::FLASH.sr().modify(|_| {});
74} 74}
75 75
diff --git a/embassy-stm32/src/flash/g0.rs b/embassy-stm32/src/flash/g.rs
index 19a388970..d97b4a932 100644
--- a/embassy-stm32/src/flash/g0.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -8,11 +8,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
8use crate::flash::Error; 8use crate::flash::Error;
9use crate::pac; 9use crate::pac;
10 10
11pub const fn is_default_layout() -> bool { 11pub(crate) const fn is_default_layout() -> bool {
12 true 12 true
13} 13}
14 14
15pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 15pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
16 &FLASH_REGIONS 16 &FLASH_REGIONS
17} 17}
18 18
@@ -92,6 +92,6 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
92 92
93pub(crate) unsafe fn clear_all_err() { 93pub(crate) unsafe fn clear_all_err() {
94 // read and write back the same value. 94 // read and write back the same value.
95 // This clears all "write 0 to clear" bits. 95 // This clears all "write 1 to clear" bits.
96 pac::FLASH.sr().modify(|_| {}); 96 pac::FLASH.sr().modify(|_| {});
97} 97}
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index b064fd6ea..65d163d29 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
@@ -14,7 +14,7 @@ const fn is_dual_bank() -> bool {
14 FLASH_REGIONS.len() >= 2 14 FLASH_REGIONS.len() >= 2
15} 15}
16 16
17pub fn get_flash_regions() -> &'static [&'static FlashRegion] { 17pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] {
18 &FLASH_REGIONS 18 &FLASH_REGIONS
19} 19}
20 20
@@ -113,7 +113,7 @@ pub(crate) unsafe fn clear_all_err() {
113 113
114unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { 114unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
115 // read and write back the same value. 115 // read and write back the same value.
116 // This clears all "write 0 to clear" bits. 116 // This clears all "write 1 to clear" bits.
117 bank.sr().modify(|_| {}); 117 bank.sr().modify(|_| {});
118} 118}
119 119
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 1db0da923..0b332dc61 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -5,11 +5,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub const fn is_default_layout() -> bool { 8pub(crate) const fn is_default_layout() -> bool {
9 true 9 true
10} 10}
11 11
12pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS 13 &FLASH_REGIONS
14} 14}
15 15
@@ -120,7 +120,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
120 120
121pub(crate) unsafe fn clear_all_err() { 121pub(crate) unsafe fn clear_all_err() {
122 // read and write back the same value. 122 // read and write back the same value.
123 // This clears all "write 0 to clear" bits. 123 // This clears all "write 1 to clear" bits.
124 pac::FLASH.sr().modify(|_| {}); 124 pac::FLASH.sr().modify(|_| {});
125} 125}
126 126
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index fb20dcd38..cbf5c25b2 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,3 +1,4 @@
1//! Flash memory (FLASH)
1use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; 2use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
2 3
3#[cfg(flash_f4)] 4#[cfg(flash_f4)]
@@ -14,62 +15,96 @@ pub use crate::_generated::flash_regions::*;
14pub use crate::_generated::MAX_ERASE_SIZE; 15pub use crate::_generated::MAX_ERASE_SIZE;
15pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; 16pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
16 17
18/// Get whether the default flash layout is being used.
19///
20/// In some chips, dual-bank is not default. This will then return `false`
21/// when dual-bank is enabled.
22pub fn is_default_layout() -> bool {
23 family::is_default_layout()
24}
25
26/// Get all flash regions.
27pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
28 family::get_flash_regions()
29}
30
31/// Read size (always 1)
17pub const READ_SIZE: usize = 1; 32pub const READ_SIZE: usize = 1;
18 33
19pub struct Blocking; 34/// Blocking flash mode typestate.
20pub struct Async; 35pub enum Blocking {}
36/// Async flash mode typestate.
37pub enum Async {}
21 38
39/// Flash memory region
22#[derive(Debug)] 40#[derive(Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))] 41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct FlashRegion { 42pub struct FlashRegion {
43 /// Bank number.
25 pub bank: FlashBank, 44 pub bank: FlashBank,
45 /// Absolute base address.
26 pub base: u32, 46 pub base: u32,
47 /// Size in bytes.
27 pub size: u32, 48 pub size: u32,
49 /// Erase size (sector size).
28 pub erase_size: u32, 50 pub erase_size: u32,
51 /// Minimum write size.
29 pub write_size: u32, 52 pub write_size: u32,
53 /// Erase value (usually `0xFF`, but is `0x00` in some chips)
30 pub erase_value: u8, 54 pub erase_value: u8,
31 pub(crate) _ensure_internal: (), 55 pub(crate) _ensure_internal: (),
32} 56}
33 57
58impl FlashRegion {
59 /// Absolute end address.
60 pub const fn end(&self) -> u32 {
61 self.base + self.size
62 }
63
64 /// Number of sectors in the region.
65 pub const fn sectors(&self) -> u8 {
66 (self.size / self.erase_size) as u8
67 }
68}
69
70/// Flash sector.
34#[derive(Debug, PartialEq)] 71#[derive(Debug, PartialEq)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))] 72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36pub struct FlashSector { 73pub struct FlashSector {
74 /// Bank number.
37 pub bank: FlashBank, 75 pub bank: FlashBank,
76 /// Sector number within the bank.
38 pub index_in_bank: u8, 77 pub index_in_bank: u8,
78 /// Absolute start address.
39 pub start: u32, 79 pub start: u32,
80 /// Size in bytes.
40 pub size: u32, 81 pub size: u32,
41} 82}
42 83
84/// Flash bank.
43#[derive(Clone, Copy, Debug, PartialEq)] 85#[derive(Clone, Copy, Debug, PartialEq)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))] 86#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub enum FlashBank { 87pub enum FlashBank {
88 /// Bank 1
46 Bank1 = 0, 89 Bank1 = 0,
90 /// Bank 2
47 Bank2 = 1, 91 Bank2 = 1,
92 /// OTP region
48 Otp, 93 Otp,
49} 94}
50 95
51impl FlashRegion {
52 pub const fn end(&self) -> u32 {
53 self.base + self.size
54 }
55
56 pub const fn sectors(&self) -> u8 {
57 (self.size / self.erase_size) as u8
58 }
59}
60
61#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] 96#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
62#[cfg_attr(flash_f0, path = "f0.rs")] 97#[cfg_attr(flash_f0, path = "f0.rs")]
63#[cfg_attr(flash_f3, path = "f3.rs")] 98#[cfg_attr(flash_f3, path = "f3.rs")]
64#[cfg_attr(flash_f4, path = "f4.rs")] 99#[cfg_attr(flash_f4, path = "f4.rs")]
65#[cfg_attr(flash_f7, path = "f7.rs")] 100#[cfg_attr(flash_f7, path = "f7.rs")]
66#[cfg_attr(flash_g0, path = "g0.rs")] 101#[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")]
67#[cfg_attr(flash_h7, path = "h7.rs")] 102#[cfg_attr(flash_h7, path = "h7.rs")]
68#[cfg_attr(flash_h7ab, path = "h7.rs")] 103#[cfg_attr(flash_h7ab, path = "h7.rs")]
69#[cfg_attr( 104#[cfg_attr(
70 not(any( 105 not(any(
71 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7, 106 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_g4,
72 flash_h7ab 107 flash_h7, flash_h7ab
73 )), 108 )),
74 path = "other.rs" 109 path = "other.rs"
75)] 110)]
@@ -78,6 +113,10 @@ mod family;
78#[allow(unused_imports)] 113#[allow(unused_imports)]
79pub use family::*; 114pub use family::*;
80 115
116/// Flash error
117///
118/// See STM32 Reference Manual for your chip for details.
119#[allow(missing_docs)]
81#[derive(Debug, Copy, Clone, PartialEq, Eq)] 120#[derive(Debug, Copy, Clone, PartialEq, Eq)]
82#[cfg_attr(feature = "defmt", derive(defmt::Format))] 121#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub enum Error { 122pub enum Error {
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
index a7e8d1d57..20f84a72f 100644
--- a/embassy-stm32/src/flash/other.rs
+++ b/embassy-stm32/src/flash/other.rs
@@ -2,11 +2,11 @@
2 2
3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4 4
5pub const fn is_default_layout() -> bool { 5pub(crate) const fn is_default_layout() -> bool {
6 true 6 true
7} 7}
8 8
9pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 9pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS 10 &FLASH_REGIONS
11} 11}
12 12
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index dd0d27217..873c8a70c 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -1,3 +1,4 @@
1//! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC)
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2 3
3use embassy_hal_internal::into_ref; 4use embassy_hal_internal::into_ref;
@@ -6,6 +7,7 @@ use crate::gpio::sealed::AFType;
6use crate::gpio::{Pull, Speed}; 7use crate::gpio::{Pull, Speed};
7use crate::Peripheral; 8use crate::Peripheral;
8 9
10/// FMC driver
9pub struct Fmc<'d, T: Instance> { 11pub struct Fmc<'d, T: Instance> {
10 peri: PhantomData<&'d mut T>, 12 peri: PhantomData<&'d mut T>,
11} 13}
@@ -38,6 +40,7 @@ where
38 T::REGS.bcr1().modify(|r| r.set_fmcen(true)); 40 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
39 } 41 }
40 42
43 /// Get the kernel clock currently in use for this FMC instance.
41 pub fn source_clock_hz(&self) -> u32 { 44 pub fn source_clock_hz(&self) -> u32 {
42 <T as crate::rcc::sealed::RccPeripheral>::frequency().0 45 <T as crate::rcc::sealed::RccPeripheral>::frequency().0
43 } 46 }
@@ -85,6 +88,7 @@ macro_rules! fmc_sdram_constructor {
85 nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*], 88 nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*],
86 ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*] 89 ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*]
87 )) => { 90 )) => {
91 /// Create a new FMC instance.
88 pub fn $name<CHIP: stm32_fmc::SdramChip>( 92 pub fn $name<CHIP: stm32_fmc::SdramChip>(
89 _instance: impl Peripheral<P = T> + 'd, 93 _instance: impl Peripheral<P = T> + 'd,
90 $($addr_pin_name: impl Peripheral<P = impl $addr_signal<T>> + 'd),*, 94 $($addr_pin_name: impl Peripheral<P = impl $addr_signal<T>> + 'd),*,
@@ -199,6 +203,7 @@ pub(crate) mod sealed {
199 } 203 }
200} 204}
201 205
206/// FMC instance trait.
202pub trait Instance: sealed::Instance + 'static {} 207pub trait Instance: sealed::Instance + 'static {}
203 208
204foreach_peripheral!( 209foreach_peripheral!(
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index b863c4ffe..c300a079e 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -1,3 +1,5 @@
1//! General-purpose Input/Output (GPIO)
2
1#![macro_use] 3#![macro_use]
2use core::convert::Infallible; 4use core::convert::Infallible;
3 5
@@ -29,6 +31,11 @@ impl<'d, T: Pin> Flex<'d, T> {
29 Self { pin } 31 Self { pin }
30 } 32 }
31 33
34 /// Type-erase (degrade) this pin into an `AnyPin`.
35 ///
36 /// This converts pin singletons (`PA5`, `PB6`, ...), which
37 /// are all different types, into the same type. It is useful for
38 /// creating arrays of pins, or avoiding generics.
32 #[inline] 39 #[inline]
33 pub fn degrade(self) -> Flex<'d, AnyPin> { 40 pub fn degrade(self) -> Flex<'d, AnyPin> {
34 // Safety: We are about to drop the other copy of this pin, so 41 // Safety: We are about to drop the other copy of this pin, so
@@ -141,40 +148,55 @@ impl<'d, T: Pin> Flex<'d, T> {
141 }); 148 });
142 } 149 }
143 150
151 /// Get whether the pin input level is high.
152 #[inline]
153 pub fn is_high(&mut self) -> bool {
154 !self.ref_is_low()
155 }
156
157 /// Get whether the pin input level is low.
144 #[inline] 158 #[inline]
145 pub fn is_high(&self) -> bool { 159 pub fn is_low(&mut self) -> bool {
146 !self.is_low() 160 self.ref_is_low()
147 } 161 }
148 162
149 #[inline] 163 #[inline]
150 pub fn is_low(&self) -> bool { 164 pub(crate) fn ref_is_low(&self) -> bool {
151 let state = self.pin.block().idr().read().idr(self.pin.pin() as _); 165 let state = self.pin.block().idr().read().idr(self.pin.pin() as _);
152 state == vals::Idr::LOW 166 state == vals::Idr::LOW
153 } 167 }
154 168
169 /// Get the current pin input level.
155 #[inline] 170 #[inline]
156 pub fn get_level(&self) -> Level { 171 pub fn get_level(&mut self) -> Level {
157 self.is_high().into() 172 self.is_high().into()
158 } 173 }
159 174
175 /// Get whether the output level is set to high.
160 #[inline] 176 #[inline]
161 pub fn is_set_high(&self) -> bool { 177 pub fn is_set_high(&mut self) -> bool {
162 !self.is_set_low() 178 !self.ref_is_set_low()
163 } 179 }
164 180
165 /// Is the output pin set as low? 181 /// Get whether the output level is set to low.
166 #[inline] 182 #[inline]
167 pub fn is_set_low(&self) -> bool { 183 pub fn is_set_low(&mut self) -> bool {
184 self.ref_is_set_low()
185 }
186
187 #[inline]
188 pub(crate) fn ref_is_set_low(&self) -> bool {
168 let state = self.pin.block().odr().read().odr(self.pin.pin() as _); 189 let state = self.pin.block().odr().read().odr(self.pin.pin() as _);
169 state == vals::Odr::LOW 190 state == vals::Odr::LOW
170 } 191 }
171 192
172 /// What level output is set to 193 /// Get the current output level.
173 #[inline] 194 #[inline]
174 pub fn get_output_level(&self) -> Level { 195 pub fn get_output_level(&mut self) -> Level {
175 self.is_set_high().into() 196 self.is_set_high().into()
176 } 197 }
177 198
199 /// Set the output as high.
178 #[inline] 200 #[inline]
179 pub fn set_high(&mut self) { 201 pub fn set_high(&mut self) {
180 self.pin.set_high(); 202 self.pin.set_high();
@@ -186,6 +208,7 @@ impl<'d, T: Pin> Flex<'d, T> {
186 self.pin.set_low(); 208 self.pin.set_low();
187 } 209 }
188 210
211 /// Set the output level.
189 #[inline] 212 #[inline]
190 pub fn set_level(&mut self, level: Level) { 213 pub fn set_level(&mut self, level: Level) {
191 match level { 214 match level {
@@ -194,7 +217,7 @@ impl<'d, T: Pin> Flex<'d, T> {
194 } 217 }
195 } 218 }
196 219
197 /// Toggle pin output 220 /// Toggle the output level.
198 #[inline] 221 #[inline]
199 pub fn toggle(&mut self) { 222 pub fn toggle(&mut self) {
200 if self.is_set_low() { 223 if self.is_set_low() {
@@ -232,8 +255,11 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
232#[derive(Debug, Eq, PartialEq, Copy, Clone)] 255#[derive(Debug, Eq, PartialEq, Copy, Clone)]
233#[cfg_attr(feature = "defmt", derive(defmt::Format))] 256#[cfg_attr(feature = "defmt", derive(defmt::Format))]
234pub enum Pull { 257pub enum Pull {
258 /// No pull
235 None, 259 None,
260 /// Pull up
236 Up, 261 Up,
262 /// Pull down
237 Down, 263 Down,
238} 264}
239 265
@@ -251,6 +277,9 @@ impl From<Pull> for vals::Pupdr {
251} 277}
252 278
253/// Speed settings 279/// Speed settings
280///
281/// These vary dpeending on the chip, ceck the reference manual or datasheet for details.
282#[allow(missing_docs)]
254#[derive(Debug, Copy, Clone)] 283#[derive(Debug, Copy, Clone)]
255#[cfg_attr(feature = "defmt", derive(defmt::Format))] 284#[cfg_attr(feature = "defmt", derive(defmt::Format))]
256pub enum Speed { 285pub enum Speed {
@@ -295,6 +324,7 @@ pub struct Input<'d, T: Pin> {
295} 324}
296 325
297impl<'d, T: Pin> Input<'d, T> { 326impl<'d, T: Pin> Input<'d, T> {
327 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
298 #[inline] 328 #[inline]
299 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { 329 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self {
300 let mut pin = Flex::new(pin); 330 let mut pin = Flex::new(pin);
@@ -302,6 +332,11 @@ impl<'d, T: Pin> Input<'d, T> {
302 Self { pin } 332 Self { pin }
303 } 333 }
304 334
335 /// Type-erase (degrade) this pin into an `AnyPin`.
336 ///
337 /// This converts pin singletons (`PA5`, `PB6`, ...), which
338 /// are all different types, into the same type. It is useful for
339 /// creating arrays of pins, or avoiding generics.
305 #[inline] 340 #[inline]
306 pub fn degrade(self) -> Input<'d, AnyPin> { 341 pub fn degrade(self) -> Input<'d, AnyPin> {
307 Input { 342 Input {
@@ -309,18 +344,21 @@ impl<'d, T: Pin> Input<'d, T> {
309 } 344 }
310 } 345 }
311 346
347 /// Get whether the pin input level is high.
312 #[inline] 348 #[inline]
313 pub fn is_high(&self) -> bool { 349 pub fn is_high(&mut self) -> bool {
314 self.pin.is_high() 350 self.pin.is_high()
315 } 351 }
316 352
353 /// Get whether the pin input level is low.
317 #[inline] 354 #[inline]
318 pub fn is_low(&self) -> bool { 355 pub fn is_low(&mut self) -> bool {
319 self.pin.is_low() 356 self.pin.is_low()
320 } 357 }
321 358
359 /// Get the current pin input level.
322 #[inline] 360 #[inline]
323 pub fn get_level(&self) -> Level { 361 pub fn get_level(&mut self) -> Level {
324 self.pin.get_level() 362 self.pin.get_level()
325 } 363 }
326} 364}
@@ -329,7 +367,9 @@ impl<'d, T: Pin> Input<'d, T> {
329#[derive(Debug, Eq, PartialEq, Copy, Clone)] 367#[derive(Debug, Eq, PartialEq, Copy, Clone)]
330#[cfg_attr(feature = "defmt", derive(defmt::Format))] 368#[cfg_attr(feature = "defmt", derive(defmt::Format))]
331pub enum Level { 369pub enum Level {
370 /// Low
332 Low, 371 Low,
372 /// High
333 High, 373 High,
334} 374}
335 375
@@ -361,6 +401,7 @@ pub struct Output<'d, T: Pin> {
361} 401}
362 402
363impl<'d, T: Pin> Output<'d, T> { 403impl<'d, T: Pin> Output<'d, T> {
404 /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration.
364 #[inline] 405 #[inline]
365 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self { 406 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self {
366 let mut pin = Flex::new(pin); 407 let mut pin = Flex::new(pin);
@@ -372,6 +413,11 @@ impl<'d, T: Pin> Output<'d, T> {
372 Self { pin } 413 Self { pin }
373 } 414 }
374 415
416 /// Type-erase (degrade) this pin into an `AnyPin`.
417 ///
418 /// This converts pin singletons (`PA5`, `PB6`, ...), which
419 /// are all different types, into the same type. It is useful for
420 /// creating arrays of pins, or avoiding generics.
375 #[inline] 421 #[inline]
376 pub fn degrade(self) -> Output<'d, AnyPin> { 422 pub fn degrade(self) -> Output<'d, AnyPin> {
377 Output { 423 Output {
@@ -399,19 +445,19 @@ impl<'d, T: Pin> Output<'d, T> {
399 445
400 /// Is the output pin set as high? 446 /// Is the output pin set as high?
401 #[inline] 447 #[inline]
402 pub fn is_set_high(&self) -> bool { 448 pub fn is_set_high(&mut self) -> bool {
403 self.pin.is_set_high() 449 self.pin.is_set_high()
404 } 450 }
405 451
406 /// Is the output pin set as low? 452 /// Is the output pin set as low?
407 #[inline] 453 #[inline]
408 pub fn is_set_low(&self) -> bool { 454 pub fn is_set_low(&mut self) -> bool {
409 self.pin.is_set_low() 455 self.pin.is_set_low()
410 } 456 }
411 457
412 /// What level output is set to 458 /// What level output is set to
413 #[inline] 459 #[inline]
414 pub fn get_output_level(&self) -> Level { 460 pub fn get_output_level(&mut self) -> Level {
415 self.pin.get_output_level() 461 self.pin.get_output_level()
416 } 462 }
417 463
@@ -432,6 +478,7 @@ pub struct OutputOpenDrain<'d, T: Pin> {
432} 478}
433 479
434impl<'d, T: Pin> OutputOpenDrain<'d, T> { 480impl<'d, T: Pin> OutputOpenDrain<'d, T> {
481 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration.
435 #[inline] 482 #[inline]
436 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { 483 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self {
437 let mut pin = Flex::new(pin); 484 let mut pin = Flex::new(pin);
@@ -445,6 +492,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
445 Self { pin } 492 Self { pin }
446 } 493 }
447 494
495 /// Type-erase (degrade) this pin into an `AnyPin`.
496 ///
497 /// This converts pin singletons (`PA5`, `PB6`, ...), which
498 /// are all different types, into the same type. It is useful for
499 /// creating arrays of pins, or avoiding generics.
448 #[inline] 500 #[inline]
449 pub fn degrade(self) -> Output<'d, AnyPin> { 501 pub fn degrade(self) -> Output<'d, AnyPin> {
450 Output { 502 Output {
@@ -452,19 +504,21 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
452 } 504 }
453 } 505 }
454 506
507 /// Get whether the pin input level is high.
455 #[inline] 508 #[inline]
456 pub fn is_high(&self) -> bool { 509 pub fn is_high(&mut self) -> bool {
457 !self.pin.is_low() 510 !self.pin.is_low()
458 } 511 }
459 512
513 /// Get whether the pin input level is low.
460 #[inline] 514 #[inline]
461 pub fn is_low(&self) -> bool { 515 pub fn is_low(&mut self) -> bool {
462 self.pin.is_low() 516 self.pin.is_low()
463 } 517 }
464 518
465 /// Returns current pin level 519 /// Get the current pin input level.
466 #[inline] 520 #[inline]
467 pub fn get_level(&self) -> Level { 521 pub fn get_level(&mut self) -> Level {
468 self.pin.get_level() 522 self.pin.get_level()
469 } 523 }
470 524
@@ -486,21 +540,21 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
486 self.pin.set_level(level); 540 self.pin.set_level(level);
487 } 541 }
488 542
489 /// Is the output pin set as high? 543 /// Get whether the output level is set to high.
490 #[inline] 544 #[inline]
491 pub fn is_set_high(&self) -> bool { 545 pub fn is_set_high(&mut self) -> bool {
492 self.pin.is_set_high() 546 self.pin.is_set_high()
493 } 547 }
494 548
495 /// Is the output pin set as low? 549 /// Get whether the output level is set to low.
496 #[inline] 550 #[inline]
497 pub fn is_set_low(&self) -> bool { 551 pub fn is_set_low(&mut self) -> bool {
498 self.pin.is_set_low() 552 self.pin.is_set_low()
499 } 553 }
500 554
501 /// What level output is set to 555 /// Get the current output level.
502 #[inline] 556 #[inline]
503 pub fn get_output_level(&self) -> Level { 557 pub fn get_output_level(&mut self) -> Level {
504 self.pin.get_output_level() 558 self.pin.get_output_level()
505 } 559 }
506 560
@@ -511,8 +565,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
511 } 565 }
512} 566}
513 567
568/// GPIO output type
514pub enum OutputType { 569pub enum OutputType {
570 /// Drive the pin both high or low.
515 PushPull, 571 PushPull,
572 /// Drive the pin low, or don't drive it at all if the output level is high.
516 OpenDrain, 573 OpenDrain,
517} 574}
518 575
@@ -525,6 +582,7 @@ impl From<OutputType> for sealed::AFType {
525 } 582 }
526} 583}
527 584
585#[allow(missing_docs)]
528pub(crate) mod sealed { 586pub(crate) mod sealed {
529 use super::*; 587 use super::*;
530 588
@@ -532,8 +590,11 @@ pub(crate) mod sealed {
532 #[derive(Debug, Copy, Clone)] 590 #[derive(Debug, Copy, Clone)]
533 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 591 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
534 pub enum AFType { 592 pub enum AFType {
593 /// Input
535 Input, 594 Input,
595 /// Output, drive the pin both high or low.
536 OutputPushPull, 596 OutputPushPull,
597 /// Output, drive the pin low, or don't drive it at all if the output level is high.
537 OutputOpenDrain, 598 OutputOpenDrain,
538 } 599 }
539 600
@@ -676,7 +737,11 @@ pub(crate) mod sealed {
676 } 737 }
677} 738}
678 739
740/// GPIO pin trait.
679pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { 741pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static {
742 /// EXTI channel assigned to this pin.
743 ///
744 /// For example, PC4 uses EXTI4.
680 #[cfg(feature = "exti")] 745 #[cfg(feature = "exti")]
681 type ExtiChannel: crate::exti::Channel; 746 type ExtiChannel: crate::exti::Channel;
682 747
@@ -692,7 +757,11 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
692 self._port() 757 self._port()
693 } 758 }
694 759
695 /// Convert from concrete pin type PX_XX to type erased `AnyPin`. 760 /// Type-erase (degrade) this pin into an `AnyPin`.
761 ///
762 /// This converts pin singletons (`PA5`, `PB6`, ...), which
763 /// are all different types, into the same type. It is useful for
764 /// creating arrays of pins, or avoiding generics.
696 #[inline] 765 #[inline]
697 fn degrade(self) -> AnyPin { 766 fn degrade(self) -> AnyPin {
698 AnyPin { 767 AnyPin {
@@ -701,12 +770,15 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
701 } 770 }
702} 771}
703 772
704// Type-erased GPIO pin 773/// Type-erased GPIO pin
705pub struct AnyPin { 774pub struct AnyPin {
706 pin_port: u8, 775 pin_port: u8,
707} 776}
708 777
709impl AnyPin { 778impl AnyPin {
779 /// Unsafely create an `AnyPin` from a pin+port number.
780 ///
781 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
710 #[inline] 782 #[inline]
711 pub unsafe fn steal(pin_port: u8) -> Self { 783 pub unsafe fn steal(pin_port: u8) -> Self {
712 Self { pin_port } 784 Self { pin_port }
@@ -717,6 +789,8 @@ impl AnyPin {
717 self.pin_port / 16 789 self.pin_port / 16
718 } 790 }
719 791
792 /// Get the GPIO register block for this pin.
793 #[cfg(feature = "unstable-pac")]
720 #[inline] 794 #[inline]
721 pub fn block(&self) -> gpio::Gpio { 795 pub fn block(&self) -> gpio::Gpio {
722 pac::GPIO(self._port() as _) 796 pac::GPIO(self._port() as _)
@@ -777,12 +851,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> {
777 851
778 #[inline] 852 #[inline]
779 fn is_high(&self) -> Result<bool, Self::Error> { 853 fn is_high(&self) -> Result<bool, Self::Error> {
780 Ok(self.is_high()) 854 Ok(!self.pin.ref_is_low())
781 } 855 }
782 856
783 #[inline] 857 #[inline]
784 fn is_low(&self) -> Result<bool, Self::Error> { 858 fn is_low(&self) -> Result<bool, Self::Error> {
785 Ok(self.is_low()) 859 Ok(self.pin.ref_is_low())
786 } 860 }
787} 861}
788 862
@@ -805,13 +879,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> {
805impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { 879impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> {
806 #[inline] 880 #[inline]
807 fn is_set_high(&self) -> Result<bool, Self::Error> { 881 fn is_set_high(&self) -> Result<bool, Self::Error> {
808 Ok(self.is_set_high()) 882 Ok(!self.pin.ref_is_set_low())
809 } 883 }
810 884
811 /// Is the output pin set as low? 885 /// Is the output pin set as low?
812 #[inline] 886 #[inline]
813 fn is_set_low(&self) -> Result<bool, Self::Error> { 887 fn is_set_low(&self) -> Result<bool, Self::Error> {
814 Ok(self.is_set_low()) 888 Ok(self.pin.ref_is_set_low())
815 } 889 }
816} 890}
817 891
@@ -843,13 +917,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d,
843impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { 917impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> {
844 #[inline] 918 #[inline]
845 fn is_set_high(&self) -> Result<bool, Self::Error> { 919 fn is_set_high(&self) -> Result<bool, Self::Error> {
846 Ok(self.is_set_high()) 920 Ok(!self.pin.ref_is_set_low())
847 } 921 }
848 922
849 /// Is the output pin set as low? 923 /// Is the output pin set as low?
850 #[inline] 924 #[inline]
851 fn is_set_low(&self) -> Result<bool, Self::Error> { 925 fn is_set_low(&self) -> Result<bool, Self::Error> {
852 Ok(self.is_set_low()) 926 Ok(self.pin.ref_is_set_low())
853 } 927 }
854} 928}
855 929
@@ -867,12 +941,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> {
867 941
868 #[inline] 942 #[inline]
869 fn is_high(&self) -> Result<bool, Self::Error> { 943 fn is_high(&self) -> Result<bool, Self::Error> {
870 Ok(self.is_high()) 944 Ok(!self.ref_is_low())
871 } 945 }
872 946
873 #[inline] 947 #[inline]
874 fn is_low(&self) -> Result<bool, Self::Error> { 948 fn is_low(&self) -> Result<bool, Self::Error> {
875 Ok(self.is_low()) 949 Ok(self.ref_is_low())
876 } 950 }
877} 951}
878 952
@@ -895,13 +969,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> {
895impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { 969impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> {
896 #[inline] 970 #[inline]
897 fn is_set_high(&self) -> Result<bool, Self::Error> { 971 fn is_set_high(&self) -> Result<bool, Self::Error> {
898 Ok(self.is_set_high()) 972 Ok(!self.ref_is_set_low())
899 } 973 }
900 974
901 /// Is the output pin set as low? 975 /// Is the output pin set as low?
902 #[inline] 976 #[inline]
903 fn is_set_low(&self) -> Result<bool, Self::Error> { 977 fn is_set_low(&self) -> Result<bool, Self::Error> {
904 Ok(self.is_set_low()) 978 Ok(self.ref_is_set_low())
905 } 979 }
906} 980}
907 981
@@ -920,12 +994,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
920 994
921impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { 995impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
922 #[inline] 996 #[inline]
923 fn is_high(&self) -> Result<bool, Self::Error> { 997 fn is_high(&mut self) -> Result<bool, Self::Error> {
924 Ok(self.is_high()) 998 Ok(self.is_high())
925 } 999 }
926 1000
927 #[inline] 1001 #[inline]
928 fn is_low(&self) -> Result<bool, Self::Error> { 1002 fn is_low(&mut self) -> Result<bool, Self::Error> {
929 Ok(self.is_low()) 1003 Ok(self.is_low())
930 } 1004 }
931} 1005}
@@ -948,13 +1022,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
948 1022
949impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { 1023impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
950 #[inline] 1024 #[inline]
951 fn is_set_high(&self) -> Result<bool, Self::Error> { 1025 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
952 Ok(self.is_set_high()) 1026 Ok(self.is_set_high())
953 } 1027 }
954 1028
955 /// Is the output pin set as low? 1029 /// Is the output pin set as low?
956 #[inline] 1030 #[inline]
957 fn is_set_low(&self) -> Result<bool, Self::Error> { 1031 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
958 Ok(self.is_set_low()) 1032 Ok(self.is_set_low())
959 } 1033 }
960} 1034}
@@ -972,12 +1046,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> {
972 1046
973impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { 1047impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> {
974 #[inline] 1048 #[inline]
975 fn is_high(&self) -> Result<bool, Self::Error> { 1049 fn is_high(&mut self) -> Result<bool, Self::Error> {
976 Ok(self.is_high()) 1050 Ok(self.is_high())
977 } 1051 }
978 1052
979 #[inline] 1053 #[inline]
980 fn is_low(&self) -> Result<bool, Self::Error> { 1054 fn is_low(&mut self) -> Result<bool, Self::Error> {
981 Ok(self.is_low()) 1055 Ok(self.is_low())
982 } 1056 }
983} 1057}
@@ -996,13 +1070,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> {
996 1070
997impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { 1071impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> {
998 #[inline] 1072 #[inline]
999 fn is_set_high(&self) -> Result<bool, Self::Error> { 1073 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1000 Ok(self.is_set_high()) 1074 Ok(self.is_set_high())
1001 } 1075 }
1002 1076
1003 /// Is the output pin set as low? 1077 /// Is the output pin set as low?
1004 #[inline] 1078 #[inline]
1005 fn is_set_low(&self) -> Result<bool, Self::Error> { 1079 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1006 Ok(self.is_set_low()) 1080 Ok(self.is_set_low())
1007 } 1081 }
1008} 1082}
@@ -1016,12 +1090,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrai
1016 1090
1017impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { 1091impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
1018 #[inline] 1092 #[inline]
1019 fn is_high(&self) -> Result<bool, Self::Error> { 1093 fn is_high(&mut self) -> Result<bool, Self::Error> {
1020 Ok(self.is_high()) 1094 Ok(self.is_high())
1021 } 1095 }
1022 1096
1023 #[inline] 1097 #[inline]
1024 fn is_low(&self) -> Result<bool, Self::Error> { 1098 fn is_low(&mut self) -> Result<bool, Self::Error> {
1025 Ok(self.is_low()) 1099 Ok(self.is_low())
1026 } 1100 }
1027} 1101}
@@ -1051,17 +1125,18 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
1051 1125
1052impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { 1126impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
1053 #[inline] 1127 #[inline]
1054 fn is_set_high(&self) -> Result<bool, Self::Error> { 1128 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1055 Ok(self.is_set_high()) 1129 Ok(self.is_set_high())
1056 } 1130 }
1057 1131
1058 /// Is the output pin set as low? 1132 /// Is the output pin set as low?
1059 #[inline] 1133 #[inline]
1060 fn is_set_low(&self) -> Result<bool, Self::Error> { 1134 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1061 Ok(self.is_set_low()) 1135 Ok(self.is_set_low())
1062 } 1136 }
1063} 1137}
1064 1138
1139/// Low-level GPIO manipulation.
1065#[cfg(feature = "unstable-pac")] 1140#[cfg(feature = "unstable-pac")]
1066pub mod low_level { 1141pub mod low_level {
1067 pub use super::sealed::*; 1142 pub use super::sealed::*;
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 17096d48c..faefaabbc 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -1,3 +1,5 @@
1//! High Resolution Timer (HRTIM)
2
1mod traits; 3mod traits;
2 4
3use core::marker::PhantomData; 5use core::marker::PhantomData;
@@ -13,38 +15,42 @@ use crate::rcc::get_freqs;
13use crate::time::Hertz; 15use crate::time::Hertz;
14use crate::Peripheral; 16use crate::Peripheral;
15 17
16pub enum Source { 18/// HRTIM burst controller instance.
17 Master,
18 ChA,
19 ChB,
20 ChC,
21 ChD,
22 ChE,
23 #[cfg(hrtim_v2)]
24 ChF,
25}
26
27pub struct BurstController<T: Instance> { 19pub struct BurstController<T: Instance> {
28 phantom: PhantomData<T>, 20 phantom: PhantomData<T>,
29} 21}
22
23/// HRTIM master instance.
30pub struct Master<T: Instance> { 24pub struct Master<T: Instance> {
31 phantom: PhantomData<T>, 25 phantom: PhantomData<T>,
32} 26}
27
28/// HRTIM channel A instance.
33pub struct ChA<T: Instance> { 29pub struct ChA<T: Instance> {
34 phantom: PhantomData<T>, 30 phantom: PhantomData<T>,
35} 31}
32
33/// HRTIM channel B instance.
36pub struct ChB<T: Instance> { 34pub struct ChB<T: Instance> {
37 phantom: PhantomData<T>, 35 phantom: PhantomData<T>,
38} 36}
37
38/// HRTIM channel C instance.
39pub struct ChC<T: Instance> { 39pub struct ChC<T: Instance> {
40 phantom: PhantomData<T>, 40 phantom: PhantomData<T>,
41} 41}
42
43/// HRTIM channel D instance.
42pub struct ChD<T: Instance> { 44pub struct ChD<T: Instance> {
43 phantom: PhantomData<T>, 45 phantom: PhantomData<T>,
44} 46}
47
48/// HRTIM channel E instance.
45pub struct ChE<T: Instance> { 49pub struct ChE<T: Instance> {
46 phantom: PhantomData<T>, 50 phantom: PhantomData<T>,
47} 51}
52
53/// HRTIM channel F instance.
48#[cfg(hrtim_v2)] 54#[cfg(hrtim_v2)]
49pub struct ChF<T: Instance> { 55pub struct ChF<T: Instance> {
50 phantom: PhantomData<T>, 56 phantom: PhantomData<T>,
@@ -58,22 +64,26 @@ mod sealed {
58 } 64 }
59} 65}
60 66
67/// Advanced channel instance trait.
61pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} 68pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
62 69
63pub struct PwmPin<'d, Perip, Channel> { 70/// HRTIM PWM pin.
71pub struct PwmPin<'d, T, C> {
64 _pin: PeripheralRef<'d, AnyPin>, 72 _pin: PeripheralRef<'d, AnyPin>,
65 phantom: PhantomData<(Perip, Channel)>, 73 phantom: PhantomData<(T, C)>,
66} 74}
67 75
68pub struct ComplementaryPwmPin<'d, Perip, Channel> { 76/// HRTIM complementary PWM pin.
77pub struct ComplementaryPwmPin<'d, T, C> {
69 _pin: PeripheralRef<'d, AnyPin>, 78 _pin: PeripheralRef<'d, AnyPin>,
70 phantom: PhantomData<(Perip, Channel)>, 79 phantom: PhantomData<(T, C)>,
71} 80}
72 81
73macro_rules! advanced_channel_impl { 82macro_rules! advanced_channel_impl {
74 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 83 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
75 impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { 84 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
76 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 85 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
86 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
77 into_ref!(pin); 87 into_ref!(pin);
78 critical_section::with(|_| { 88 critical_section::with(|_| {
79 pin.set_low(); 89 pin.set_low();
@@ -88,8 +98,9 @@ macro_rules! advanced_channel_impl {
88 } 98 }
89 } 99 }
90 100
91 impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { 101 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
92 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { 102 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
103 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<T>> + 'd) -> Self {
93 into_ref!(pin); 104 into_ref!(pin);
94 critical_section::with(|_| { 105 critical_section::with(|_| {
95 pin.set_low(); 106 pin.set_low();
@@ -124,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin);
124/// Struct used to divide a high resolution timer into multiple channels 135/// Struct used to divide a high resolution timer into multiple channels
125pub struct AdvancedPwm<'d, T: Instance> { 136pub struct AdvancedPwm<'d, T: Instance> {
126 _inner: PeripheralRef<'d, T>, 137 _inner: PeripheralRef<'d, T>,
138 /// Master instance.
127 pub master: Master<T>, 139 pub master: Master<T>,
140 /// Burst controller.
128 pub burst_controller: BurstController<T>, 141 pub burst_controller: BurstController<T>,
142 /// Channel A.
129 pub ch_a: ChA<T>, 143 pub ch_a: ChA<T>,
144 /// Channel B.
130 pub ch_b: ChB<T>, 145 pub ch_b: ChB<T>,
146 /// Channel C.
131 pub ch_c: ChC<T>, 147 pub ch_c: ChC<T>,
148 /// Channel D.
132 pub ch_d: ChD<T>, 149 pub ch_d: ChD<T>,
150 /// Channel E.
133 pub ch_e: ChE<T>, 151 pub ch_e: ChE<T>,
152 /// Channel F.
134 #[cfg(hrtim_v2)] 153 #[cfg(hrtim_v2)]
135 pub ch_f: ChF<T>, 154 pub ch_f: ChF<T>,
136} 155}
137 156
138impl<'d, T: Instance> AdvancedPwm<'d, T> { 157impl<'d, T: Instance> AdvancedPwm<'d, T> {
158 /// Create a new HRTIM driver.
159 ///
160 /// This splits the HRTIM into its constituent parts, which you can then use individually.
139 pub fn new( 161 pub fn new(
140 tim: impl Peripheral<P = T> + 'd, 162 tim: impl Peripheral<P = T> + 'd,
141 _cha: Option<PwmPin<'d, T, ChA<T>>>, 163 _cha: Option<PwmPin<'d, T, ChA<T>>>,
@@ -198,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
198 } 220 }
199} 221}
200 222
201impl<T: Instance> BurstController<T> { 223/// Fixed-frequency bridge converter driver.
202 pub fn set_source(&mut self, _source: Source) {
203 todo!("burst mode control registers not implemented")
204 }
205}
206
207/// Represents a fixed-frequency bridge converter
208/// 224///
209/// Our implementation of the bridge converter uses a single channel and three compare registers, 225/// Our implementation of the bridge converter uses a single channel and three compare registers,
210/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous 226/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous
@@ -223,6 +239,7 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
223} 239}
224 240
225impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { 241impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
242 /// Create a new HRTIM bridge converter driver.
226 pub fn new(_channel: C, frequency: Hertz) -> Self { 243 pub fn new(_channel: C, frequency: Hertz) -> Self {
227 use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; 244 use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
228 245
@@ -279,14 +296,17 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
279 } 296 }
280 } 297 }
281 298
299 /// Start HRTIM.
282 pub fn start(&mut self) { 300 pub fn start(&mut self) {
283 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); 301 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
284 } 302 }
285 303
304 /// Stop HRTIM.
286 pub fn stop(&mut self) { 305 pub fn stop(&mut self) {
287 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); 306 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
288 } 307 }
289 308
309 /// Enable burst mode.
290 pub fn enable_burst_mode(&mut self) { 310 pub fn enable_burst_mode(&mut self) {
291 T::regs().tim(C::raw()).outr().modify(|w| { 311 T::regs().tim(C::raw()).outr().modify(|w| {
292 // Enable Burst Mode 312 // Enable Burst Mode
@@ -299,6 +319,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
299 }) 319 })
300 } 320 }
301 321
322 /// Disable burst mode.
302 pub fn disable_burst_mode(&mut self) { 323 pub fn disable_burst_mode(&mut self) {
303 T::regs().tim(C::raw()).outr().modify(|w| { 324 T::regs().tim(C::raw()).outr().modify(|w| {
304 // Disable Burst Mode 325 // Disable Burst Mode
@@ -355,7 +376,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
355 } 376 }
356} 377}
357 378
358/// Represents a variable-frequency resonant converter 379/// Variable-frequency resonant converter driver.
359/// 380///
360/// This implementation of a resonsant converter is appropriate for a half or full bridge, 381/// This implementation of a resonsant converter is appropriate for a half or full bridge,
361/// but does not include secondary rectification, which is appropriate for applications 382/// but does not include secondary rectification, which is appropriate for applications
@@ -368,6 +389,7 @@ pub struct ResonantConverter<T: Instance, C: AdvancedChannel<T>> {
368} 389}
369 390
370impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { 391impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
392 /// Create a new variable-frequency resonant converter driver.
371 pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { 393 pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
372 T::set_channel_frequency(C::raw(), min_frequency); 394 T::set_channel_frequency(C::raw(), min_frequency);
373 395
@@ -406,6 +428,7 @@ impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
406 T::set_channel_dead_time(C::raw(), value); 428 T::set_channel_dead_time(C::raw(), value);
407 } 429 }
408 430
431 /// Set the timer period.
409 pub fn set_period(&mut self, period: u16) { 432 pub fn set_period(&mut self, period: u16) {
410 assert!(period < self.max_period); 433 assert!(period < self.max_period);
411 assert!(period > self.min_period); 434 assert!(period > self.min_period);
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs
index 34a363a1f..cfd31c47c 100644
--- a/embassy-stm32/src/hrtim/traits.rs
+++ b/embassy-stm32/src/hrtim/traits.rs
@@ -125,7 +125,6 @@ pub(crate) mod sealed {
125 } 125 }
126 126
127 /// Set the dead time as a proportion of max_duty 127 /// Set the dead time as a proportion of max_duty
128
129 fn set_channel_dead_time(channel: usize, dead_time: u16) { 128 fn set_channel_dead_time(channel: usize, dead_time: u16) {
130 let regs = Self::regs(); 129 let regs = Self::regs();
131 130
@@ -148,13 +147,10 @@ pub(crate) mod sealed {
148 w.set_dtr(dt_val as u16); 147 w.set_dtr(dt_val as u16);
149 }); 148 });
150 } 149 }
151
152 // fn enable_outputs(enable: bool);
153 //
154 // fn enable_channel(&mut self, channel: usize, enable: bool);
155 } 150 }
156} 151}
157 152
153/// HRTIM instance trait.
158pub trait Instance: sealed::Instance + 'static {} 154pub trait Instance: sealed::Instance + 'static {}
159 155
160foreach_interrupt! { 156foreach_interrupt! {
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index d2a50cf7e..2416005b5 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -1,30 +1,180 @@
1//! Inter-Integrated-Circuit (I2C)
1#![macro_use] 2#![macro_use]
2 3
3use core::marker::PhantomData;
4
5use crate::dma::NoDma;
6use crate::interrupt;
7
8#[cfg_attr(i2c_v1, path = "v1.rs")] 4#[cfg_attr(i2c_v1, path = "v1.rs")]
9#[cfg_attr(i2c_v2, path = "v2.rs")] 5#[cfg_attr(i2c_v2, path = "v2.rs")]
10mod _version; 6mod _version;
11pub use _version::*; 7
8use core::future::Future;
9use core::marker::PhantomData;
10
11use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
13#[cfg(feature = "time")]
14use embassy_time::{Duration, Instant};
13 15
14use crate::peripherals; 16use crate::dma::NoDma;
17use crate::gpio::sealed::AFType;
18use crate::gpio::Pull;
19use crate::interrupt::typelevel::Interrupt;
20use crate::time::Hertz;
21use crate::{interrupt, peripherals};
15 22
23/// I2C error.
16#[derive(Debug, PartialEq, Eq)] 24#[derive(Debug, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))] 25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Error { 26pub enum Error {
27 /// Bus error
19 Bus, 28 Bus,
29 /// Arbitration lost
20 Arbitration, 30 Arbitration,
31 /// ACK not received (either to the address or to a data byte)
21 Nack, 32 Nack,
33 /// Timeout
22 Timeout, 34 Timeout,
35 /// CRC error
23 Crc, 36 Crc,
37 /// Overrun error
24 Overrun, 38 Overrun,
39 /// Zero-length transfers are not allowed.
25 ZeroLengthTransfer, 40 ZeroLengthTransfer,
26} 41}
27 42
43/// I2C config
44#[non_exhaustive]
45#[derive(Copy, Clone)]
46pub struct Config {
47 /// Enable internal pullup on SDA.
48 ///
49 /// Using external pullup resistors is recommended for I2C. If you do
50 /// have external pullups you should not enable this.
51 pub sda_pullup: bool,
52 /// Enable internal pullup on SCL.
53 ///
54 /// Using external pullup resistors is recommended for I2C. If you do
55 /// have external pullups you should not enable this.
56 pub scl_pullup: bool,
57 /// Timeout.
58 #[cfg(feature = "time")]
59 pub timeout: embassy_time::Duration,
60}
61
62impl Default for Config {
63 fn default() -> Self {
64 Self {
65 sda_pullup: false,
66 scl_pullup: false,
67 #[cfg(feature = "time")]
68 timeout: embassy_time::Duration::from_millis(1000),
69 }
70 }
71}
72
73/// I2C driver.
74pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
75 _peri: PeripheralRef<'d, T>,
76 #[allow(dead_code)]
77 tx_dma: PeripheralRef<'d, TXDMA>,
78 #[allow(dead_code)]
79 rx_dma: PeripheralRef<'d, RXDMA>,
80 #[cfg(feature = "time")]
81 timeout: Duration,
82}
83
84impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
85 /// Create a new I2C driver.
86 pub fn new(
87 peri: impl Peripheral<P = T> + 'd,
88 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
89 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
90 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
91 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
92 + 'd,
93 tx_dma: impl Peripheral<P = TXDMA> + 'd,
94 rx_dma: impl Peripheral<P = RXDMA> + 'd,
95 freq: Hertz,
96 config: Config,
97 ) -> Self {
98 into_ref!(peri, scl, sda, tx_dma, rx_dma);
99
100 T::enable_and_reset();
101
102 scl.set_as_af_pull(
103 scl.af_num(),
104 AFType::OutputOpenDrain,
105 match config.scl_pullup {
106 true => Pull::Up,
107 false => Pull::None,
108 },
109 );
110 sda.set_as_af_pull(
111 sda.af_num(),
112 AFType::OutputOpenDrain,
113 match config.sda_pullup {
114 true => Pull::Up,
115 false => Pull::None,
116 },
117 );
118
119 unsafe { T::EventInterrupt::enable() };
120 unsafe { T::ErrorInterrupt::enable() };
121
122 let mut this = Self {
123 _peri: peri,
124 tx_dma,
125 rx_dma,
126 #[cfg(feature = "time")]
127 timeout: config.timeout,
128 };
129
130 this.init(freq, config);
131
132 this
133 }
134
135 fn timeout(&self) -> Timeout {
136 Timeout {
137 #[cfg(feature = "time")]
138 deadline: Instant::now() + self.timeout,
139 }
140 }
141}
142
143#[derive(Copy, Clone)]
144struct Timeout {
145 #[cfg(feature = "time")]
146 deadline: Instant,
147}
148
149#[allow(dead_code)]
150impl Timeout {
151 #[inline]
152 fn check(self) -> Result<(), Error> {
153 #[cfg(feature = "time")]
154 if Instant::now() > self.deadline {
155 return Err(Error::Timeout);
156 }
157
158 Ok(())
159 }
160
161 #[inline]
162 fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> {
163 #[cfg(feature = "time")]
164 {
165 use futures::FutureExt;
166
167 embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r {
168 embassy_futures::select::Either::First(_) => Err(Error::Timeout),
169 embassy_futures::select::Either::Second(r) => r,
170 })
171 }
172
173 #[cfg(not(feature = "time"))]
174 fut
175 }
176}
177
28pub(crate) mod sealed { 178pub(crate) mod sealed {
29 use super::*; 179 use super::*;
30 180
@@ -47,8 +197,11 @@ pub(crate) mod sealed {
47 } 197 }
48} 198}
49 199
200/// I2C peripheral instance
50pub trait Instance: sealed::Instance + 'static { 201pub trait Instance: sealed::Instance + 'static {
202 /// Event interrupt for this instance
51 type EventInterrupt: interrupt::typelevel::Interrupt; 203 type EventInterrupt: interrupt::typelevel::Interrupt;
204 /// Error interrupt for this instance
52 type ErrorInterrupt: interrupt::typelevel::Interrupt; 205 type ErrorInterrupt: interrupt::typelevel::Interrupt;
53} 206}
54 207
@@ -57,7 +210,7 @@ pin_trait!(SdaPin, Instance);
57dma_trait!(RxDma, Instance); 210dma_trait!(RxDma, Instance);
58dma_trait!(TxDma, Instance); 211dma_trait!(TxDma, Instance);
59 212
60/// Interrupt handler. 213/// Event interrupt handler.
61pub struct EventInterruptHandler<T: Instance> { 214pub struct EventInterruptHandler<T: Instance> {
62 _phantom: PhantomData<T>, 215 _phantom: PhantomData<T>,
63} 216}
@@ -68,6 +221,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInte
68 } 221 }
69} 222}
70 223
224/// Error interrupt handler.
71pub struct ErrorInterruptHandler<T: Instance> { 225pub struct ErrorInterruptHandler<T: Instance> {
72 _phantom: PhantomData<T>, 226 _phantom: PhantomData<T>,
73} 227}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index b62ee8246..cbbc201de 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -1,21 +1,32 @@
1//! # I2Cv1
2//!
3//! This implementation is used for STM32F1, STM32F2, STM32F4, and STM32L1 devices.
4//!
5//! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead.
6
1use core::future::poll_fn; 7use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::task::Poll; 8use core::task::Poll;
4 9
5use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
6use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
7use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
8use embassy_hal_internal::{into_ref, PeripheralRef};
9 13
10use super::*; 14use super::*;
11use crate::dma::{NoDma, Transfer}; 15use crate::dma::Transfer;
12use crate::gpio::sealed::AFType;
13use crate::gpio::Pull;
14use crate::interrupt::typelevel::Interrupt;
15use crate::pac::i2c; 16use crate::pac::i2c;
16use crate::time::Hertz; 17use crate::time::Hertz;
17use crate::{interrupt, Peripheral};
18 18
19// /!\ /!\
20// /!\ Implementation note! /!\
21// /!\ /!\
22//
23// It's somewhat unclear whether using interrupts here in a *strictly* one-shot style is actually
24// what we want! If you are looking in this file because you are doing async I2C and your code is
25// just totally hanging (sometimes), maybe swing by this issue:
26// <https://github.com/embassy-rs/embassy/issues/2372>.
27//
28// There's some more details there, and we might have a fix for you. But please let us know if you
29// hit a case like this!
19pub unsafe fn on_interrupt<T: Instance>() { 30pub unsafe fn on_interrupt<T: Instance>() {
20 let regs = T::regs(); 31 let regs = T::regs();
21 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 32 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
@@ -30,55 +41,8 @@ pub unsafe fn on_interrupt<T: Instance>() {
30 }); 41 });
31} 42}
32 43
33#[non_exhaustive]
34#[derive(Copy, Clone, Default)]
35pub struct Config {
36 pub sda_pullup: bool,
37 pub scl_pullup: bool,
38}
39
40pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
41 phantom: PhantomData<&'d mut T>,
42 #[allow(dead_code)]
43 tx_dma: PeripheralRef<'d, TXDMA>,
44 #[allow(dead_code)]
45 rx_dma: PeripheralRef<'d, RXDMA>,
46}
47
48impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
49 pub fn new( 45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
50 _peri: impl Peripheral<P = T> + 'd,
51 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
52 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
53 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
54 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
55 + 'd,
56 tx_dma: impl Peripheral<P = TXDMA> + 'd,
57 rx_dma: impl Peripheral<P = RXDMA> + 'd,
58 freq: Hertz,
59 config: Config,
60 ) -> Self {
61 into_ref!(scl, sda, tx_dma, rx_dma);
62
63 T::enable_and_reset();
64
65 scl.set_as_af_pull(
66 scl.af_num(),
67 AFType::OutputOpenDrain,
68 match config.scl_pullup {
69 true => Pull::Up,
70 false => Pull::None,
71 },
72 );
73 sda.set_as_af_pull(
74 sda.af_num(),
75 AFType::OutputOpenDrain,
76 match config.sda_pullup {
77 true => Pull::Up,
78 false => Pull::None,
79 },
80 );
81
82 T::regs().cr1().modify(|reg| { 46 T::regs().cr1().modify(|reg| {
83 reg.set_pe(false); 47 reg.set_pe(false);
84 //reg.set_anfoff(false); 48 //reg.set_anfoff(false);
@@ -101,15 +65,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
101 T::regs().cr1().modify(|reg| { 65 T::regs().cr1().modify(|reg| {
102 reg.set_pe(true); 66 reg.set_pe(true);
103 }); 67 });
104
105 unsafe { T::EventInterrupt::enable() };
106 unsafe { T::ErrorInterrupt::enable() };
107
108 Self {
109 phantom: PhantomData,
110 tx_dma,
111 rx_dma,
112 }
113 } 68 }
114 69
115 fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> { 70 fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> {
@@ -169,12 +124,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
169 Ok(sr1) 124 Ok(sr1)
170 } 125 }
171 126
172 fn write_bytes( 127 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> {
173 &mut self,
174 addr: u8,
175 bytes: &[u8],
176 check_timeout: impl Fn() -> Result<(), Error>,
177 ) -> Result<(), Error> {
178 // Send a START condition 128 // Send a START condition
179 129
180 T::regs().cr1().modify(|reg| { 130 T::regs().cr1().modify(|reg| {
@@ -183,7 +133,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
183 133
184 // Wait until START condition was generated 134 // Wait until START condition was generated
185 while !Self::check_and_clear_error_flags()?.start() { 135 while !Self::check_and_clear_error_flags()?.start() {
186 check_timeout()?; 136 timeout.check()?;
187 } 137 }
188 138
189 // Also wait until signalled we're master and everything is waiting for us 139 // Also wait until signalled we're master and everything is waiting for us
@@ -193,7 +143,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
193 let sr2 = T::regs().sr2().read(); 143 let sr2 = T::regs().sr2().read();
194 !sr2.msl() && !sr2.busy() 144 !sr2.msl() && !sr2.busy()
195 } { 145 } {
196 check_timeout()?; 146 timeout.check()?;
197 } 147 }
198 148
199 // Set up current address, we're trying to talk to 149 // Set up current address, we're trying to talk to
@@ -203,7 +153,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
203 // Wait for the address to be acknowledged 153 // Wait for the address to be acknowledged
204 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 154 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
205 while !Self::check_and_clear_error_flags()?.addr() { 155 while !Self::check_and_clear_error_flags()?.addr() {
206 check_timeout()?; 156 timeout.check()?;
207 } 157 }
208 158
209 // Clear condition by reading SR2 159 // Clear condition by reading SR2
@@ -211,20 +161,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
211 161
212 // Send bytes 162 // Send bytes
213 for c in bytes { 163 for c in bytes {
214 self.send_byte(*c, &check_timeout)?; 164 self.send_byte(*c, timeout)?;
215 } 165 }
216 166
217 // Fallthrough is success 167 // Fallthrough is success
218 Ok(()) 168 Ok(())
219 } 169 }
220 170
221 fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 171 fn send_byte(&self, byte: u8, timeout: Timeout) -> Result<(), Error> {
222 // Wait until we're ready for sending 172 // Wait until we're ready for sending
223 while { 173 while {
224 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 174 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
225 !Self::check_and_clear_error_flags()?.txe() 175 !Self::check_and_clear_error_flags()?.txe()
226 } { 176 } {
227 check_timeout()?; 177 timeout.check()?;
228 } 178 }
229 179
230 // Push out a byte of data 180 // Push out a byte of data
@@ -235,32 +185,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
235 // Check for any potential error conditions. 185 // Check for any potential error conditions.
236 !Self::check_and_clear_error_flags()?.btf() 186 !Self::check_and_clear_error_flags()?.btf()
237 } { 187 } {
238 check_timeout()?; 188 timeout.check()?;
239 } 189 }
240 190
241 Ok(()) 191 Ok(())
242 } 192 }
243 193
244 fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { 194 fn recv_byte(&self, timeout: Timeout) -> Result<u8, Error> {
245 while { 195 while {
246 // Check for any potential error conditions. 196 // Check for any potential error conditions.
247 Self::check_and_clear_error_flags()?; 197 Self::check_and_clear_error_flags()?;
248 198
249 !T::regs().sr1().read().rxne() 199 !T::regs().sr1().read().rxne()
250 } { 200 } {
251 check_timeout()?; 201 timeout.check()?;
252 } 202 }
253 203
254 let value = T::regs().dr().read().dr(); 204 let value = T::regs().dr().read().dr();
255 Ok(value) 205 Ok(value)
256 } 206 }
257 207
258 pub fn blocking_read_timeout( 208 fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> {
259 &mut self,
260 addr: u8,
261 buffer: &mut [u8],
262 check_timeout: impl Fn() -> Result<(), Error>,
263 ) -> Result<(), Error> {
264 if let Some((last, buffer)) = buffer.split_last_mut() { 209 if let Some((last, buffer)) = buffer.split_last_mut() {
265 // Send a START condition and set ACK bit 210 // Send a START condition and set ACK bit
266 T::regs().cr1().modify(|reg| { 211 T::regs().cr1().modify(|reg| {
@@ -270,7 +215,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
270 215
271 // Wait until START condition was generated 216 // Wait until START condition was generated
272 while !Self::check_and_clear_error_flags()?.start() { 217 while !Self::check_and_clear_error_flags()?.start() {
273 check_timeout()?; 218 timeout.check()?;
274 } 219 }
275 220
276 // Also wait until signalled we're master and everything is waiting for us 221 // Also wait until signalled we're master and everything is waiting for us
@@ -278,7 +223,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
278 let sr2 = T::regs().sr2().read(); 223 let sr2 = T::regs().sr2().read();
279 !sr2.msl() && !sr2.busy() 224 !sr2.msl() && !sr2.busy()
280 } { 225 } {
281 check_timeout()?; 226 timeout.check()?;
282 } 227 }
283 228
284 // Set up current address, we're trying to talk to 229 // Set up current address, we're trying to talk to
@@ -287,7 +232,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
287 // Wait until address was sent 232 // Wait until address was sent
288 // Wait for the address to be acknowledged 233 // Wait for the address to be acknowledged
289 while !Self::check_and_clear_error_flags()?.addr() { 234 while !Self::check_and_clear_error_flags()?.addr() {
290 check_timeout()?; 235 timeout.check()?;
291 } 236 }
292 237
293 // Clear condition by reading SR2 238 // Clear condition by reading SR2
@@ -295,7 +240,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
295 240
296 // Receive bytes into buffer 241 // Receive bytes into buffer
297 for c in buffer { 242 for c in buffer {
298 *c = self.recv_byte(&check_timeout)?; 243 *c = self.recv_byte(timeout)?;
299 } 244 }
300 245
301 // Prepare to send NACK then STOP after next byte 246 // Prepare to send NACK then STOP after next byte
@@ -305,11 +250,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
305 }); 250 });
306 251
307 // Receive last byte 252 // Receive last byte
308 *last = self.recv_byte(&check_timeout)?; 253 *last = self.recv_byte(timeout)?;
309 254
310 // Wait for the STOP to be sent. 255 // Wait for the STOP to be sent.
311 while T::regs().cr1().read().stop() { 256 while T::regs().cr1().read().stop() {
312 check_timeout()?; 257 timeout.check()?;
313 } 258 }
314 259
315 // Fallthrough is success 260 // Fallthrough is success
@@ -319,49 +264,37 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
319 } 264 }
320 } 265 }
321 266
267 /// Blocking read.
322 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 268 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
323 self.blocking_read_timeout(addr, read, || Ok(())) 269 self.blocking_read_timeout(addr, read, self.timeout())
324 } 270 }
325 271
326 pub fn blocking_write_timeout( 272 /// Blocking write.
327 &mut self, 273 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
328 addr: u8, 274 let timeout = self.timeout();
329 write: &[u8], 275
330 check_timeout: impl Fn() -> Result<(), Error>, 276 self.write_bytes(addr, write, timeout)?;
331 ) -> Result<(), Error> {
332 self.write_bytes(addr, write, &check_timeout)?;
333 // Send a STOP condition 277 // Send a STOP condition
334 T::regs().cr1().modify(|reg| reg.set_stop(true)); 278 T::regs().cr1().modify(|reg| reg.set_stop(true));
335 // Wait for STOP condition to transmit. 279 // Wait for STOP condition to transmit.
336 while T::regs().cr1().read().stop() { 280 while T::regs().cr1().read().stop() {
337 check_timeout()?; 281 timeout.check()?;
338 } 282 }
339 283
340 // Fallthrough is success 284 // Fallthrough is success
341 Ok(()) 285 Ok(())
342 } 286 }
343 287
344 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 288 /// Blocking write, restart, read.
345 self.blocking_write_timeout(addr, write, || Ok(())) 289 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
346 } 290 let timeout = self.timeout();
347 291
348 pub fn blocking_write_read_timeout( 292 self.write_bytes(addr, write, timeout)?;
349 &mut self, 293 self.blocking_read_timeout(addr, read, timeout)?;
350 addr: u8,
351 write: &[u8],
352 read: &mut [u8],
353 check_timeout: impl Fn() -> Result<(), Error>,
354 ) -> Result<(), Error> {
355 self.write_bytes(addr, write, &check_timeout)?;
356 self.blocking_read_timeout(addr, read, &check_timeout)?;
357 294
358 Ok(()) 295 Ok(())
359 } 296 }
360 297
361 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
362 self.blocking_write_read_timeout(addr, write, read, || Ok(()))
363 }
364
365 // Async 298 // Async
366 299
367 #[inline] // pretty sure this should always be inlined 300 #[inline] // pretty sure this should always be inlined
@@ -459,6 +392,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
459 T::regs().sr2().read(); 392 T::regs().sr2().read();
460 Poll::Ready(Ok(())) 393 Poll::Ready(Ok(()))
461 } else { 394 } else {
395 // If we need to go around, then re-enable the interrupts, otherwise nothing
396 // can wake us up and we'll hang.
397 Self::enable_interrupts();
462 Poll::Pending 398 Poll::Pending
463 } 399 }
464 } 400 }
@@ -522,6 +458,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
522 Ok(()) 458 Ok(())
523 } 459 }
524 460
461 /// Write.
525 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 462 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
526 where 463 where
527 TXDMA: crate::i2c::TxDma<T>, 464 TXDMA: crate::i2c::TxDma<T>,
@@ -544,6 +481,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
544 Ok(()) 481 Ok(())
545 } 482 }
546 483
484 /// Read.
547 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 485 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
548 where 486 where
549 RXDMA: crate::i2c::RxDma<T>, 487 RXDMA: crate::i2c::RxDma<T>,
@@ -703,6 +641,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
703 Ok(()) 641 Ok(())
704 } 642 }
705 643
644 /// Write, restart, read.
706 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 645 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
707 where 646 where
708 RXDMA: crate::i2c::RxDma<T>, 647 RXDMA: crate::i2c::RxDma<T>,
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 8c20e1c54..bd3abaac1 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -4,37 +4,13 @@ use core::task::Poll;
4 4
5use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
6use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
7use embassy_hal_internal::{into_ref, PeripheralRef};
8#[cfg(feature = "time")]
9use embassy_time::{Duration, Instant};
10 7
11use super::*; 8use super::*;
12use crate::dma::{NoDma, Transfer}; 9use crate::dma::Transfer;
13use crate::gpio::sealed::AFType;
14use crate::gpio::Pull;
15use crate::interrupt::typelevel::Interrupt;
16use crate::pac::i2c; 10use crate::pac::i2c;
17use crate::time::Hertz; 11use crate::time::Hertz;
18use crate::{interrupt, Peripheral};
19
20#[cfg(feature = "time")]
21fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
22 let deadline = Instant::now() + timeout;
23 move || {
24 if Instant::now() > deadline {
25 Err(Error::Timeout)
26 } else {
27 Ok(())
28 }
29 }
30}
31
32#[cfg(not(feature = "time"))]
33pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> {
34 move || Ok(())
35}
36 12
37pub unsafe fn on_interrupt<T: Instance>() { 13pub(crate) unsafe fn on_interrupt<T: Instance>() {
38 let regs = T::regs(); 14 let regs = T::regs();
39 let isr = regs.isr().read(); 15 let isr = regs.isr().read();
40 16
@@ -48,70 +24,8 @@ pub unsafe fn on_interrupt<T: Instance>() {
48 }); 24 });
49} 25}
50 26
51#[non_exhaustive]
52#[derive(Copy, Clone)]
53pub struct Config {
54 pub sda_pullup: bool,
55 pub scl_pullup: bool,
56 #[cfg(feature = "time")]
57 pub transaction_timeout: Duration,
58}
59
60impl Default for Config {
61 fn default() -> Self {
62 Self {
63 sda_pullup: false,
64 scl_pullup: false,
65 #[cfg(feature = "time")]
66 transaction_timeout: Duration::from_millis(100),
67 }
68 }
69}
70
71pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
72 _peri: PeripheralRef<'d, T>,
73 #[allow(dead_code)]
74 tx_dma: PeripheralRef<'d, TXDMA>,
75 #[allow(dead_code)]
76 rx_dma: PeripheralRef<'d, RXDMA>,
77 #[cfg(feature = "time")]
78 timeout: Duration,
79}
80
81impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 27impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
82 pub fn new( 28 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
83 peri: impl Peripheral<P = T> + 'd,
84 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
85 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
86 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
87 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
88 + 'd,
89 tx_dma: impl Peripheral<P = TXDMA> + 'd,
90 rx_dma: impl Peripheral<P = RXDMA> + 'd,
91 freq: Hertz,
92 config: Config,
93 ) -> Self {
94 into_ref!(peri, scl, sda, tx_dma, rx_dma);
95
96 T::enable_and_reset();
97
98 scl.set_as_af_pull(
99 scl.af_num(),
100 AFType::OutputOpenDrain,
101 match config.scl_pullup {
102 true => Pull::Up,
103 false => Pull::None,
104 },
105 );
106 sda.set_as_af_pull(
107 sda.af_num(),
108 AFType::OutputOpenDrain,
109 match config.sda_pullup {
110 true => Pull::Up,
111 false => Pull::None,
112 },
113 );
114
115 T::regs().cr1().modify(|reg| { 29 T::regs().cr1().modify(|reg| {
116 reg.set_pe(false); 30 reg.set_pe(false);
117 reg.set_anfoff(false); 31 reg.set_anfoff(false);
@@ -130,17 +44,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
130 T::regs().cr1().modify(|reg| { 44 T::regs().cr1().modify(|reg| {
131 reg.set_pe(true); 45 reg.set_pe(true);
132 }); 46 });
133
134 unsafe { T::EventInterrupt::enable() };
135 unsafe { T::ErrorInterrupt::enable() };
136
137 Self {
138 _peri: peri,
139 tx_dma,
140 rx_dma,
141 #[cfg(feature = "time")]
142 timeout: config.transaction_timeout,
143 }
144 } 47 }
145 48
146 fn master_stop(&mut self) { 49 fn master_stop(&mut self) {
@@ -153,7 +56,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
153 stop: Stop, 56 stop: Stop,
154 reload: bool, 57 reload: bool,
155 restart: bool, 58 restart: bool,
156 check_timeout: impl Fn() -> Result<(), Error>, 59 timeout: Timeout,
157 ) -> Result<(), Error> { 60 ) -> Result<(), Error> {
158 assert!(length < 256); 61 assert!(length < 256);
159 62
@@ -162,7 +65,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
162 // automatically. This could be up to 50% of a bus 65 // automatically. This could be up to 50% of a bus
163 // cycle (ie. up to 0.5/freq) 66 // cycle (ie. up to 0.5/freq)
164 while T::regs().cr2().read().start() { 67 while T::regs().cr2().read().start() {
165 check_timeout()?; 68 timeout.check()?;
166 } 69 }
167 } 70 }
168 71
@@ -189,20 +92,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
189 Ok(()) 92 Ok(())
190 } 93 }
191 94
192 fn master_write( 95 fn master_write(address: u8, length: usize, stop: Stop, reload: bool, timeout: Timeout) -> Result<(), Error> {
193 address: u8,
194 length: usize,
195 stop: Stop,
196 reload: bool,
197 check_timeout: impl Fn() -> Result<(), Error>,
198 ) -> Result<(), Error> {
199 assert!(length < 256); 96 assert!(length < 256);
200 97
201 // Wait for any previous address sequence to end 98 // Wait for any previous address sequence to end
202 // automatically. This could be up to 50% of a bus 99 // automatically. This could be up to 50% of a bus
203 // cycle (ie. up to 0.5/freq) 100 // cycle (ie. up to 0.5/freq)
204 while T::regs().cr2().read().start() { 101 while T::regs().cr2().read().start() {
205 check_timeout()?; 102 timeout.check()?;
206 } 103 }
207 104
208 let reload = if reload { 105 let reload = if reload {
@@ -227,15 +124,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
227 Ok(()) 124 Ok(())
228 } 125 }
229 126
230 fn master_continue( 127 fn master_continue(length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> {
231 length: usize,
232 reload: bool,
233 check_timeout: impl Fn() -> Result<(), Error>,
234 ) -> Result<(), Error> {
235 assert!(length < 256 && length > 0); 128 assert!(length < 256 && length > 0);
236 129
237 while !T::regs().isr().read().tcr() { 130 while !T::regs().isr().read().tcr() {
238 check_timeout()?; 131 timeout.check()?;
239 } 132 }
240 133
241 let reload = if reload { 134 let reload = if reload {
@@ -261,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
261 } 154 }
262 } 155 }
263 156
264 fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 157 fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> {
265 loop { 158 loop {
266 let isr = T::regs().isr().read(); 159 let isr = T::regs().isr().read();
267 if isr.txe() { 160 if isr.txe() {
@@ -278,11 +171,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
278 return Err(Error::Nack); 171 return Err(Error::Nack);
279 } 172 }
280 173
281 check_timeout()?; 174 timeout.check()?;
282 } 175 }
283 } 176 }
284 177
285 fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 178 fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> {
286 loop { 179 loop {
287 let isr = T::regs().isr().read(); 180 let isr = T::regs().isr().read();
288 if isr.rxne() { 181 if isr.rxne() {
@@ -299,11 +192,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
299 return Err(Error::Nack); 192 return Err(Error::Nack);
300 } 193 }
301 194
302 check_timeout()?; 195 timeout.check()?;
303 } 196 }
304 } 197 }
305 198
306 fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 199 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> {
307 loop { 200 loop {
308 let isr = T::regs().isr().read(); 201 let isr = T::regs().isr().read();
309 if isr.tc() { 202 if isr.tc() {
@@ -320,17 +213,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
320 return Err(Error::Nack); 213 return Err(Error::Nack);
321 } 214 }
322 215
323 check_timeout()?; 216 timeout.check()?;
324 } 217 }
325 } 218 }
326 219
327 fn read_internal( 220 fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> {
328 &mut self,
329 address: u8,
330 read: &mut [u8],
331 restart: bool,
332 check_timeout: impl Fn() -> Result<(), Error>,
333 ) -> Result<(), Error> {
334 let completed_chunks = read.len() / 255; 221 let completed_chunks = read.len() / 255;
335 let total_chunks = if completed_chunks * 255 == read.len() { 222 let total_chunks = if completed_chunks * 255 == read.len() {
336 completed_chunks 223 completed_chunks
@@ -345,17 +232,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
345 Stop::Automatic, 232 Stop::Automatic,
346 last_chunk_idx != 0, 233 last_chunk_idx != 0,
347 restart, 234 restart,
348 &check_timeout, 235 timeout,
349 )?; 236 )?;
350 237
351 for (number, chunk) in read.chunks_mut(255).enumerate() { 238 for (number, chunk) in read.chunks_mut(255).enumerate() {
352 if number != 0 { 239 if number != 0 {
353 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; 240 Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?;
354 } 241 }
355 242
356 for byte in chunk { 243 for byte in chunk {
357 // Wait until we have received something 244 // Wait until we have received something
358 self.wait_rxne(&check_timeout)?; 245 self.wait_rxne(timeout)?;
359 246
360 *byte = T::regs().rxdr().read().rxdata(); 247 *byte = T::regs().rxdr().read().rxdata();
361 } 248 }
@@ -363,13 +250,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
363 Ok(()) 250 Ok(())
364 } 251 }
365 252
366 fn write_internal( 253 fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> {
367 &mut self,
368 address: u8,
369 write: &[u8],
370 send_stop: bool,
371 check_timeout: impl Fn() -> Result<(), Error>,
372 ) -> Result<(), Error> {
373 let completed_chunks = write.len() / 255; 254 let completed_chunks = write.len() / 255;
374 let total_chunks = if completed_chunks * 255 == write.len() { 255 let total_chunks = if completed_chunks * 255 == write.len() {
375 completed_chunks 256 completed_chunks
@@ -386,7 +267,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
386 write.len().min(255), 267 write.len().min(255),
387 Stop::Software, 268 Stop::Software,
388 last_chunk_idx != 0, 269 last_chunk_idx != 0,
389 &check_timeout, 270 timeout,
390 ) { 271 ) {
391 if send_stop { 272 if send_stop {
392 self.master_stop(); 273 self.master_stop();
@@ -396,14 +277,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
396 277
397 for (number, chunk) in write.chunks(255).enumerate() { 278 for (number, chunk) in write.chunks(255).enumerate() {
398 if number != 0 { 279 if number != 0 {
399 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; 280 Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?;
400 } 281 }
401 282
402 for byte in chunk { 283 for byte in chunk {
403 // Wait until we are allowed to send data 284 // Wait until we are allowed to send data
404 // (START has been ACKed or last byte when 285 // (START has been ACKed or last byte when
405 // through) 286 // through)
406 if let Err(err) = self.wait_txe(&check_timeout) { 287 if let Err(err) = self.wait_txe(timeout) {
407 if send_stop { 288 if send_stop {
408 self.master_stop(); 289 self.master_stop();
409 } 290 }
@@ -414,7 +295,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
414 } 295 }
415 } 296 }
416 // Wait until the write finishes 297 // Wait until the write finishes
417 let result = self.wait_tc(&check_timeout); 298 let result = self.wait_tc(timeout);
418 if send_stop { 299 if send_stop {
419 self.master_stop(); 300 self.master_stop();
420 } 301 }
@@ -427,7 +308,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
427 write: &[u8], 308 write: &[u8],
428 first_slice: bool, 309 first_slice: bool,
429 last_slice: bool, 310 last_slice: bool,
430 check_timeout: impl Fn() -> Result<(), Error>, 311 timeout: Timeout,
431 ) -> Result<(), Error> 312 ) -> Result<(), Error>
432 where 313 where
433 TXDMA: crate::i2c::TxDma<T>, 314 TXDMA: crate::i2c::TxDma<T>,
@@ -473,10 +354,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
473 total_len.min(255), 354 total_len.min(255),
474 Stop::Software, 355 Stop::Software,
475 (total_len > 255) || !last_slice, 356 (total_len > 255) || !last_slice,
476 &check_timeout, 357 timeout,
477 )?; 358 )?;
478 } else { 359 } else {
479 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; 360 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?;
480 T::regs().cr1().modify(|w| w.set_tcie(true)); 361 T::regs().cr1().modify(|w| w.set_tcie(true));
481 } 362 }
482 } else if !(isr.tcr() || isr.tc()) { 363 } else if !(isr.tcr() || isr.tc()) {
@@ -487,7 +368,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
487 } else { 368 } else {
488 let last_piece = (remaining_len <= 255) && last_slice; 369 let last_piece = (remaining_len <= 255) && last_slice;
489 370
490 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { 371 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
491 return Poll::Ready(Err(e)); 372 return Poll::Ready(Err(e));
492 } 373 }
493 T::regs().cr1().modify(|w| w.set_tcie(true)); 374 T::regs().cr1().modify(|w| w.set_tcie(true));
@@ -502,7 +383,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
502 383
503 if last_slice { 384 if last_slice {
504 // This should be done already 385 // This should be done already
505 self.wait_tc(&check_timeout)?; 386 self.wait_tc(timeout)?;
506 self.master_stop(); 387 self.master_stop();
507 } 388 }
508 389
@@ -516,7 +397,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
516 address: u8, 397 address: u8,
517 buffer: &mut [u8], 398 buffer: &mut [u8],
518 restart: bool, 399 restart: bool,
519 check_timeout: impl Fn() -> Result<(), Error>, 400 timeout: Timeout,
520 ) -> Result<(), Error> 401 ) -> Result<(), Error>
521 where 402 where
522 RXDMA: crate::i2c::RxDma<T>, 403 RXDMA: crate::i2c::RxDma<T>,
@@ -558,7 +439,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
558 Stop::Software, 439 Stop::Software,
559 total_len > 255, 440 total_len > 255,
560 restart, 441 restart,
561 &check_timeout, 442 timeout,
562 )?; 443 )?;
563 } else if !(isr.tcr() || isr.tc()) { 444 } else if !(isr.tcr() || isr.tc()) {
564 // poll_fn was woken without an interrupt present 445 // poll_fn was woken without an interrupt present
@@ -568,7 +449,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
568 } else { 449 } else {
569 let last_piece = remaining_len <= 255; 450 let last_piece = remaining_len <= 255;
570 451
571 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { 452 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
572 return Poll::Ready(Err(e)); 453 return Poll::Ready(Err(e));
573 } 454 }
574 T::regs().cr1().modify(|w| w.set_tcie(true)); 455 T::regs().cr1().modify(|w| w.set_tcie(true));
@@ -582,7 +463,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
582 dma_transfer.await; 463 dma_transfer.await;
583 464
584 // This should be done already 465 // This should be done already
585 self.wait_tc(&check_timeout)?; 466 self.wait_tc(timeout)?;
586 self.master_stop(); 467 self.master_stop();
587 468
588 drop(on_drop); 469 drop(on_drop);
@@ -592,69 +473,31 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
592 473
593 // ========================= 474 // =========================
594 // Async public API 475 // Async public API
595 #[cfg(feature = "time")]
596 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
597 where
598 TXDMA: crate::i2c::TxDma<T>,
599 {
600 if write.is_empty() {
601 self.write_internal(address, write, true, timeout_fn(self.timeout))
602 } else {
603 embassy_time::with_timeout(
604 self.timeout,
605 self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)),
606 )
607 .await
608 .unwrap_or(Err(Error::Timeout))
609 }
610 }
611 476
612 #[cfg(not(feature = "time"))] 477 /// Write.
613 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 478 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
614 where 479 where
615 TXDMA: crate::i2c::TxDma<T>, 480 TXDMA: crate::i2c::TxDma<T>,
616 { 481 {
482 let timeout = self.timeout();
617 if write.is_empty() { 483 if write.is_empty() {
618 self.write_internal(address, write, true, no_timeout_fn()) 484 self.write_internal(address, write, true, timeout)
619 } else { 485 } else {
620 self.write_dma_internal(address, write, true, true, no_timeout_fn()) 486 timeout
487 .with(self.write_dma_internal(address, write, true, true, timeout))
621 .await 488 .await
622 } 489 }
623 } 490 }
624 491
625 #[cfg(feature = "time")] 492 /// Write multiple buffers.
493 ///
494 /// The buffers are concatenated in a single write transaction.
626 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> 495 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
627 where 496 where
628 TXDMA: crate::i2c::TxDma<T>, 497 TXDMA: crate::i2c::TxDma<T>,
629 { 498 {
630 if write.is_empty() { 499 let timeout = self.timeout();
631 return Err(Error::ZeroLengthTransfer);
632 }
633 let mut iter = write.iter();
634
635 let mut first = true;
636 let mut current = iter.next();
637 while let Some(c) = current {
638 let next = iter.next();
639 let is_last = next.is_none();
640
641 embassy_time::with_timeout(
642 self.timeout,
643 self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)),
644 )
645 .await
646 .unwrap_or(Err(Error::Timeout))?;
647 first = false;
648 current = next;
649 }
650 Ok(())
651 }
652 500
653 #[cfg(not(feature = "time"))]
654 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
655 where
656 TXDMA: crate::i2c::TxDma<T>,
657 {
658 if write.is_empty() { 501 if write.is_empty() {
659 return Err(Error::ZeroLengthTransfer); 502 return Err(Error::ZeroLengthTransfer);
660 } 503 }
@@ -666,95 +509,49 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
666 let next = iter.next(); 509 let next = iter.next();
667 let is_last = next.is_none(); 510 let is_last = next.is_none();
668 511
669 self.write_dma_internal(address, c, first, is_last, no_timeout_fn()) 512 let fut = self.write_dma_internal(address, c, first, is_last, timeout);
670 .await?; 513 timeout.with(fut).await?;
671 first = false; 514 first = false;
672 current = next; 515 current = next;
673 } 516 }
674 Ok(()) 517 Ok(())
675 } 518 }
676 519
677 #[cfg(feature = "time")] 520 /// Read.
678 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 521 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
679 where 522 where
680 RXDMA: crate::i2c::RxDma<T>, 523 RXDMA: crate::i2c::RxDma<T>,
681 { 524 {
682 if buffer.is_empty() { 525 let timeout = self.timeout();
683 self.read_internal(address, buffer, false, timeout_fn(self.timeout))
684 } else {
685 embassy_time::with_timeout(
686 self.timeout,
687 self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)),
688 )
689 .await
690 .unwrap_or(Err(Error::Timeout))
691 }
692 }
693 526
694 #[cfg(not(feature = "time"))]
695 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
696 where
697 RXDMA: crate::i2c::RxDma<T>,
698 {
699 if buffer.is_empty() { 527 if buffer.is_empty() {
700 self.read_internal(address, buffer, false, no_timeout_fn()) 528 self.read_internal(address, buffer, false, timeout)
701 } else { 529 } else {
702 self.read_dma_internal(address, buffer, false, no_timeout_fn()).await 530 let fut = self.read_dma_internal(address, buffer, false, timeout);
531 timeout.with(fut).await
703 } 532 }
704 } 533 }
705 534
706 #[cfg(feature = "time")] 535 /// Write, restart, read.
707 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 536 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
708 where 537 where
709 TXDMA: super::TxDma<T>, 538 TXDMA: super::TxDma<T>,
710 RXDMA: super::RxDma<T>, 539 RXDMA: super::RxDma<T>,
711 { 540 {
712 let start_instant = Instant::now(); 541 let timeout = self.timeout();
713 let check_timeout = timeout_fn(self.timeout);
714 if write.is_empty() {
715 self.write_internal(address, write, false, &check_timeout)?;
716 } else {
717 embassy_time::with_timeout(
718 self.timeout,
719 self.write_dma_internal(address, write, true, true, &check_timeout),
720 )
721 .await
722 .unwrap_or(Err(Error::Timeout))?;
723 }
724
725 let time_left_until_timeout = self.timeout - Instant::now().duration_since(start_instant);
726 542
727 if read.is_empty() {
728 self.read_internal(address, read, true, &check_timeout)?;
729 } else {
730 embassy_time::with_timeout(
731 time_left_until_timeout,
732 self.read_dma_internal(address, read, true, &check_timeout),
733 )
734 .await
735 .unwrap_or(Err(Error::Timeout))?;
736 }
737
738 Ok(())
739 }
740
741 #[cfg(not(feature = "time"))]
742 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
743 where
744 TXDMA: super::TxDma<T>,
745 RXDMA: super::RxDma<T>,
746 {
747 let no_timeout = no_timeout_fn();
748 if write.is_empty() { 543 if write.is_empty() {
749 self.write_internal(address, write, false, &no_timeout)?; 544 self.write_internal(address, write, false, timeout)?;
750 } else { 545 } else {
751 self.write_dma_internal(address, write, true, true, &no_timeout).await?; 546 let fut = self.write_dma_internal(address, write, true, true, timeout);
547 timeout.with(fut).await?;
752 } 548 }
753 549
754 if read.is_empty() { 550 if read.is_empty() {
755 self.read_internal(address, read, true, &no_timeout)?; 551 self.read_internal(address, read, true, timeout)?;
756 } else { 552 } else {
757 self.read_dma_internal(address, read, true, &no_timeout).await?; 553 let fut = self.read_dma_internal(address, read, true, timeout);
554 timeout.with(fut).await?;
758 } 555 }
759 556
760 Ok(()) 557 Ok(())
@@ -763,105 +560,35 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
763 // ========================= 560 // =========================
764 // Blocking public API 561 // Blocking public API
765 562
766 #[cfg(feature = "time")] 563 /// Blocking read.
767 pub fn blocking_read_timeout(&mut self, address: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> {
768 self.read_internal(address, read, false, timeout_fn(timeout))
769 // Automatic Stop
770 }
771
772 #[cfg(not(feature = "time"))]
773 pub fn blocking_read_timeout(
774 &mut self,
775 address: u8,
776 read: &mut [u8],
777 check_timeout: impl Fn() -> Result<(), Error>,
778 ) -> Result<(), Error> {
779 self.read_internal(address, read, false, check_timeout)
780 // Automatic Stop
781 }
782
783 #[cfg(feature = "time")]
784 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
785 self.blocking_read_timeout(address, read, self.timeout)
786 }
787
788 #[cfg(not(feature = "time"))]
789 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { 564 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
790 self.blocking_read_timeout(address, read, || Ok(())) 565 self.read_internal(address, read, false, self.timeout())
791 }
792
793 #[cfg(feature = "time")]
794 pub fn blocking_write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> {
795 self.write_internal(address, write, true, timeout_fn(timeout))
796 }
797
798 #[cfg(not(feature = "time"))]
799 pub fn blocking_write_timeout(
800 &mut self,
801 address: u8,
802 write: &[u8],
803 check_timeout: impl Fn() -> Result<(), Error>,
804 ) -> Result<(), Error> {
805 self.write_internal(address, write, true, check_timeout)
806 }
807
808 #[cfg(feature = "time")]
809 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
810 self.blocking_write_timeout(address, write, self.timeout)
811 }
812
813 #[cfg(not(feature = "time"))]
814 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
815 self.blocking_write_timeout(address, write, || Ok(()))
816 }
817
818 #[cfg(feature = "time")]
819 pub fn blocking_write_read_timeout(
820 &mut self,
821 address: u8,
822 write: &[u8],
823 read: &mut [u8],
824 timeout: Duration,
825 ) -> Result<(), Error> {
826 let check_timeout = timeout_fn(timeout);
827 self.write_internal(address, write, false, &check_timeout)?;
828 self.read_internal(address, read, true, &check_timeout)
829 // Automatic Stop 566 // Automatic Stop
830 } 567 }
831 568
832 #[cfg(not(feature = "time"))] 569 /// Blocking write.
833 pub fn blocking_write_read_timeout( 570 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
834 &mut self, 571 self.write_internal(address, write, true, self.timeout())
835 address: u8,
836 write: &[u8],
837 read: &mut [u8],
838 check_timeout: impl Fn() -> Result<(), Error>,
839 ) -> Result<(), Error> {
840 self.write_internal(address, write, false, &check_timeout)?;
841 self.read_internal(address, read, true, &check_timeout)
842 // Automatic Stop
843 }
844
845 #[cfg(feature = "time")]
846 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
847 self.blocking_write_read_timeout(address, write, read, self.timeout)
848 } 572 }
849 573
850 #[cfg(not(feature = "time"))] 574 /// Blocking write, restart, read.
851 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 575 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
852 self.blocking_write_read_timeout(address, write, read, || Ok(())) 576 let timeout = self.timeout();
577 self.write_internal(address, write, false, timeout)?;
578 self.read_internal(address, read, true, timeout)
579 // Automatic Stop
853 } 580 }
854 581
855 fn blocking_write_vectored_with_timeout( 582 /// Blocking write multiple buffers.
856 &mut self, 583 ///
857 address: u8, 584 /// The buffers are concatenated in a single write transaction.
858 write: &[&[u8]], 585 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
859 check_timeout: impl Fn() -> Result<(), Error>,
860 ) -> Result<(), Error> {
861 if write.is_empty() { 586 if write.is_empty() {
862 return Err(Error::ZeroLengthTransfer); 587 return Err(Error::ZeroLengthTransfer);
863 } 588 }
864 589
590 let timeout = self.timeout();
591
865 let first_length = write[0].len(); 592 let first_length = write[0].len();
866 let last_slice_index = write.len() - 1; 593 let last_slice_index = write.len() - 1;
867 594
@@ -870,7 +597,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
870 first_length.min(255), 597 first_length.min(255),
871 Stop::Software, 598 Stop::Software,
872 (first_length > 255) || (last_slice_index != 0), 599 (first_length > 255) || (last_slice_index != 0),
873 &check_timeout, 600 timeout,
874 ) { 601 ) {
875 self.master_stop(); 602 self.master_stop();
876 return Err(err); 603 return Err(err);
@@ -890,7 +617,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
890 if let Err(err) = Self::master_continue( 617 if let Err(err) = Self::master_continue(
891 slice_len.min(255), 618 slice_len.min(255),
892 (idx != last_slice_index) || (slice_len > 255), 619 (idx != last_slice_index) || (slice_len > 255),
893 &check_timeout, 620 timeout,
894 ) { 621 ) {
895 self.master_stop(); 622 self.master_stop();
896 return Err(err); 623 return Err(err);
@@ -902,7 +629,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
902 if let Err(err) = Self::master_continue( 629 if let Err(err) = Self::master_continue(
903 chunk.len(), 630 chunk.len(),
904 (number != last_chunk_idx) || (idx != last_slice_index), 631 (number != last_chunk_idx) || (idx != last_slice_index),
905 &check_timeout, 632 timeout,
906 ) { 633 ) {
907 self.master_stop(); 634 self.master_stop();
908 return Err(err); 635 return Err(err);
@@ -913,7 +640,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
913 // Wait until we are allowed to send data 640 // Wait until we are allowed to send data
914 // (START has been ACKed or last byte when 641 // (START has been ACKed or last byte when
915 // through) 642 // through)
916 if let Err(err) = self.wait_txe(&check_timeout) { 643 if let Err(err) = self.wait_txe(timeout) {
917 self.master_stop(); 644 self.master_stop();
918 return Err(err); 645 return Err(err);
919 } 646 }
@@ -925,41 +652,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
925 } 652 }
926 } 653 }
927 // Wait until the write finishes 654 // Wait until the write finishes
928 let result = self.wait_tc(&check_timeout); 655 let result = self.wait_tc(timeout);
929 self.master_stop(); 656 self.master_stop();
930 result 657 result
931 } 658 }
932
933 #[cfg(feature = "time")]
934 pub fn blocking_write_vectored_timeout(
935 &mut self,
936 address: u8,
937 write: &[&[u8]],
938 timeout: Duration,
939 ) -> Result<(), Error> {
940 let check_timeout = timeout_fn(timeout);
941 self.blocking_write_vectored_with_timeout(address, write, check_timeout)
942 }
943
944 #[cfg(not(feature = "time"))]
945 pub fn blocking_write_vectored_timeout(
946 &mut self,
947 address: u8,
948 write: &[&[u8]],
949 check_timeout: impl Fn() -> Result<(), Error>,
950 ) -> Result<(), Error> {
951 self.blocking_write_vectored_with_timeout(address, write, check_timeout)
952 }
953
954 #[cfg(feature = "time")]
955 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
956 self.blocking_write_vectored_timeout(address, write, self.timeout)
957 }
958
959 #[cfg(not(feature = "time"))]
960 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
961 self.blocking_write_vectored_timeout(address, write, || Ok(()))
962 }
963} 659}
964 660
965impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 661impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 67d40c479..1f85c0bc5 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -1,3 +1,4 @@
1//! Inter-IC Sound (I2S)
1use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
2 3
3use crate::gpio::sealed::{AFType, Pin as _}; 4use crate::gpio::sealed::{AFType, Pin as _};
@@ -8,30 +9,42 @@ use crate::spi::{Config as SpiConfig, *};
8use crate::time::Hertz; 9use crate::time::Hertz;
9use crate::{Peripheral, PeripheralRef}; 10use crate::{Peripheral, PeripheralRef};
10 11
12/// I2S mode
11#[derive(Copy, Clone)] 13#[derive(Copy, Clone)]
12pub enum Mode { 14pub enum Mode {
15 /// Master mode
13 Master, 16 Master,
17 /// Slave mode
14 Slave, 18 Slave,
15} 19}
16 20
21/// I2S function
17#[derive(Copy, Clone)] 22#[derive(Copy, Clone)]
18pub enum Function { 23pub enum Function {
24 /// Transmit audio data
19 Transmit, 25 Transmit,
26 /// Receive audio data
20 Receive, 27 Receive,
21} 28}
22 29
30/// I2C standard
23#[derive(Copy, Clone)] 31#[derive(Copy, Clone)]
24pub enum Standard { 32pub enum Standard {
33 /// Philips
25 Philips, 34 Philips,
35 /// Most significant bit first.
26 MsbFirst, 36 MsbFirst,
37 /// Least significant bit first.
27 LsbFirst, 38 LsbFirst,
39 /// PCM with long sync.
28 PcmLongSync, 40 PcmLongSync,
41 /// PCM with short sync.
29 PcmShortSync, 42 PcmShortSync,
30} 43}
31 44
32impl Standard { 45impl Standard {
33 #[cfg(any(spi_v1, spi_f1))] 46 #[cfg(any(spi_v1, spi_f1))]
34 pub const fn i2sstd(&self) -> vals::I2sstd { 47 const fn i2sstd(&self) -> vals::I2sstd {
35 match self { 48 match self {
36 Standard::Philips => vals::I2sstd::PHILIPS, 49 Standard::Philips => vals::I2sstd::PHILIPS,
37 Standard::MsbFirst => vals::I2sstd::MSB, 50 Standard::MsbFirst => vals::I2sstd::MSB,
@@ -42,7 +55,7 @@ impl Standard {
42 } 55 }
43 56
44 #[cfg(any(spi_v1, spi_f1))] 57 #[cfg(any(spi_v1, spi_f1))]
45 pub const fn pcmsync(&self) -> vals::Pcmsync { 58 const fn pcmsync(&self) -> vals::Pcmsync {
46 match self { 59 match self {
47 Standard::PcmLongSync => vals::Pcmsync::LONG, 60 Standard::PcmLongSync => vals::Pcmsync::LONG,
48 _ => vals::Pcmsync::SHORT, 61 _ => vals::Pcmsync::SHORT,
@@ -50,6 +63,7 @@ impl Standard {
50 } 63 }
51} 64}
52 65
66/// I2S data format.
53#[derive(Copy, Clone)] 67#[derive(Copy, Clone)]
54pub enum Format { 68pub enum Format {
55 /// 16 bit data length on 16 bit wide channel 69 /// 16 bit data length on 16 bit wide channel
@@ -64,7 +78,7 @@ pub enum Format {
64 78
65impl Format { 79impl Format {
66 #[cfg(any(spi_v1, spi_f1))] 80 #[cfg(any(spi_v1, spi_f1))]
67 pub const fn datlen(&self) -> vals::Datlen { 81 const fn datlen(&self) -> vals::Datlen {
68 match self { 82 match self {
69 Format::Data16Channel16 => vals::Datlen::SIXTEENBIT, 83 Format::Data16Channel16 => vals::Datlen::SIXTEENBIT,
70 Format::Data16Channel32 => vals::Datlen::SIXTEENBIT, 84 Format::Data16Channel32 => vals::Datlen::SIXTEENBIT,
@@ -74,7 +88,7 @@ impl Format {
74 } 88 }
75 89
76 #[cfg(any(spi_v1, spi_f1))] 90 #[cfg(any(spi_v1, spi_f1))]
77 pub const fn chlen(&self) -> vals::Chlen { 91 const fn chlen(&self) -> vals::Chlen {
78 match self { 92 match self {
79 Format::Data16Channel16 => vals::Chlen::SIXTEENBIT, 93 Format::Data16Channel16 => vals::Chlen::SIXTEENBIT,
80 Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT, 94 Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT,
@@ -84,15 +98,18 @@ impl Format {
84 } 98 }
85} 99}
86 100
101/// Clock polarity
87#[derive(Copy, Clone)] 102#[derive(Copy, Clone)]
88pub enum ClockPolarity { 103pub enum ClockPolarity {
104 /// Low on idle.
89 IdleLow, 105 IdleLow,
106 /// High on idle.
90 IdleHigh, 107 IdleHigh,
91} 108}
92 109
93impl ClockPolarity { 110impl ClockPolarity {
94 #[cfg(any(spi_v1, spi_f1))] 111 #[cfg(any(spi_v1, spi_f1))]
95 pub const fn ckpol(&self) -> vals::Ckpol { 112 const fn ckpol(&self) -> vals::Ckpol {
96 match self { 113 match self {
97 ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, 114 ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH,
98 ClockPolarity::IdleLow => vals::Ckpol::IDLELOW, 115 ClockPolarity::IdleLow => vals::Ckpol::IDLELOW,
@@ -109,11 +126,17 @@ impl ClockPolarity {
109#[non_exhaustive] 126#[non_exhaustive]
110#[derive(Copy, Clone)] 127#[derive(Copy, Clone)]
111pub struct Config { 128pub struct Config {
129 /// Mode
112 pub mode: Mode, 130 pub mode: Mode,
131 /// Function (transmit, receive)
113 pub function: Function, 132 pub function: Function,
133 /// Which I2S standard to use.
114 pub standard: Standard, 134 pub standard: Standard,
135 /// Data format.
115 pub format: Format, 136 pub format: Format,
137 /// Clock polarity.
116 pub clock_polarity: ClockPolarity, 138 pub clock_polarity: ClockPolarity,
139 /// True to eanble master clock output from this instance.
117 pub master_clock: bool, 140 pub master_clock: bool,
118} 141}
119 142
@@ -130,6 +153,7 @@ impl Default for Config {
130 } 153 }
131} 154}
132 155
156/// I2S driver.
133pub struct I2S<'d, T: Instance, Tx, Rx> { 157pub struct I2S<'d, T: Instance, Tx, Rx> {
134 _peri: Spi<'d, T, Tx, Rx>, 158 _peri: Spi<'d, T, Tx, Rx>,
135 sd: Option<PeripheralRef<'d, AnyPin>>, 159 sd: Option<PeripheralRef<'d, AnyPin>>,
@@ -242,6 +266,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
242 } 266 }
243 } 267 }
244 268
269 /// Write audio data.
245 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 270 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
246 where 271 where
247 Tx: TxDma<T>, 272 Tx: TxDma<T>,
@@ -249,6 +274,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
249 self._peri.write(data).await 274 self._peri.write(data).await
250 } 275 }
251 276
277 /// Read audio data.
252 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 278 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
253 where 279 where
254 Tx: TxDma<T>, 280 Tx: TxDma<T>,
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 4006dee19..663a7f59d 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,3 +1,5 @@
1//! Inter-Process Communication Controller (IPCC)
2
1use core::future::poll_fn; 3use core::future::poll_fn;
2use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
3use core::task::Poll; 5use core::task::Poll;
@@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
41 } 43 }
42} 44}
43 45
46/// TX interrupt handler.
44pub struct TransmitInterruptHandler {} 47pub struct TransmitInterruptHandler {}
45 48
46impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { 49impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
@@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
72 } 75 }
73} 76}
74 77
78/// IPCC config.
75#[non_exhaustive] 79#[non_exhaustive]
76#[derive(Clone, Copy, Default)] 80#[derive(Clone, Copy, Default)]
77pub struct Config { 81pub struct Config {
@@ -79,6 +83,8 @@ pub struct Config {
79 // reserved for future use 83 // reserved for future use
80} 84}
81 85
86/// Channel.
87#[allow(missing_docs)]
82#[derive(Debug, Clone, Copy)] 88#[derive(Debug, Clone, Copy)]
83#[repr(C)] 89#[repr(C)]
84pub enum IpccChannel { 90pub enum IpccChannel {
@@ -90,9 +96,11 @@ pub enum IpccChannel {
90 Channel6 = 5, 96 Channel6 = 5,
91} 97}
92 98
99/// IPCC driver.
93pub struct Ipcc; 100pub struct Ipcc;
94 101
95impl Ipcc { 102impl Ipcc {
103 /// Enable IPCC.
96 pub fn enable(_config: Config) { 104 pub fn enable(_config: Config) {
97 IPCC::enable_and_reset(); 105 IPCC::enable_and_reset();
98 IPCC::set_cpu2(true); 106 IPCC::set_cpu2(true);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 5d9b4e6a0..f10e9d50d 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,5 +1,6 @@
1#![cfg_attr(not(test), no_std)] 1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![warn(missing_docs)]
3 4
4//! ## Feature flags 5//! ## Feature flags
5#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] 6#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
@@ -79,6 +80,7 @@ pub(crate) mod _generated {
79 #![allow(dead_code)] 80 #![allow(dead_code)]
80 #![allow(unused_imports)] 81 #![allow(unused_imports)]
81 #![allow(non_snake_case)] 82 #![allow(non_snake_case)]
83 #![allow(missing_docs)]
82 84
83 include!(concat!(env!("OUT_DIR"), "/_generated.rs")); 85 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
84} 86}
@@ -149,15 +151,33 @@ use crate::interrupt::Priority;
149pub use crate::pac::NVIC_PRIO_BITS; 151pub use crate::pac::NVIC_PRIO_BITS;
150use crate::rcc::sealed::RccPeripheral; 152use crate::rcc::sealed::RccPeripheral;
151 153
154/// `embassy-stm32` global configuration.
152#[non_exhaustive] 155#[non_exhaustive]
153pub struct Config { 156pub struct Config {
157 /// RCC config.
154 pub rcc: rcc::Config, 158 pub rcc: rcc::Config,
159
160 /// Enable debug during sleep.
161 ///
162 /// May incrase power consumption. Defaults to true.
155 #[cfg(dbgmcu)] 163 #[cfg(dbgmcu)]
156 pub enable_debug_during_sleep: bool, 164 pub enable_debug_during_sleep: bool,
165
166 /// BDMA interrupt priority.
167 ///
168 /// Defaults to P0 (highest).
157 #[cfg(bdma)] 169 #[cfg(bdma)]
158 pub bdma_interrupt_priority: Priority, 170 pub bdma_interrupt_priority: Priority,
171
172 /// DMA interrupt priority.
173 ///
174 /// Defaults to P0 (highest).
159 #[cfg(dma)] 175 #[cfg(dma)]
160 pub dma_interrupt_priority: Priority, 176 pub dma_interrupt_priority: Priority,
177
178 /// GPDMA interrupt priority.
179 ///
180 /// Defaults to P0 (highest).
161 #[cfg(gpdma)] 181 #[cfg(gpdma)]
162 pub gpdma_interrupt_priority: Priority, 182 pub gpdma_interrupt_priority: Priority,
163} 183}
@@ -178,38 +198,40 @@ impl Default for Config {
178 } 198 }
179} 199}
180 200
181/// Initialize embassy. 201/// Initialize the `embassy-stm32` HAL with the provided configuration.
202///
203/// This returns the peripheral singletons that can be used for creating drivers.
204///
205/// This should only be called once at startup, otherwise it panics.
182pub fn init(config: Config) -> Peripherals { 206pub fn init(config: Config) -> Peripherals {
183 critical_section::with(|cs| { 207 critical_section::with(|cs| {
184 let p = Peripherals::take_with_cs(cs); 208 let p = Peripherals::take_with_cs(cs);
185 209
186 #[cfg(dbgmcu)] 210 #[cfg(dbgmcu)]
187 if config.enable_debug_during_sleep { 211 crate::pac::DBGMCU.cr().modify(|cr| {
188 crate::pac::DBGMCU.cr().modify(|cr| { 212 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
189 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] 213 {
190 { 214 cr.set_dbg_stop(config.enable_debug_during_sleep);
191 cr.set_dbg_stop(true); 215 cr.set_dbg_standby(config.enable_debug_during_sleep);
192 cr.set_dbg_standby(true); 216 }
193 } 217 #[cfg(any(
194 #[cfg(any( 218 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
195 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, 219 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
196 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl 220 ))]
197 ))] 221 {
198 { 222 cr.set_dbg_sleep(config.enable_debug_during_sleep);
199 cr.set_dbg_sleep(true); 223 cr.set_dbg_stop(config.enable_debug_during_sleep);
200 cr.set_dbg_stop(true); 224 cr.set_dbg_standby(config.enable_debug_during_sleep);
201 cr.set_dbg_standby(true); 225 }
202 } 226 #[cfg(dbgmcu_h7)]
203 #[cfg(dbgmcu_h7)] 227 {
204 { 228 cr.set_d1dbgcken(config.enable_debug_during_sleep);
205 cr.set_d1dbgcken(true); 229 cr.set_d3dbgcken(config.enable_debug_during_sleep);
206 cr.set_d3dbgcken(true); 230 cr.set_dbgsleep_d1(config.enable_debug_during_sleep);
207 cr.set_dbgsleep_d1(true); 231 cr.set_dbgstby_d1(config.enable_debug_during_sleep);
208 cr.set_dbgstby_d1(true); 232 cr.set_dbgstop_d1(config.enable_debug_during_sleep);
209 cr.set_dbgstop_d1(true); 233 }
210 } 234 });
211 });
212 }
213 235
214 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] 236 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
215 peripherals::SYSCFG::enable_and_reset_with_cs(cs); 237 peripherals::SYSCFG::enable_and_reset_with_cs(cs);
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 20d8f9045..4fab8dae4 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -1,50 +1,54 @@
1/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating 1//! Low-power support.
2/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which 2//!
3/// can use knowledge of which peripherals are currently blocked upon to transparently and safely 3//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
4/// enter such low-power modes (currently, only `STOP2`) when idle. 4//! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which
5/// 5//! can use knowledge of which peripherals are currently blocked upon to transparently and safely
6/// The executor determines which peripherals are active by their RCC state; consequently, 6//! enter such low-power modes (currently, only `STOP2`) when idle.
7/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few 7//!
8/// exceptions to this rule: 8//! The executor determines which peripherals are active by their RCC state; consequently,
9/// 9//! low-power states can only be entered if all peripherals have been `drop`'d. There are a few
10/// * `GPIO` 10//! exceptions to this rule:
11/// * `RCC` 11//!
12/// 12//! * `GPIO`
13/// Since entering and leaving low-power modes typically incurs a significant latency, the 13//! * `RCC`
14/// low-power executor will only attempt to enter when the next timer event is at least 14//!
15/// [`time_driver::MIN_STOP_PAUSE`] in the future. 15//! Since entering and leaving low-power modes typically incurs a significant latency, the
16/// 16//! low-power executor will only attempt to enter when the next timer event is at least
17/// Currently there is no macro analogous to `embassy_executor::main` for this executor; 17//! [`time_driver::MIN_STOP_PAUSE`] in the future.
18/// consequently one must define their entrypoint manually. Moveover, you must relinquish control 18//!
19/// of the `RTC` peripheral to the executor. This will typically look like 19//! Currently there is no macro analogous to `embassy_executor::main` for this executor;
20/// 20//! consequently one must define their entrypoint manually. Moveover, you must relinquish control
21/// ```rust,no_run 21//! of the `RTC` peripheral to the executor. This will typically look like
22/// use embassy_executor::Spawner; 22//!
23/// use embassy_stm32::low_power::Executor; 23//! ```rust,no_run
24/// use embassy_stm32::rtc::{Rtc, RtcConfig}; 24//! use embassy_executor::Spawner;
25/// use static_cell::make_static; 25//! use embassy_stm32::low_power::Executor;
26/// 26//! use embassy_stm32::rtc::{Rtc, RtcConfig};
27/// #[cortex_m_rt::entry] 27//! use static_cell::StaticCell;
28/// fn main() -> ! { 28//!
29/// Executor::take().run(|spawner| { 29//! #[cortex_m_rt::entry]
30/// unwrap!(spawner.spawn(async_main(spawner))); 30//! fn main() -> ! {
31/// }); 31//! Executor::take().run(|spawner| {
32/// } 32//! unwrap!(spawner.spawn(async_main(spawner)));
33/// 33//! });
34/// #[embassy_executor::task] 34//! }
35/// async fn async_main(spawner: Spawner) { 35//!
36/// // initialize the platform... 36//! #[embassy_executor::task]
37/// let mut config = embassy_stm32::Config::default(); 37//! async fn async_main(spawner: Spawner) {
38/// let p = embassy_stm32::init(config); 38//! // initialize the platform...
39/// 39//! let mut config = embassy_stm32::Config::default();
40/// // give the RTC to the executor... 40//! let p = embassy_stm32::init(config);
41/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 41//!
42/// let rtc = make_static!(rtc); 42//! // give the RTC to the executor...
43/// embassy_stm32::low_power::stop_with_rtc(rtc); 43//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
44/// 44//! static RTC: StaticCell<Rtc> = StaticCell::new();
45/// // your application here... 45//! let rtc = RTC.init(rtc);
46/// } 46//! embassy_stm32::low_power::stop_with_rtc(rtc);
47/// ``` 47//!
48//! // your application here...
49//! }
50//! ```
51
48use core::arch::asm; 52use core::arch::asm;
49use core::marker::PhantomData; 53use core::marker::PhantomData;
50use core::sync::atomic::{compiler_fence, Ordering}; 54use core::sync::atomic::{compiler_fence, Ordering};
@@ -64,6 +68,7 @@ static mut EXECUTOR: Option<Executor> = None;
64foreach_interrupt! { 68foreach_interrupt! {
65 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 69 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
66 #[interrupt] 70 #[interrupt]
71 #[allow(non_snake_case)]
67 unsafe fn $irq() { 72 unsafe fn $irq() {
68 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 73 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
69 } 74 }
@@ -75,10 +80,15 @@ pub(crate) unsafe fn on_wakeup_irq() {
75 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 80 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
76} 81}
77 82
83/// Configure STOP mode with RTC.
78pub fn stop_with_rtc(rtc: &'static Rtc) { 84pub fn stop_with_rtc(rtc: &'static Rtc) {
79 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) 85 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
80} 86}
81 87
88/// Get whether the core is ready to enter the given stop mode.
89///
90/// This will return false if some peripheral driver is in use that
91/// prevents entering the given stop mode.
82pub fn stop_ready(stop_mode: StopMode) -> bool { 92pub fn stop_ready(stop_mode: StopMode) -> bool {
83 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 93 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
84 Some(StopMode::Stop2) => true, 94 Some(StopMode::Stop2) => true,
@@ -87,10 +97,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
87 } 97 }
88} 98}
89 99
100/// Available stop modes.
90#[non_exhaustive] 101#[non_exhaustive]
91#[derive(PartialEq)] 102#[derive(PartialEq)]
92pub enum StopMode { 103pub enum StopMode {
104 /// STOP 1
93 Stop1, 105 Stop1,
106 /// STOP 2
94 Stop2, 107 Stop2,
95} 108}
96 109
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index e1eb031d1..df8a78bcc 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -1,9 +1,12 @@
1//! Operational Amplifier (OPAMP)
1#![macro_use] 2#![macro_use]
2 3
3use embassy_hal_internal::{into_ref, PeripheralRef}; 4use embassy_hal_internal::{into_ref, PeripheralRef};
4 5
5use crate::Peripheral; 6use crate::Peripheral;
6 7
8/// Gain
9#[allow(missing_docs)]
7#[derive(Clone, Copy)] 10#[derive(Clone, Copy)]
8pub enum OpAmpGain { 11pub enum OpAmpGain {
9 Mul1, 12 Mul1,
@@ -13,6 +16,8 @@ pub enum OpAmpGain {
13 Mul16, 16 Mul16,
14} 17}
15 18
19/// Speed
20#[allow(missing_docs)]
16#[derive(Clone, Copy)] 21#[derive(Clone, Copy)]
17pub enum OpAmpSpeed { 22pub enum OpAmpSpeed {
18 Normal, 23 Normal,
@@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
180 } 185 }
181} 186}
182 187
188/// Opamp instance trait.
183pub trait Instance: sealed::Instance + 'static {} 189pub trait Instance: sealed::Instance + 'static {}
184 190
185pub(crate) mod sealed { 191pub(crate) mod sealed {
@@ -198,8 +204,11 @@ pub(crate) mod sealed {
198 pub trait OutputPin<T: Instance> {} 204 pub trait OutputPin<T: Instance> {}
199} 205}
200 206
207/// Non-inverting pin trait.
201pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} 208pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
209/// Inverting pin trait.
202pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} 210pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
211/// Output pin trait.
203pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} 212pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {}
204 213
205macro_rules! impl_opamp_external_output { 214macro_rules! impl_opamp_external_output {
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index 0412d991a..ecade9b1a 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -1,3 +1,5 @@
1//! Enums used in QSPI configuration.
2
1#[allow(dead_code)] 3#[allow(dead_code)]
2#[derive(Copy, Clone)] 4#[derive(Copy, Clone)]
3pub(crate) enum QspiMode { 5pub(crate) enum QspiMode {
@@ -18,12 +20,17 @@ impl Into<u8> for QspiMode {
18 } 20 }
19} 21}
20 22
23/// QSPI lane width
21#[allow(dead_code)] 24#[allow(dead_code)]
22#[derive(Copy, Clone)] 25#[derive(Copy, Clone)]
23pub enum QspiWidth { 26pub enum QspiWidth {
27 /// None
24 NONE, 28 NONE,
29 /// Single lane
25 SING, 30 SING,
31 /// Dual lanes
26 DUAL, 32 DUAL,
33 /// Quad lanes
27 QUAD, 34 QUAD,
28} 35}
29 36
@@ -38,10 +45,13 @@ impl Into<u8> for QspiWidth {
38 } 45 }
39} 46}
40 47
48/// Flash bank selection
41#[allow(dead_code)] 49#[allow(dead_code)]
42#[derive(Copy, Clone)] 50#[derive(Copy, Clone)]
43pub enum FlashSelection { 51pub enum FlashSelection {
52 /// Bank 1
44 Flash1, 53 Flash1,
54 /// Bank 2
45 Flash2, 55 Flash2,
46} 56}
47 57
@@ -54,6 +64,8 @@ impl Into<bool> for FlashSelection {
54 } 64 }
55} 65}
56 66
67/// QSPI memory size.
68#[allow(missing_docs)]
57#[derive(Copy, Clone)] 69#[derive(Copy, Clone)]
58pub enum MemorySize { 70pub enum MemorySize {
59 _1KiB, 71 _1KiB,
@@ -113,11 +125,16 @@ impl Into<u8> for MemorySize {
113 } 125 }
114} 126}
115 127
128/// QSPI Address size
116#[derive(Copy, Clone)] 129#[derive(Copy, Clone)]
117pub enum AddressSize { 130pub enum AddressSize {
131 /// 8-bit address
118 _8Bit, 132 _8Bit,
133 /// 16-bit address
119 _16Bit, 134 _16Bit,
135 /// 24-bit address
120 _24bit, 136 _24bit,
137 /// 32-bit address
121 _32bit, 138 _32bit,
122} 139}
123 140
@@ -132,8 +149,10 @@ impl Into<u8> for AddressSize {
132 } 149 }
133} 150}
134 151
152/// Time the Chip Select line stays high.
153#[allow(missing_docs)]
135#[derive(Copy, Clone)] 154#[derive(Copy, Clone)]
136pub enum ChipSelectHightTime { 155pub enum ChipSelectHighTime {
137 _1Cycle, 156 _1Cycle,
138 _2Cycle, 157 _2Cycle,
139 _3Cycle, 158 _3Cycle,
@@ -144,21 +163,23 @@ pub enum ChipSelectHightTime {
144 _8Cycle, 163 _8Cycle,
145} 164}
146 165
147impl Into<u8> for ChipSelectHightTime { 166impl Into<u8> for ChipSelectHighTime {
148 fn into(self) -> u8 { 167 fn into(self) -> u8 {
149 match self { 168 match self {
150 ChipSelectHightTime::_1Cycle => 0, 169 ChipSelectHighTime::_1Cycle => 0,
151 ChipSelectHightTime::_2Cycle => 1, 170 ChipSelectHighTime::_2Cycle => 1,
152 ChipSelectHightTime::_3Cycle => 2, 171 ChipSelectHighTime::_3Cycle => 2,
153 ChipSelectHightTime::_4Cycle => 3, 172 ChipSelectHighTime::_4Cycle => 3,
154 ChipSelectHightTime::_5Cycle => 4, 173 ChipSelectHighTime::_5Cycle => 4,
155 ChipSelectHightTime::_6Cycle => 5, 174 ChipSelectHighTime::_6Cycle => 5,
156 ChipSelectHightTime::_7Cycle => 6, 175 ChipSelectHighTime::_7Cycle => 6,
157 ChipSelectHightTime::_8Cycle => 7, 176 ChipSelectHighTime::_8Cycle => 7,
158 } 177 }
159 } 178 }
160} 179}
161 180
181/// FIFO threshold.
182#[allow(missing_docs)]
162#[derive(Copy, Clone)] 183#[derive(Copy, Clone)]
163pub enum FIFOThresholdLevel { 184pub enum FIFOThresholdLevel {
164 _1Bytes, 185 _1Bytes,
@@ -234,6 +255,8 @@ impl Into<u8> for FIFOThresholdLevel {
234 } 255 }
235} 256}
236 257
258/// Dummy cycle count
259#[allow(missing_docs)]
237#[derive(Copy, Clone)] 260#[derive(Copy, Clone)]
238pub enum DummyCycles { 261pub enum DummyCycles {
239 _0, 262 _0,
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 4b0e8ecef..8a709a89e 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -1,3 +1,5 @@
1//! Quad Serial Peripheral Interface (QSPI)
2
1#![macro_use] 3#![macro_use]
2 4
3pub mod enums; 5pub mod enums;
@@ -12,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs;
12use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
13use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peripheral};
14 16
17/// QSPI transfer configuration.
15pub struct TransferConfig { 18pub struct TransferConfig {
16 /// Instraction width (IMODE) 19 /// Instraction width (IMODE)
17 pub iwidth: QspiWidth, 20 pub iwidth: QspiWidth,
@@ -43,6 +46,7 @@ impl Default for TransferConfig {
43 } 46 }
44} 47}
45 48
49/// QSPI driver configuration.
46pub struct Config { 50pub struct Config {
47 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. 51 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
48 /// If you need other value the whose predefined use `Other` variant. 52 /// If you need other value the whose predefined use `Other` variant.
@@ -54,7 +58,7 @@ pub struct Config {
54 /// Number of bytes to trigger FIFO threshold flag. 58 /// Number of bytes to trigger FIFO threshold flag.
55 pub fifo_threshold: FIFOThresholdLevel, 59 pub fifo_threshold: FIFOThresholdLevel,
56 /// Minimum number of cycles that chip select must be high between issued commands 60 /// Minimum number of cycles that chip select must be high between issued commands
57 pub cs_high_time: ChipSelectHightTime, 61 pub cs_high_time: ChipSelectHighTime,
58} 62}
59 63
60impl Default for Config { 64impl Default for Config {
@@ -64,11 +68,12 @@ impl Default for Config {
64 address_size: AddressSize::_24bit, 68 address_size: AddressSize::_24bit,
65 prescaler: 128, 69 prescaler: 128,
66 fifo_threshold: FIFOThresholdLevel::_17Bytes, 70 fifo_threshold: FIFOThresholdLevel::_17Bytes,
67 cs_high_time: ChipSelectHightTime::_5Cycle, 71 cs_high_time: ChipSelectHighTime::_5Cycle,
68 } 72 }
69 } 73 }
70} 74}
71 75
76/// QSPI driver.
72#[allow(dead_code)] 77#[allow(dead_code)]
73pub struct Qspi<'d, T: Instance, Dma> { 78pub struct Qspi<'d, T: Instance, Dma> {
74 _peri: PeripheralRef<'d, T>, 79 _peri: PeripheralRef<'d, T>,
@@ -83,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> {
83} 88}
84 89
85impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { 90impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
91 /// Create a new QSPI driver for bank 1.
86 pub fn new_bk1( 92 pub fn new_bk1(
87 peri: impl Peripheral<P = T> + 'd, 93 peri: impl Peripheral<P = T> + 'd,
88 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, 94 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
@@ -119,10 +125,11 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
119 Some(nss.map_into()), 125 Some(nss.map_into()),
120 dma, 126 dma,
121 config, 127 config,
122 FlashSelection::Flash2, 128 FlashSelection::Flash1,
123 ) 129 )
124 } 130 }
125 131
132 /// Create a new QSPI driver for bank 2.
126 pub fn new_bk2( 133 pub fn new_bk2(
127 peri: impl Peripheral<P = T> + 'd, 134 peri: impl Peripheral<P = T> + 'd,
128 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, 135 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
@@ -221,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
221 } 228 }
222 } 229 }
223 230
231 /// Do a QSPI command.
224 pub fn command(&mut self, transaction: TransferConfig) { 232 pub fn command(&mut self, transaction: TransferConfig) {
225 #[cfg(not(stm32h7))] 233 #[cfg(not(stm32h7))]
226 T::REGS.cr().modify(|v| v.set_dmaen(false)); 234 T::REGS.cr().modify(|v| v.set_dmaen(false));
@@ -230,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
230 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 238 T::REGS.fcr().modify(|v| v.set_ctcf(true));
231 } 239 }
232 240
241 /// Blocking read data.
233 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { 242 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
234 #[cfg(not(stm32h7))] 243 #[cfg(not(stm32h7))]
235 T::REGS.cr().modify(|v| v.set_dmaen(false)); 244 T::REGS.cr().modify(|v| v.set_dmaen(false));
@@ -254,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
254 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 263 T::REGS.fcr().modify(|v| v.set_ctcf(true));
255 } 264 }
256 265
266 /// Blocking write data.
257 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { 267 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
258 // STM32H7 does not have dmaen 268 // STM32H7 does not have dmaen
259 #[cfg(not(stm32h7))] 269 #[cfg(not(stm32h7))]
@@ -276,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
276 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 286 T::REGS.fcr().modify(|v| v.set_ctcf(true));
277 } 287 }
278 288
289 /// Blocking read data, using DMA.
279 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) 290 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
280 where 291 where
281 Dma: QuadDma<T>, 292 Dma: QuadDma<T>,
@@ -308,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
308 transfer.blocking_wait(); 319 transfer.blocking_wait();
309 } 320 }
310 321
322 /// Blocking write data, using DMA.
311 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) 323 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
312 where 324 where
313 Dma: QuadDma<T>, 325 Dma: QuadDma<T>,
@@ -377,6 +389,7 @@ pub(crate) mod sealed {
377 } 389 }
378} 390}
379 391
392/// QSPI instance trait.
380pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 393pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
381 394
382pin_trait!(SckPin, Instance); 395pin_trait!(SckPin, Instance);
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 1889eb280..15b51a398 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -70,7 +70,9 @@ pub struct Pll {
70 pub mul: PllMul, 70 pub mul: PllMul,
71 71
72 /// PLL P division factor. If None, PLL P output is disabled. 72 /// PLL P division factor. If None, PLL P output is disabled.
73 /// On PLL1, it must be even (in particular, it cannot be 1.) 73 /// On PLL1, it must be even for most series (in particular,
74 /// it cannot be 1 in series other than STM32H723/733,
75 /// STM32H725/735 and STM32H730.)
74 pub divp: Option<PllDiv>, 76 pub divp: Option<PllDiv>,
75 /// PLL Q division factor. If None, PLL Q output is disabled. 77 /// PLL Q division factor. If None, PLL Q output is disabled.
76 pub divq: Option<PllDiv>, 78 pub divq: Option<PllDiv>,
@@ -476,7 +478,14 @@ pub(crate) unsafe fn init(config: Config) {
476 VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)), 478 VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)),
477 VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)), 479 VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)),
478 }; 480 };
479 #[cfg(all(stm32h7, not(pwr_h7rm0455)))] 481 #[cfg(pwr_h7rm0468)]
482 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
483 VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)),
484 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
485 VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
486 VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)),
487 };
488 #[cfg(all(stm32h7, not(any(pwr_h7rm0455, pwr_h7rm0468))))]
480 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { 489 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
481 VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), 490 VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
482 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), 491 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
@@ -729,9 +738,12 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
729 738
730 let p = config.divp.map(|div| { 739 let p = config.divp.map(|div| {
731 if num == 0 { 740 if num == 0 {
732 // on PLL1, DIVP must be even. 741 // on PLL1, DIVP must be even for most series.
733 // The enum value is 1 less than the divider, so check it's odd. 742 // The enum value is 1 less than the divider, so check it's odd.
743 #[cfg(not(pwr_h7rm0468))]
734 assert!(div.to_bits() % 2 == 1); 744 assert!(div.to_bits() % 2 == 1);
745 #[cfg(pwr_h7rm0468)]
746 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
735 } 747 }
736 748
737 vco_clk / div 749 vco_clk / div
@@ -820,7 +832,7 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
820 _ => unreachable!(), 832 _ => unreachable!(),
821 }; 833 };
822 834
823 #[cfg(flash_h7)] 835 #[cfg(all(flash_h7, not(pwr_h7rm0468)))]
824 let (latency, wrhighfreq) = match (vos, clk.0) { 836 let (latency, wrhighfreq) = match (vos, clk.0) {
825 // VOS 0 range VCORE 1.26V - 1.40V 837 // VOS 0 range VCORE 1.26V - 1.40V
826 (VoltageScale::Scale0, ..=70_000_000) => (0, 0), 838 (VoltageScale::Scale0, ..=70_000_000) => (0, 0),
@@ -849,6 +861,30 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
849 _ => unreachable!(), 861 _ => unreachable!(),
850 }; 862 };
851 863
864 // See RM0468 Rev 3 Table 16. FLASH recommended number of wait
865 // states and programming delay
866 #[cfg(all(flash_h7, pwr_h7rm0468))]
867 let (latency, wrhighfreq) = match (vos, clk.0) {
868 // VOS 0 range VCORE 1.26V - 1.40V
869 (VoltageScale::Scale0, ..=70_000_000) => (0, 0),
870 (VoltageScale::Scale0, ..=140_000_000) => (1, 1),
871 (VoltageScale::Scale0, ..=210_000_000) => (2, 2),
872 (VoltageScale::Scale0, ..=275_000_000) => (3, 3),
873 // VOS 1 range VCORE 1.15V - 1.26V
874 (VoltageScale::Scale1, ..=67_000_000) => (0, 0),
875 (VoltageScale::Scale1, ..=133_000_000) => (1, 1),
876 (VoltageScale::Scale1, ..=200_000_000) => (2, 2),
877 // VOS 2 range VCORE 1.05V - 1.15V
878 (VoltageScale::Scale2, ..=50_000_000) => (0, 0),
879 (VoltageScale::Scale2, ..=100_000_000) => (1, 1),
880 (VoltageScale::Scale2, ..=150_000_000) => (2, 2),
881 // VOS 3 range VCORE 0.95V - 1.05V
882 (VoltageScale::Scale3, ..=35_000_000) => (0, 0),
883 (VoltageScale::Scale3, ..=70_000_000) => (1, 1),
884 (VoltageScale::Scale3, ..=85_000_000) => (2, 2),
885 _ => unreachable!(),
886 };
887
852 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait 888 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait
853 // states and programming delay 889 // states and programming delay
854 #[cfg(flash_h7ab)] 890 #[cfg(flash_h7ab)]
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index dc829a9ad..04a51110c 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -1,4 +1,7 @@
1//! Reset and Clock Control (RCC)
2
1#![macro_use] 3#![macro_use]
4#![allow(missing_docs)] // TODO
2 5
3use core::mem::MaybeUninit; 6use core::mem::MaybeUninit;
4 7
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 5e6922e9b..ca641f352 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -1,3 +1,4 @@
1//! Random Number Generator (RNG)
1#![macro_use] 2#![macro_use]
2 3
3use core::future::poll_fn; 4use core::future::poll_fn;
@@ -13,13 +14,19 @@ use crate::{interrupt, pac, peripherals, Peripheral};
13 14
14static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 15static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15 16
17/// RNG error
16#[derive(Debug, PartialEq, Eq)] 18#[derive(Debug, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))] 19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Error { 20pub enum Error {
21 /// Seed error.
19 SeedError, 22 SeedError,
23 /// Clock error. Double-check the RCC configuration,
24 /// see the Reference Manual for details on restrictions
25 /// on RNG clocks.
20 ClockError, 26 ClockError,
21} 27}
22 28
29/// RNG interrupt handler.
23pub struct InterruptHandler<T: Instance> { 30pub struct InterruptHandler<T: Instance> {
24 _phantom: PhantomData<T>, 31 _phantom: PhantomData<T>,
25} 32}
@@ -34,11 +41,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
34 } 41 }
35} 42}
36 43
44/// RNG driver.
37pub struct Rng<'d, T: Instance> { 45pub struct Rng<'d, T: Instance> {
38 _inner: PeripheralRef<'d, T>, 46 _inner: PeripheralRef<'d, T>,
39} 47}
40 48
41impl<'d, T: Instance> Rng<'d, T> { 49impl<'d, T: Instance> Rng<'d, T> {
50 /// Create a new RNG driver.
42 pub fn new( 51 pub fn new(
43 inner: impl Peripheral<P = T> + 'd, 52 inner: impl Peripheral<P = T> + 'd,
44 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 53 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -54,6 +63,7 @@ impl<'d, T: Instance> Rng<'d, T> {
54 random 63 random
55 } 64 }
56 65
66 /// Reset the RNG.
57 #[cfg(rng_v1)] 67 #[cfg(rng_v1)]
58 pub fn reset(&mut self) { 68 pub fn reset(&mut self) {
59 T::regs().cr().write(|reg| { 69 T::regs().cr().write(|reg| {
@@ -70,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> {
70 let _ = self.next_u32(); 80 let _ = self.next_u32();
71 } 81 }
72 82
83 /// Reset the RNG.
73 #[cfg(not(rng_v1))] 84 #[cfg(not(rng_v1))]
74 pub fn reset(&mut self) { 85 pub fn reset(&mut self) {
75 T::regs().cr().write(|reg| { 86 T::regs().cr().write(|reg| {
@@ -106,7 +117,8 @@ impl<'d, T: Instance> Rng<'d, T> {
106 while T::regs().cr().read().condrst() {} 117 while T::regs().cr().read().condrst() {}
107 } 118 }
108 119
109 pub fn recover_seed_error(&mut self) -> () { 120 /// Try to recover from a seed error.
121 pub fn recover_seed_error(&mut self) {
110 self.reset(); 122 self.reset();
111 // reset should also clear the SEIS flag 123 // reset should also clear the SEIS flag
112 if T::regs().sr().read().seis() { 124 if T::regs().sr().read().seis() {
@@ -117,6 +129,7 @@ impl<'d, T: Instance> Rng<'d, T> {
117 while T::regs().sr().read().secs() {} 129 while T::regs().sr().read().secs() {}
118 } 130 }
119 131
132 /// Fill the given slice with random values.
120 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { 133 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
121 for chunk in dest.chunks_mut(4) { 134 for chunk in dest.chunks_mut(4) {
122 let mut bits = T::regs().sr().read(); 135 let mut bits = T::regs().sr().read();
@@ -217,7 +230,9 @@ pub(crate) mod sealed {
217 } 230 }
218} 231}
219 232
233/// RNG instance trait.
220pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 234pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send {
235 /// Interrupt for this RNG instance.
221 type Interrupt: interrupt::typelevel::Interrupt; 236 type Interrupt: interrupt::typelevel::Interrupt;
222} 237}
223 238
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index f4e86dd87..ef92fa4bb 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -104,45 +104,51 @@ pub struct DateTime {
104} 104}
105 105
106impl DateTime { 106impl DateTime {
107 /// Get the year (0..=4095)
107 pub const fn year(&self) -> u16 { 108 pub const fn year(&self) -> u16 {
108 self.year 109 self.year
109 } 110 }
110 111
112 /// Get the month (1..=12, 1 is January)
111 pub const fn month(&self) -> u8 { 113 pub const fn month(&self) -> u8 {
112 self.month 114 self.month
113 } 115 }
114 116
117 /// Get the day (1..=31)
115 pub const fn day(&self) -> u8 { 118 pub const fn day(&self) -> u8 {
116 self.day 119 self.day
117 } 120 }
118 121
122 /// Get the day of week
119 pub const fn day_of_week(&self) -> DayOfWeek { 123 pub const fn day_of_week(&self) -> DayOfWeek {
120 self.day_of_week 124 self.day_of_week
121 } 125 }
122 126
127 /// Get the hour (0..=23)
123 pub const fn hour(&self) -> u8 { 128 pub const fn hour(&self) -> u8 {
124 self.hour 129 self.hour
125 } 130 }
126 131
132 /// Get the minute (0..=59)
127 pub const fn minute(&self) -> u8 { 133 pub const fn minute(&self) -> u8 {
128 self.minute 134 self.minute
129 } 135 }
130 136
137 /// Get the second (0..=59)
131 pub const fn second(&self) -> u8 { 138 pub const fn second(&self) -> u8 {
132 self.second 139 self.second
133 } 140 }
134 141
142 /// Create a new DateTime with the given information.
135 pub fn from( 143 pub fn from(
136 year: u16, 144 year: u16,
137 month: u8, 145 month: u8,
138 day: u8, 146 day: u8,
139 day_of_week: u8, 147 day_of_week: DayOfWeek,
140 hour: u8, 148 hour: u8,
141 minute: u8, 149 minute: u8,
142 second: u8, 150 second: u8,
143 ) -> Result<Self, Error> { 151 ) -> Result<Self, Error> {
144 let day_of_week = day_of_week_from_u8(day_of_week)?;
145
146 if year > 4095 { 152 if year > 4095 {
147 Err(Error::InvalidYear) 153 Err(Error::InvalidYear)
148 } else if month < 1 || month > 12 { 154 } else if month < 1 || month > 12 {
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index b4315f535..1ffb567b3 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -1,4 +1,4 @@
1//! RTC peripheral abstraction 1//! Real Time Clock (RTC)
2mod datetime; 2mod datetime;
3 3
4#[cfg(feature = "low-power")] 4#[cfg(feature = "low-power")]
@@ -9,9 +9,9 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9#[cfg(feature = "low-power")] 9#[cfg(feature = "low-power")]
10use embassy_sync::blocking_mutex::Mutex; 10use embassy_sync::blocking_mutex::Mutex;
11 11
12use self::datetime::day_of_week_to_u8;
13#[cfg(not(rtc_v2f2))] 12#[cfg(not(rtc_v2f2))]
14use self::datetime::RtcInstant; 13use self::datetime::RtcInstant;
14use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
15pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 15pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
16use crate::pac::rtc::regs::{Dr, Tr}; 16use crate::pac::rtc::regs::{Dr, Tr};
17use crate::time::Hertz; 17use crate::time::Hertz;
@@ -24,7 +24,7 @@ use crate::time::Hertz;
24 ), 24 ),
25 path = "v2.rs" 25 path = "v2.rs"
26)] 26)]
27#[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")] 27#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")]
28mod _version; 28mod _version;
29#[allow(unused_imports)] 29#[allow(unused_imports)]
30pub use _version::*; 30pub use _version::*;
@@ -43,7 +43,7 @@ pub(crate) enum WakeupPrescaler {
43 Div16 = 16, 43 Div16 = 16,
44} 44}
45 45
46#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] 46#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
47impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 47impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
48 fn from(val: WakeupPrescaler) -> Self { 48 fn from(val: WakeupPrescaler) -> Self {
49 use crate::pac::rtc::vals::Wucksel; 49 use crate::pac::rtc::vals::Wucksel;
@@ -57,7 +57,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
57 } 57 }
58} 58}
59 59
60#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] 60#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
61impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 61impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
62 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 62 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
63 use crate::pac::rtc::vals::Wucksel; 63 use crate::pac::rtc::vals::Wucksel;
@@ -102,6 +102,7 @@ pub enum RtcError {
102 NotRunning, 102 NotRunning,
103} 103}
104 104
105/// Provides immutable access to the current time of the RTC.
105pub struct RtcTimeProvider { 106pub struct RtcTimeProvider {
106 _private: (), 107 _private: (),
107} 108}
@@ -127,10 +128,10 @@ impl RtcTimeProvider {
127 let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); 128 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
128 let hour = bcd2_to_byte((tr.ht(), tr.hu())); 129 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
129 130
130 let weekday = dr.wdu(); 131 let weekday = day_of_week_from_u8(dr.wdu()).map_err(RtcError::InvalidDateTime)?;
131 let day = bcd2_to_byte((dr.dt(), dr.du())); 132 let day = bcd2_to_byte((dr.dt(), dr.du()));
132 let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); 133 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
133 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; 134 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16;
134 135
135 DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) 136 DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
136 }) 137 })
@@ -163,7 +164,7 @@ impl RtcTimeProvider {
163 } 164 }
164} 165}
165 166
166/// RTC Abstraction 167/// RTC driver.
167pub struct Rtc { 168pub struct Rtc {
168 #[cfg(feature = "low-power")] 169 #[cfg(feature = "low-power")]
169 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, 170 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
@@ -171,6 +172,7 @@ pub struct Rtc {
171 _private: (), 172 _private: (),
172} 173}
173 174
175/// RTC configuration.
174#[non_exhaustive] 176#[non_exhaustive]
175#[derive(Copy, Clone, PartialEq)] 177#[derive(Copy, Clone, PartialEq)]
176pub struct RtcConfig { 178pub struct RtcConfig {
@@ -188,6 +190,7 @@ impl Default for RtcConfig {
188 } 190 }
189} 191}
190 192
193/// Calibration cycle period.
191#[derive(Copy, Clone, Debug, PartialEq)] 194#[derive(Copy, Clone, Debug, PartialEq)]
192#[repr(u8)] 195#[repr(u8)]
193pub enum RtcCalibrationCyclePeriod { 196pub enum RtcCalibrationCyclePeriod {
@@ -206,6 +209,7 @@ impl Default for RtcCalibrationCyclePeriod {
206} 209}
207 210
208impl Rtc { 211impl Rtc {
212 /// Create a new RTC instance.
209 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { 213 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
210 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 214 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
211 <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset(); 215 <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset();
@@ -258,7 +262,7 @@ impl Rtc {
258 let (dt, du) = byte_to_bcd2(t.day() as u8); 262 let (dt, du) = byte_to_bcd2(t.day() as u8);
259 let (mt, mu) = byte_to_bcd2(t.month() as u8); 263 let (mt, mu) = byte_to_bcd2(t.month() as u8);
260 let yr = t.year() as u16; 264 let yr = t.year() as u16;
261 let yr_offset = (yr - 1970_u16) as u8; 265 let yr_offset = (yr - 2000_u16) as u8;
262 let (yt, yu) = byte_to_bcd2(yr_offset); 266 let (yt, yu) = byte_to_bcd2(yr_offset);
263 267
264 use crate::pac::rtc::vals::Ampm; 268 use crate::pac::rtc::vals::Ampm;
@@ -315,6 +319,7 @@ impl Rtc {
315 }) 319 })
316 } 320 }
317 321
322 /// Number of backup registers of this instance.
318 pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; 323 pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT;
319 324
320 /// Read content of the backup register. 325 /// Read content of the backup register.
@@ -343,7 +348,7 @@ impl Rtc {
343 ) { 348 ) {
344 use embassy_time::{Duration, TICK_HZ}; 349 use embassy_time::{Duration, TICK_HZ};
345 350
346 #[cfg(any(rtc_v3, rtc_v3u5))] 351 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
347 use crate::pac::rtc::vals::Calrf; 352 use crate::pac::rtc::vals::Calrf;
348 353
349 // Panic if the rcc mod knows we're not using low-power rtc 354 // Panic if the rcc mod knows we're not using low-power rtc
@@ -370,7 +375,7 @@ impl Rtc {
370 while !regs.isr().read().wutwf() {} 375 while !regs.isr().read().wutwf() {}
371 } 376 }
372 377
373 #[cfg(any(rtc_v3, rtc_v3u5))] 378 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
374 { 379 {
375 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 380 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
376 while !regs.icsr().read().wutwf() {} 381 while !regs.icsr().read().wutwf() {}
@@ -399,7 +404,7 @@ impl Rtc {
399 /// was called, otherwise none 404 /// was called, otherwise none
400 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 405 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
401 use crate::interrupt::typelevel::Interrupt; 406 use crate::interrupt::typelevel::Interrupt;
402 #[cfg(any(rtc_v3, rtc_v3u5))] 407 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
403 use crate::pac::rtc::vals::Calrf; 408 use crate::pac::rtc::vals::Calrf;
404 409
405 let instant = self.instant().unwrap(); 410 let instant = self.instant().unwrap();
@@ -415,13 +420,19 @@ impl Rtc {
415 ))] 420 ))]
416 regs.isr().modify(|w| w.set_wutf(false)); 421 regs.isr().modify(|w| w.set_wutf(false));
417 422
418 #[cfg(any(rtc_v3, rtc_v3u5))] 423 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
419 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 424 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
420 425
426 #[cfg(not(stm32l5))]
421 crate::pac::EXTI 427 crate::pac::EXTI
422 .pr(0) 428 .pr(0)
423 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 429 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
424 430
431 #[cfg(stm32l5)]
432 crate::pac::EXTI
433 .fpr(0)
434 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
435
425 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); 436 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
426 }); 437 });
427 } 438 }
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 91f08fae4..1eda097a7 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -1,4 +1,4 @@
1use stm32_metapac::rtc::vals::{Init, Osel, Pol}; 1use stm32_metapac::rtc::vals::{Osel, Pol};
2 2
3use super::sealed; 3use super::sealed;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
@@ -49,7 +49,7 @@ impl super::Rtc {
49 clock_drift = RTC_CALR_MAX_PPM; 49 clock_drift = RTC_CALR_MAX_PPM;
50 } 50 }
51 51
52 clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; 52 clock_drift /= RTC_CALR_RESOLUTION_PPM;
53 53
54 self.write(false, |rtc| { 54 self.write(false, |rtc| {
55 rtc.calr().write(|w| { 55 rtc.calr().write(|w| {
@@ -107,7 +107,7 @@ impl super::Rtc {
107 // true if initf bit indicates RTC peripheral is in init mode 107 // true if initf bit indicates RTC peripheral is in init mode
108 if init_mode && !r.isr().read().initf() { 108 if init_mode && !r.isr().read().initf() {
109 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode 109 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
110 r.isr().modify(|w| w.set_init(Init::INITMODE)); 110 r.isr().modify(|w| w.set_init(true));
111 // wait till init state entered 111 // wait till init state entered
112 // ~2 RTCCLK cycles 112 // ~2 RTCCLK cycles
113 while !r.isr().read().initf() {} 113 while !r.isr().read().initf() {}
@@ -116,7 +116,7 @@ impl super::Rtc {
116 let result = f(&r); 116 let result = f(&r);
117 117
118 if init_mode { 118 if init_mode {
119 r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode 119 r.isr().modify(|w| w.set_init(false)); // Exits init mode
120 } 120 }
121 121
122 // Re-enable write protection. 122 // Re-enable write protection.
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index d2d0d9309..114141b64 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -1,4 +1,4 @@
1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; 1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType};
2 2
3use super::{sealed, RtcCalibrationCyclePeriod}; 3use super::{sealed, RtcCalibrationCyclePeriod};
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
@@ -26,7 +26,7 @@ impl super::Rtc {
26 rtc.cr().modify(|w| { 26 rtc.cr().modify(|w| {
27 w.set_out2en(false); 27 w.set_out2en(false);
28 w.set_tampalrm_type(TampalrmType::PUSHPULL); 28 w.set_tampalrm_type(TampalrmType::PUSHPULL);
29 w.set_tampalrm_pu(TampalrmPu::NOPULLUP); 29 w.set_tampalrm_pu(false);
30 }); 30 });
31 }); 31 });
32 } 32 }
@@ -106,7 +106,7 @@ impl super::Rtc {
106 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); 106 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
107 107
108 if init_mode && !r.icsr().read().initf() { 108 if init_mode && !r.icsr().read().initf() {
109 r.icsr().modify(|w| w.set_init(Init::INITMODE)); 109 r.icsr().modify(|w| w.set_init(true));
110 // wait till init state entered 110 // wait till init state entered
111 // ~2 RTCCLK cycles 111 // ~2 RTCCLK cycles
112 while !r.icsr().read().initf() {} 112 while !r.icsr().read().initf() {}
@@ -115,7 +115,7 @@ impl super::Rtc {
115 let result = f(&r); 115 let result = f(&r);
116 116
117 if init_mode { 117 if init_mode {
118 r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode 118 r.icsr().modify(|w| w.set_init(false)); // Exits init mode
119 } 119 }
120 120
121 // Re-enable write protection. 121 // Re-enable write protection.
@@ -135,6 +135,12 @@ impl sealed::Instance for crate::peripherals::RTC {
135 #[cfg(all(feature = "low-power", stm32g4))] 135 #[cfg(all(feature = "low-power", stm32g4))]
136 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 136 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
137 137
138 #[cfg(all(feature = "low-power", stm32l5))]
139 const EXTI_WAKEUP_LINE: usize = 17;
140
141 #[cfg(all(feature = "low-power", stm32l5))]
142 type WakeupInterrupt = crate::interrupt::typelevel::RTC;
143
138 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> { 144 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
139 #[allow(clippy::if_same_then_else)] 145 #[allow(clippy::if_same_then_else)]
140 if register < Self::BACKUP_REGISTER_COUNT { 146 if register < Self::BACKUP_REGISTER_COUNT {
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index a16d38af1..ef8802184 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -1,8 +1,11 @@
1//! Serial Audio Interface (SAI)
1#![macro_use] 2#![macro_use]
2 3
3use embassy_embedded_hal::SetConfig; 4use core::marker::PhantomData;
5
4use embassy_hal_internal::{into_ref, PeripheralRef}; 6use embassy_hal_internal::{into_ref, PeripheralRef};
5 7
8use self::sealed::WhichSubBlock;
6pub use crate::dma::word; 9pub use crate::dma::word;
7use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 10use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
8use crate::gpio::sealed::{AFType, Pin as _}; 11use crate::gpio::sealed::{AFType, Pin as _};
@@ -11,48 +14,32 @@ use crate::pac::sai::{vals, Sai as Regs};
11use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
12use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peripheral};
13 16
17/// SAI error
14#[derive(Debug, PartialEq, Eq)] 18#[derive(Debug, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))] 19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum Error { 20pub enum Error {
21 /// `write` called on a SAI in receive mode.
17 NotATransmitter, 22 NotATransmitter,
23 /// `read` called on a SAI in transmit mode.
18 NotAReceiver, 24 NotAReceiver,
19 OverrunError, 25 /// Overrun
26 Overrun,
20} 27}
21 28
22impl From<ringbuffer::OverrunError> for Error { 29impl From<ringbuffer::OverrunError> for Error {
23 fn from(_: ringbuffer::OverrunError) -> Self { 30 fn from(_: ringbuffer::OverrunError) -> Self {
24 Self::OverrunError 31 Self::Overrun
25 } 32 }
26} 33}
27 34
35/// Master/slave mode.
28#[derive(Copy, Clone)] 36#[derive(Copy, Clone)]
29pub enum SyncBlock { 37#[allow(missing_docs)]
30 None,
31 Sai1BlockA,
32 Sai1BlockB,
33 Sai2BlockA,
34 Sai2BlockB,
35}
36
37#[derive(Copy, Clone)]
38pub enum SyncIn {
39 None,
40 ChannelZero,
41 ChannelOne,
42}
43
44#[derive(Copy, Clone)]
45pub enum Mode { 38pub enum Mode {
46 Master, 39 Master,
47 Slave, 40 Slave,
48} 41}
49 42
50#[derive(Copy, Clone)]
51pub enum TxRx {
52 Transmitter,
53 Receiver,
54}
55
56impl Mode { 43impl Mode {
57 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 44 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
58 const fn mode(&self, tx_rx: TxRx) -> vals::Mode { 45 const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
@@ -69,7 +56,17 @@ impl Mode {
69 } 56 }
70} 57}
71 58
59/// Direction: transmit or receive
72#[derive(Copy, Clone)] 60#[derive(Copy, Clone)]
61#[allow(missing_docs)]
62pub enum TxRx {
63 Transmitter,
64 Receiver,
65}
66
67/// Data slot size.
68#[derive(Copy, Clone)]
69#[allow(missing_docs)]
73pub enum SlotSize { 70pub enum SlotSize {
74 DataSize, 71 DataSize,
75 /// 16 bit data length on 16 bit wide channel 72 /// 16 bit data length on 16 bit wide channel
@@ -80,7 +77,7 @@ pub enum SlotSize {
80 77
81impl SlotSize { 78impl SlotSize {
82 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 79 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
83 pub const fn slotsz(&self) -> vals::Slotsz { 80 const fn slotsz(&self) -> vals::Slotsz {
84 match self { 81 match self {
85 SlotSize::DataSize => vals::Slotsz::DATASIZE, 82 SlotSize::DataSize => vals::Slotsz::DATASIZE,
86 SlotSize::Channel16 => vals::Slotsz::BIT16, 83 SlotSize::Channel16 => vals::Slotsz::BIT16,
@@ -89,7 +86,9 @@ impl SlotSize {
89 } 86 }
90} 87}
91 88
89/// Data size.
92#[derive(Copy, Clone)] 90#[derive(Copy, Clone)]
91#[allow(missing_docs)]
93pub enum DataSize { 92pub enum DataSize {
94 Data8, 93 Data8,
95 Data10, 94 Data10,
@@ -101,7 +100,7 @@ pub enum DataSize {
101 100
102impl DataSize { 101impl DataSize {
103 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 102 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
104 pub const fn ds(&self) -> vals::Ds { 103 const fn ds(&self) -> vals::Ds {
105 match self { 104 match self {
106 DataSize::Data8 => vals::Ds::BIT8, 105 DataSize::Data8 => vals::Ds::BIT8,
107 DataSize::Data10 => vals::Ds::BIT10, 106 DataSize::Data10 => vals::Ds::BIT10,
@@ -113,7 +112,9 @@ impl DataSize {
113 } 112 }
114} 113}
115 114
115/// FIFO threshold level.
116#[derive(Copy, Clone)] 116#[derive(Copy, Clone)]
117#[allow(missing_docs)]
117pub enum FifoThreshold { 118pub enum FifoThreshold {
118 Empty, 119 Empty,
119 Quarter, 120 Quarter,
@@ -124,7 +125,7 @@ pub enum FifoThreshold {
124 125
125impl FifoThreshold { 126impl FifoThreshold {
126 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 127 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
127 pub const fn fth(&self) -> vals::Fth { 128 const fn fth(&self) -> vals::Fth {
128 match self { 129 match self {
129 FifoThreshold::Empty => vals::Fth::EMPTY, 130 FifoThreshold::Empty => vals::Fth::EMPTY,
130 FifoThreshold::Quarter => vals::Fth::QUARTER1, 131 FifoThreshold::Quarter => vals::Fth::QUARTER1,
@@ -135,38 +136,9 @@ impl FifoThreshold {
135 } 136 }
136} 137}
137 138
139/// Output value on mute.
138#[derive(Copy, Clone)] 140#[derive(Copy, Clone)]
139pub enum FifoLevel { 141#[allow(missing_docs)]
140 Empty,
141 FirstQuarter,
142 SecondQuarter,
143 ThirdQuarter,
144 FourthQuarter,
145 Full,
146}
147
148#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
149impl From<vals::Flvl> for FifoLevel {
150 fn from(flvl: vals::Flvl) -> Self {
151 match flvl {
152 vals::Flvl::EMPTY => FifoLevel::Empty,
153 vals::Flvl::QUARTER1 => FifoLevel::FirstQuarter,
154 vals::Flvl::QUARTER2 => FifoLevel::SecondQuarter,
155 vals::Flvl::QUARTER3 => FifoLevel::ThirdQuarter,
156 vals::Flvl::QUARTER4 => FifoLevel::FourthQuarter,
157 vals::Flvl::FULL => FifoLevel::Full,
158 _ => FifoLevel::Empty,
159 }
160 }
161}
162
163#[derive(Copy, Clone)]
164pub enum MuteDetection {
165 NoMute,
166 Mute,
167}
168
169#[derive(Copy, Clone)]
170pub enum MuteValue { 142pub enum MuteValue {
171 Zero, 143 Zero,
172 LastValue, 144 LastValue,
@@ -174,7 +146,7 @@ pub enum MuteValue {
174 146
175impl MuteValue { 147impl MuteValue {
176 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 148 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
177 pub const fn muteval(&self) -> vals::Muteval { 149 const fn muteval(&self) -> vals::Muteval {
178 match self { 150 match self {
179 MuteValue::Zero => vals::Muteval::SENDZERO, 151 MuteValue::Zero => vals::Muteval::SENDZERO,
180 MuteValue::LastValue => vals::Muteval::SENDLAST, 152 MuteValue::LastValue => vals::Muteval::SENDLAST,
@@ -182,13 +154,9 @@ impl MuteValue {
182 } 154 }
183} 155}
184 156
157/// Protocol variant to use.
185#[derive(Copy, Clone)] 158#[derive(Copy, Clone)]
186pub enum OverUnderStatus { 159#[allow(missing_docs)]
187 NoError,
188 OverUnderRunDetected,
189}
190
191#[derive(Copy, Clone)]
192pub enum Protocol { 160pub enum Protocol {
193 Free, 161 Free,
194 Spdif, 162 Spdif,
@@ -197,7 +165,7 @@ pub enum Protocol {
197 165
198impl Protocol { 166impl Protocol {
199 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 167 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
200 pub const fn prtcfg(&self) -> vals::Prtcfg { 168 const fn prtcfg(&self) -> vals::Prtcfg {
201 match self { 169 match self {
202 Protocol::Free => vals::Prtcfg::FREE, 170 Protocol::Free => vals::Prtcfg::FREE,
203 Protocol::Spdif => vals::Prtcfg::SPDIF, 171 Protocol::Spdif => vals::Prtcfg::SPDIF,
@@ -206,7 +174,9 @@ impl Protocol {
206 } 174 }
207} 175}
208 176
177/// Sync input between SAI units/blocks.
209#[derive(Copy, Clone, PartialEq)] 178#[derive(Copy, Clone, PartialEq)]
179#[allow(missing_docs)]
210pub enum SyncInput { 180pub enum SyncInput {
211 /// Not synced to any other SAI unit. 181 /// Not synced to any other SAI unit.
212 None, 182 None,
@@ -218,7 +188,7 @@ pub enum SyncInput {
218} 188}
219 189
220impl SyncInput { 190impl SyncInput {
221 pub const fn syncen(&self) -> vals::Syncen { 191 const fn syncen(&self) -> vals::Syncen {
222 match self { 192 match self {
223 SyncInput::None => vals::Syncen::ASYNCHRONOUS, 193 SyncInput::None => vals::Syncen::ASYNCHRONOUS,
224 SyncInput::Internal => vals::Syncen::INTERNAL, 194 SyncInput::Internal => vals::Syncen::INTERNAL,
@@ -228,8 +198,10 @@ impl SyncInput {
228 } 198 }
229} 199}
230 200
201/// SAI instance to sync from.
231#[cfg(sai_v4)] 202#[cfg(sai_v4)]
232#[derive(Copy, Clone, PartialEq)] 203#[derive(Copy, Clone, PartialEq)]
204#[allow(missing_docs)]
233pub enum SyncInputInstance { 205pub enum SyncInputInstance {
234 #[cfg(peri_sai1)] 206 #[cfg(peri_sai1)]
235 Sai1 = 0, 207 Sai1 = 0,
@@ -241,7 +213,9 @@ pub enum SyncInputInstance {
241 Sai4 = 3, 213 Sai4 = 3,
242} 214}
243 215
216/// Channels (stereo or mono).
244#[derive(Copy, Clone, PartialEq)] 217#[derive(Copy, Clone, PartialEq)]
218#[allow(missing_docs)]
245pub enum StereoMono { 219pub enum StereoMono {
246 Stereo, 220 Stereo,
247 Mono, 221 Mono,
@@ -249,7 +223,7 @@ pub enum StereoMono {
249 223
250impl StereoMono { 224impl StereoMono {
251 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 225 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
252 pub const fn mono(&self) -> vals::Mono { 226 const fn mono(&self) -> vals::Mono {
253 match self { 227 match self {
254 StereoMono::Stereo => vals::Mono::STEREO, 228 StereoMono::Stereo => vals::Mono::STEREO,
255 StereoMono::Mono => vals::Mono::MONO, 229 StereoMono::Mono => vals::Mono::MONO,
@@ -257,15 +231,18 @@ impl StereoMono {
257 } 231 }
258} 232}
259 233
234/// Bit order
260#[derive(Copy, Clone)] 235#[derive(Copy, Clone)]
261pub enum BitOrder { 236pub enum BitOrder {
237 /// Least significant bit first.
262 LsbFirst, 238 LsbFirst,
239 /// Most significant bit first.
263 MsbFirst, 240 MsbFirst,
264} 241}
265 242
266impl BitOrder { 243impl BitOrder {
267 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 244 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
268 pub const fn lsbfirst(&self) -> vals::Lsbfirst { 245 const fn lsbfirst(&self) -> vals::Lsbfirst {
269 match self { 246 match self {
270 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, 247 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST,
271 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, 248 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
@@ -273,6 +250,7 @@ impl BitOrder {
273 } 250 }
274} 251}
275 252
253/// Frame sync offset.
276#[derive(Copy, Clone)] 254#[derive(Copy, Clone)]
277pub enum FrameSyncOffset { 255pub enum FrameSyncOffset {
278 /// This is used in modes other than standard I2S phillips mode 256 /// This is used in modes other than standard I2S phillips mode
@@ -283,7 +261,7 @@ pub enum FrameSyncOffset {
283 261
284impl FrameSyncOffset { 262impl FrameSyncOffset {
285 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 263 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
286 pub const fn fsoff(&self) -> vals::Fsoff { 264 const fn fsoff(&self) -> vals::Fsoff {
287 match self { 265 match self {
288 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, 266 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST,
289 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, 267 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST,
@@ -291,15 +269,18 @@ impl FrameSyncOffset {
291 } 269 }
292} 270}
293 271
272/// Frame sync polarity
294#[derive(Copy, Clone)] 273#[derive(Copy, Clone)]
295pub enum FrameSyncPolarity { 274pub enum FrameSyncPolarity {
275 /// Sync signal is active low.
296 ActiveLow, 276 ActiveLow,
277 /// Sync signal is active high
297 ActiveHigh, 278 ActiveHigh,
298} 279}
299 280
300impl FrameSyncPolarity { 281impl FrameSyncPolarity {
301 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 282 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
302 pub const fn fspol(&self) -> vals::Fspol { 283 const fn fspol(&self) -> vals::Fspol {
303 match self { 284 match self {
304 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, 285 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE,
305 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, 286 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE,
@@ -307,7 +288,9 @@ impl FrameSyncPolarity {
307 } 288 }
308} 289}
309 290
291/// Sync definition.
310#[derive(Copy, Clone)] 292#[derive(Copy, Clone)]
293#[allow(missing_docs)]
311pub enum FrameSyncDefinition { 294pub enum FrameSyncDefinition {
312 StartOfFrame, 295 StartOfFrame,
313 ChannelIdentification, 296 ChannelIdentification,
@@ -315,7 +298,7 @@ pub enum FrameSyncDefinition {
315 298
316impl FrameSyncDefinition { 299impl FrameSyncDefinition {
317 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 300 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
318 pub const fn fsdef(&self) -> bool { 301 const fn fsdef(&self) -> bool {
319 match self { 302 match self {
320 FrameSyncDefinition::StartOfFrame => false, 303 FrameSyncDefinition::StartOfFrame => false,
321 FrameSyncDefinition::ChannelIdentification => true, 304 FrameSyncDefinition::ChannelIdentification => true,
@@ -323,7 +306,9 @@ impl FrameSyncDefinition {
323 } 306 }
324} 307}
325 308
309/// Clock strobe.
326#[derive(Copy, Clone)] 310#[derive(Copy, Clone)]
311#[allow(missing_docs)]
327pub enum ClockStrobe { 312pub enum ClockStrobe {
328 Falling, 313 Falling,
329 Rising, 314 Rising,
@@ -331,7 +316,7 @@ pub enum ClockStrobe {
331 316
332impl ClockStrobe { 317impl ClockStrobe {
333 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 318 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
334 pub const fn ckstr(&self) -> vals::Ckstr { 319 const fn ckstr(&self) -> vals::Ckstr {
335 match self { 320 match self {
336 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, 321 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE,
337 ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, 322 ClockStrobe::Rising => vals::Ckstr::RISINGEDGE,
@@ -339,7 +324,9 @@ impl ClockStrobe {
339 } 324 }
340} 325}
341 326
327/// Complements format for negative samples.
342#[derive(Copy, Clone)] 328#[derive(Copy, Clone)]
329#[allow(missing_docs)]
343pub enum ComplementFormat { 330pub enum ComplementFormat {
344 OnesComplement, 331 OnesComplement,
345 TwosComplement, 332 TwosComplement,
@@ -347,7 +334,7 @@ pub enum ComplementFormat {
347 334
348impl ComplementFormat { 335impl ComplementFormat {
349 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 336 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
350 pub const fn cpl(&self) -> vals::Cpl { 337 const fn cpl(&self) -> vals::Cpl {
351 match self { 338 match self {
352 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, 339 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT,
353 ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, 340 ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT,
@@ -355,7 +342,9 @@ impl ComplementFormat {
355 } 342 }
356} 343}
357 344
345/// Companding setting.
358#[derive(Copy, Clone)] 346#[derive(Copy, Clone)]
347#[allow(missing_docs)]
359pub enum Companding { 348pub enum Companding {
360 None, 349 None,
361 MuLaw, 350 MuLaw,
@@ -364,7 +353,7 @@ pub enum Companding {
364 353
365impl Companding { 354impl Companding {
366 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 355 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
367 pub const fn comp(&self) -> vals::Comp { 356 const fn comp(&self) -> vals::Comp {
368 match self { 357 match self {
369 Companding::None => vals::Comp::NOCOMPANDING, 358 Companding::None => vals::Comp::NOCOMPANDING,
370 Companding::MuLaw => vals::Comp::MULAW, 359 Companding::MuLaw => vals::Comp::MULAW,
@@ -373,7 +362,9 @@ impl Companding {
373 } 362 }
374} 363}
375 364
365/// Output drive
376#[derive(Copy, Clone)] 366#[derive(Copy, Clone)]
367#[allow(missing_docs)]
377pub enum OutputDrive { 368pub enum OutputDrive {
378 OnStart, 369 OnStart,
379 Immediately, 370 Immediately,
@@ -381,7 +372,7 @@ pub enum OutputDrive {
381 372
382impl OutputDrive { 373impl OutputDrive {
383 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 374 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
384 pub const fn outdriv(&self) -> vals::Outdriv { 375 const fn outdriv(&self) -> vals::Outdriv {
385 match self { 376 match self {
386 OutputDrive::OnStart => vals::Outdriv::ONSTART, 377 OutputDrive::OnStart => vals::Outdriv::ONSTART,
387 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, 378 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY,
@@ -389,7 +380,9 @@ impl OutputDrive {
389 } 380 }
390} 381}
391 382
383/// Master clock divider.
392#[derive(Copy, Clone, PartialEq)] 384#[derive(Copy, Clone, PartialEq)]
385#[allow(missing_docs)]
393pub enum MasterClockDivider { 386pub enum MasterClockDivider {
394 MasterClockDisabled, 387 MasterClockDisabled,
395 Div1, 388 Div1,
@@ -412,7 +405,7 @@ pub enum MasterClockDivider {
412 405
413impl MasterClockDivider { 406impl MasterClockDivider {
414 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 407 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
415 pub const fn mckdiv(&self) -> u8 { 408 const fn mckdiv(&self) -> u8 {
416 match self { 409 match self {
417 MasterClockDivider::MasterClockDisabled => 0, 410 MasterClockDivider::MasterClockDisabled => 0,
418 MasterClockDivider::Div1 => 0, 411 MasterClockDivider::Div1 => 0,
@@ -436,6 +429,7 @@ impl MasterClockDivider {
436} 429}
437 430
438/// [`SAI`] configuration. 431/// [`SAI`] configuration.
432#[allow(missing_docs)]
439#[non_exhaustive] 433#[non_exhaustive]
440#[derive(Copy, Clone)] 434#[derive(Copy, Clone)]
441pub struct Config { 435pub struct Config {
@@ -459,7 +453,7 @@ pub struct Config {
459 pub clock_strobe: ClockStrobe, 453 pub clock_strobe: ClockStrobe,
460 pub output_drive: OutputDrive, 454 pub output_drive: OutputDrive,
461 pub master_clock_divider: MasterClockDivider, 455 pub master_clock_divider: MasterClockDivider,
462 pub is_high_impedenane_on_inactive_slot: bool, 456 pub is_high_impedance_on_inactive_slot: bool,
463 pub fifo_threshold: FifoThreshold, 457 pub fifo_threshold: FifoThreshold,
464 pub companding: Companding, 458 pub companding: Companding,
465 pub complement_format: ComplementFormat, 459 pub complement_format: ComplementFormat,
@@ -490,7 +484,7 @@ impl Default for Config {
490 master_clock_divider: MasterClockDivider::MasterClockDisabled, 484 master_clock_divider: MasterClockDivider::MasterClockDisabled,
491 clock_strobe: ClockStrobe::Rising, 485 clock_strobe: ClockStrobe::Rising,
492 output_drive: OutputDrive::Immediately, 486 output_drive: OutputDrive::Immediately,
493 is_high_impedenane_on_inactive_slot: false, 487 is_high_impedance_on_inactive_slot: false,
494 fifo_threshold: FifoThreshold::ThreeQuarters, 488 fifo_threshold: FifoThreshold::ThreeQuarters,
495 companding: Companding::None, 489 companding: Companding::None,
496 complement_format: ComplementFormat::TwosComplement, 490 complement_format: ComplementFormat::TwosComplement,
@@ -501,23 +495,10 @@ impl Default for Config {
501} 495}
502 496
503impl Config { 497impl Config {
504 pub fn new_i2s() -> Self { 498 /// Create a new config with all default values.
499 pub fn new() -> Self {
505 return Default::default(); 500 return Default::default();
506 } 501 }
507
508 pub fn new_msb_first() -> Self {
509 Self {
510 bit_order: BitOrder::MsbFirst,
511 frame_sync_offset: FrameSyncOffset::OnFirstBit,
512 ..Default::default()
513 }
514 }
515}
516
517#[derive(Copy, Clone)]
518enum WhichSubBlock {
519 A = 0,
520 B = 1,
521} 502}
522 503
523enum RingBuffer<'d, C: Channel, W: word::Word> { 504enum RingBuffer<'d, C: Channel, W: word::Word> {
@@ -531,28 +512,6 @@ fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut
531 ch.dr().as_ptr() as _ 512 ch.dr().as_ptr() as _
532} 513}
533 514
534pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> {
535 _peri: PeripheralRef<'d, T>,
536 sd: Option<PeripheralRef<'d, AnyPin>>,
537 fs: Option<PeripheralRef<'d, AnyPin>>,
538 sck: Option<PeripheralRef<'d, AnyPin>>,
539 mclk: Option<PeripheralRef<'d, AnyPin>>,
540 ring_buffer: RingBuffer<'d, C, W>,
541 sub_block: WhichSubBlock,
542}
543
544pub struct SubBlockA {}
545pub struct SubBlockB {}
546
547pub struct SubBlockAPeripheral<'d, T>(PeripheralRef<'d, T>);
548pub struct SubBlockBPeripheral<'d, T>(PeripheralRef<'d, T>);
549
550pub struct Sai<'d, T: Instance> {
551 _peri: PeripheralRef<'d, T>,
552 sub_block_a_peri: Option<SubBlockAPeripheral<'d, T>>,
553 sub_block_b_peri: Option<SubBlockBPeripheral<'d, T>>,
554}
555
556// return the type for (sd, sck) 515// return the type for (sd, sck)
557fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { 516fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) {
558 ( 517 (
@@ -583,42 +542,14 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>(
583 }; 542 };
584 match tx_rx { 543 match tx_rx {
585 TxRx::Transmitter => RingBuffer::Writable(unsafe { 544 TxRx::Transmitter => RingBuffer::Writable(unsafe {
586 WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) 545 WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
587 }), 546 }),
588 TxRx::Receiver => RingBuffer::Readable(unsafe { 547 TxRx::Receiver => RingBuffer::Readable(unsafe {
589 ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) 548 ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
590 }), 549 }),
591 } 550 }
592} 551}
593 552
594impl<'d, T: Instance> Sai<'d, T> {
595 pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
596 T::enable_and_reset();
597
598 Self {
599 _peri: unsafe { peri.clone_unchecked().into_ref() },
600 sub_block_a_peri: Some(SubBlockAPeripheral(unsafe { peri.clone_unchecked().into_ref() })),
601 sub_block_b_peri: Some(SubBlockBPeripheral(peri.into_ref())),
602 }
603 }
604
605 pub fn take_sub_block_a(self: &mut Self) -> Option<SubBlockAPeripheral<'d, T>> {
606 if self.sub_block_a_peri.is_some() {
607 self.sub_block_a_peri.take()
608 } else {
609 None
610 }
611 }
612
613 pub fn take_sub_block_b(self: &mut Self) -> Option<SubBlockBPeripheral<'d, T>> {
614 if self.sub_block_b_peri.is_some() {
615 self.sub_block_b_peri.take()
616 } else {
617 None
618 }
619 }
620}
621
622fn update_synchronous_config(config: &mut Config) { 553fn update_synchronous_config(config: &mut Config) {
623 config.mode = Mode::Slave; 554 config.mode = Mode::Slave;
624 config.sync_output = false; 555 config.sync_output = false;
@@ -636,122 +567,58 @@ fn update_synchronous_config(config: &mut Config) {
636 } 567 }
637} 568}
638 569
639impl SubBlockA { 570/// SAI subblock instance.
640 pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( 571pub struct SubBlock<'d, T, S: SubBlockInstance> {
641 peri: SubBlockAPeripheral<'d, T>, 572 peri: PeripheralRef<'d, T>,
642 sck: impl Peripheral<P = impl SckAPin<T>> + 'd, 573 _phantom: PhantomData<S>,
643 sd: impl Peripheral<P = impl SdAPin<T>> + 'd, 574}
644 fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
645 mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd,
646 dma: impl Peripheral<P = C> + 'd,
647 dma_buf: &'d mut [W],
648 mut config: Config,
649 ) -> SubBlock<'d, T, C, W>
650 where
651 C: Channel + DmaA<T>,
652 {
653 into_ref!(mclk);
654
655 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
656
657 mclk.set_as_af(mclk.af_num(), ck_af_type);
658 mclk.set_speed(crate::gpio::Speed::VeryHigh);
659
660 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
661 config.master_clock_divider = MasterClockDivider::Div1;
662 }
663
664 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
665 }
666
667 pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>(
668 peri: SubBlockAPeripheral<'d, T>,
669 sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
670 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
671 fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
672 dma: impl Peripheral<P = C> + 'd,
673 dma_buf: &'d mut [W],
674 config: Config,
675 ) -> SubBlock<'d, T, C, W>
676 where
677 C: Channel + DmaA<T>,
678 {
679 let peri = peri.0;
680 into_ref!(peri, dma, sck, sd, fs);
681
682 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
683 sd.set_as_af(sd.af_num(), sd_af_type);
684 sd.set_speed(crate::gpio::Speed::VeryHigh);
685
686 sck.set_as_af(sck.af_num(), ck_af_type);
687 sck.set_speed(crate::gpio::Speed::VeryHigh);
688 fs.set_as_af(fs.af_num(), ck_af_type);
689 fs.set_speed(crate::gpio::Speed::VeryHigh);
690 575
691 let sub_block = WhichSubBlock::A; 576/// Split the main SAIx peripheral into the two subblocks.
692 let request = dma.request(); 577///
578/// You can then create a [`Sai`] driver for each each half.
579pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
580 into_ref!(peri);
581 T::enable_and_reset();
693 582
694 SubBlock::new_inner( 583 (
584 SubBlock {
585 peri: unsafe { peri.clone_unchecked() },
586 _phantom: PhantomData,
587 },
588 SubBlock {
695 peri, 589 peri,
696 sub_block, 590 _phantom: PhantomData,
697 Some(sck.map_into()), 591 },
698 None, 592 )
699 Some(sd.map_into()), 593}
700 Some(fs.map_into()),
701 get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx),
702 config,
703 )
704 }
705
706 pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>(
707 peri: SubBlockAPeripheral<'d, T>,
708 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
709 dma: impl Peripheral<P = C> + 'd,
710 dma_buf: &'d mut [W],
711 mut config: Config,
712 ) -> SubBlock<'d, T, C, W>
713 where
714 C: Channel + DmaA<T>,
715 {
716 update_synchronous_config(&mut config);
717
718 let peri = peri.0;
719 into_ref!(dma, peri, sd);
720
721 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
722
723 sd.set_as_af(sd.af_num(), sd_af_type);
724 sd.set_speed(crate::gpio::Speed::VeryHigh);
725
726 let sub_block = WhichSubBlock::A;
727 let request = dma.request();
728 594
729 SubBlock::new_inner( 595/// SAI sub-block driver.
730 peri, 596pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> {
731 sub_block, 597 _peri: PeripheralRef<'d, T>,
732 None, 598 sd: Option<PeripheralRef<'d, AnyPin>>,
733 None, 599 fs: Option<PeripheralRef<'d, AnyPin>>,
734 Some(sd.map_into()), 600 sck: Option<PeripheralRef<'d, AnyPin>>,
735 None, 601 mclk: Option<PeripheralRef<'d, AnyPin>>,
736 get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), 602 ring_buffer: RingBuffer<'d, C, W>,
737 config, 603 sub_block: WhichSubBlock,
738 )
739 }
740} 604}
741 605
742impl SubBlockB { 606impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
743 pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( 607 /// Create a new SAI driver in asynchronous mode with MCLK.
744 peri: SubBlockBPeripheral<'d, T>, 608 ///
745 sck: impl Peripheral<P = impl SckBPin<T>> + 'd, 609 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
746 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 610 pub fn new_asynchronous_with_mclk<S: SubBlockInstance>(
747 fs: impl Peripheral<P = impl FsBPin<T>> + 'd, 611 peri: SubBlock<'d, T, S>,
748 mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd, 612 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd,
613 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
614 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
615 mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd,
749 dma: impl Peripheral<P = C> + 'd, 616 dma: impl Peripheral<P = C> + 'd,
750 dma_buf: &'d mut [W], 617 dma_buf: &'d mut [W],
751 mut config: Config, 618 mut config: Config,
752 ) -> SubBlock<'d, T, C, W> 619 ) -> Self
753 where 620 where
754 C: Channel + DmaB<T>, 621 C: Channel + Dma<T, S>,
755 { 622 {
756 into_ref!(mclk); 623 into_ref!(mclk);
757 624
@@ -767,23 +634,25 @@ impl SubBlockB {
767 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) 634 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
768 } 635 }
769 636
770 pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( 637 /// Create a new SAI driver in asynchronous mode without MCLK.
771 peri: SubBlockBPeripheral<'d, T>, 638 ///
772 sck: impl Peripheral<P = impl SckBPin<T>> + 'd, 639 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
773 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 640 pub fn new_asynchronous<S: SubBlockInstance>(
774 fs: impl Peripheral<P = impl FsBPin<T>> + 'd, 641 peri: SubBlock<'d, T, S>,
642 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd,
643 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
644 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
775 dma: impl Peripheral<P = C> + 'd, 645 dma: impl Peripheral<P = C> + 'd,
776 dma_buf: &'d mut [W], 646 dma_buf: &'d mut [W],
777 config: Config, 647 config: Config,
778 ) -> SubBlock<'d, T, C, W> 648 ) -> Self
779 where 649 where
780 C: Channel + DmaB<T>, 650 C: Channel + Dma<T, S>,
781 { 651 {
782 let peri = peri.0; 652 let peri = peri.peri;
783 into_ref!(dma, peri, sck, sd, fs); 653 into_ref!(peri, dma, sck, sd, fs);
784 654
785 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); 655 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
786
787 sd.set_as_af(sd.af_num(), sd_af_type); 656 sd.set_as_af(sd.af_num(), sd_af_type);
788 sd.set_speed(crate::gpio::Speed::VeryHigh); 657 sd.set_speed(crate::gpio::Speed::VeryHigh);
789 658
@@ -792,10 +661,10 @@ impl SubBlockB {
792 fs.set_as_af(fs.af_num(), ck_af_type); 661 fs.set_as_af(fs.af_num(), ck_af_type);
793 fs.set_speed(crate::gpio::Speed::VeryHigh); 662 fs.set_speed(crate::gpio::Speed::VeryHigh);
794 663
795 let sub_block = WhichSubBlock::B; 664 let sub_block = S::WHICH;
796 let request = dma.request(); 665 let request = dma.request();
797 666
798 SubBlock::new_inner( 667 Self::new_inner(
799 peri, 668 peri,
800 sub_block, 669 sub_block,
801 Some(sck.map_into()), 670 Some(sck.map_into()),
@@ -807,18 +676,22 @@ impl SubBlockB {
807 ) 676 )
808 } 677 }
809 678
810 pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( 679 /// Create a new SAI driver in synchronous mode.
811 peri: SubBlockBPeripheral<'d, T>, 680 ///
812 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 681 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
682 pub fn new_synchronous<S: SubBlockInstance>(
683 peri: SubBlock<'d, T, S>,
684 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
813 dma: impl Peripheral<P = C> + 'd, 685 dma: impl Peripheral<P = C> + 'd,
814 dma_buf: &'d mut [W], 686 dma_buf: &'d mut [W],
815 mut config: Config, 687 mut config: Config,
816 ) -> SubBlock<'d, T, C, W> 688 ) -> Self
817 where 689 where
818 C: Channel + DmaB<T>, 690 C: Channel + Dma<T, S>,
819 { 691 {
820 update_synchronous_config(&mut config); 692 update_synchronous_config(&mut config);
821 let peri = peri.0; 693
694 let peri = peri.peri;
822 into_ref!(dma, peri, sd); 695 into_ref!(dma, peri, sd);
823 696
824 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); 697 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
@@ -826,10 +699,10 @@ impl SubBlockB {
826 sd.set_as_af(sd.af_num(), sd_af_type); 699 sd.set_as_af(sd.af_num(), sd_af_type);
827 sd.set_speed(crate::gpio::Speed::VeryHigh); 700 sd.set_speed(crate::gpio::Speed::VeryHigh);
828 701
829 let sub_block = WhichSubBlock::B; 702 let sub_block = S::WHICH;
830 let request = dma.request(); 703 let request = dma.request();
831 704
832 SubBlock::new_inner( 705 Self::new_inner(
833 peri, 706 peri,
834 sub_block, 707 sub_block,
835 None, 708 None,
@@ -840,26 +713,6 @@ impl SubBlockB {
840 config, 713 config,
841 ) 714 )
842 } 715 }
843}
844
845impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
846 pub fn start(self: &mut Self) {
847 match self.ring_buffer {
848 RingBuffer::Writable(ref mut rb) => {
849 rb.start();
850 }
851 RingBuffer::Readable(ref mut rb) => {
852 rb.start();
853 }
854 }
855 }
856
857 fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool {
858 match ring_buffer {
859 RingBuffer::Writable(_) => true,
860 _ => false,
861 }
862 }
863 716
864 fn new_inner( 717 fn new_inner(
865 peri: impl Peripheral<P = T> + 'd, 718 peri: impl Peripheral<P = T> + 'd,
@@ -929,7 +782,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
929 w.set_cpl(config.complement_format.cpl()); 782 w.set_cpl(config.complement_format.cpl());
930 w.set_muteval(config.mute_value.muteval()); 783 w.set_muteval(config.mute_value.muteval());
931 w.set_mutecnt(config.mute_detection_counter.0 as u8); 784 w.set_mutecnt(config.mute_detection_counter.0 as u8);
932 w.set_tris(config.is_high_impedenane_on_inactive_slot); 785 w.set_tris(config.is_high_impedance_on_inactive_slot);
933 }); 786 });
934 787
935 ch.frcr().modify(|w| { 788 ch.frcr().modify(|w| {
@@ -965,10 +818,31 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
965 } 818 }
966 } 819 }
967 820
821 /// Start the SAI driver.
822 pub fn start(&mut self) {
823 match self.ring_buffer {
824 RingBuffer::Writable(ref mut rb) => {
825 rb.start();
826 }
827 RingBuffer::Readable(ref mut rb) => {
828 rb.start();
829 }
830 }
831 }
832
833 fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool {
834 match ring_buffer {
835 RingBuffer::Writable(_) => true,
836 _ => false,
837 }
838 }
839
840 /// Reset SAI operation.
968 pub fn reset() { 841 pub fn reset() {
969 T::enable_and_reset(); 842 T::enable_and_reset();
970 } 843 }
971 844
845 /// Flush.
972 pub fn flush(&mut self) { 846 pub fn flush(&mut self) {
973 let ch = T::REGS.ch(self.sub_block as usize); 847 let ch = T::REGS.ch(self.sub_block as usize);
974 ch.cr1().modify(|w| w.set_saien(false)); 848 ch.cr1().modify(|w| w.set_saien(false));
@@ -983,19 +857,18 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
983 ch.cr1().modify(|w| w.set_saien(true)); 857 ch.cr1().modify(|w| w.set_saien(true));
984 } 858 }
985 859
860 /// Enable or disable mute.
986 pub fn set_mute(&mut self, value: bool) { 861 pub fn set_mute(&mut self, value: bool) {
987 let ch = T::REGS.ch(self.sub_block as usize); 862 let ch = T::REGS.ch(self.sub_block as usize);
988 ch.cr2().modify(|w| w.set_mute(value)); 863 ch.cr2().modify(|w| w.set_mute(value));
989 } 864 }
990 865
991 #[allow(dead_code)] 866 /// Write data to the SAI ringbuffer.
992 /// Reconfigures it with the supplied config. 867 ///
993 fn reconfigure(&mut self, _config: Config) {} 868 /// This appends the data to the buffer and returns immediately. The
994 869 /// data will be transmitted in the background.
995 pub fn get_current_config(&self) -> Config { 870 ///
996 Config::default() 871 /// If there's no space in the buffer, this waits until there is.
997 }
998
999 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { 872 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
1000 match &mut self.ring_buffer { 873 match &mut self.ring_buffer {
1001 RingBuffer::Writable(buffer) => { 874 RingBuffer::Writable(buffer) => {
@@ -1006,6 +879,12 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
1006 } 879 }
1007 } 880 }
1008 881
882 /// Read data from the SAI ringbuffer.
883 ///
884 /// SAI is always receiving data in the background. This function pops already-received
885 /// data from the buffer.
886 ///
887 /// If there's less than `data.len()` data in the buffer, this waits until there is.
1009 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { 888 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
1010 match &mut self.ring_buffer { 889 match &mut self.ring_buffer {
1011 RingBuffer::Readable(buffer) => { 890 RingBuffer::Readable(buffer) => {
@@ -1017,7 +896,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
1017 } 896 }
1018} 897}
1019 898
1020impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> { 899impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> {
1021 fn drop(&mut self) { 900 fn drop(&mut self) {
1022 let ch = T::REGS.ch(self.sub_block as usize); 901 let ch = T::REGS.ch(self.sub_block as usize);
1023 ch.cr1().modify(|w| w.set_saien(false)); 902 ch.cr1().modify(|w| w.set_saien(false));
@@ -1034,22 +913,43 @@ pub(crate) mod sealed {
1034 pub trait Instance { 913 pub trait Instance {
1035 const REGS: Regs; 914 const REGS: Regs;
1036 } 915 }
916
917 #[derive(Copy, Clone)]
918 pub enum WhichSubBlock {
919 A = 0,
920 B = 1,
921 }
922
923 pub trait SubBlock {
924 const WHICH: WhichSubBlock;
925 }
1037} 926}
1038 927
1039pub trait Word: word::Word {} 928/// Sub-block instance trait.
929pub trait SubBlockInstance: sealed::SubBlock {}
1040 930
931/// Sub-block A.
932pub enum A {}
933impl sealed::SubBlock for A {
934 const WHICH: WhichSubBlock = WhichSubBlock::A;
935}
936impl SubBlockInstance for A {}
937
938/// Sub-block B.
939pub enum B {}
940impl sealed::SubBlock for B {
941 const WHICH: WhichSubBlock = WhichSubBlock::B;
942}
943impl SubBlockInstance for B {}
944
945/// SAI instance trait.
1041pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 946pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
1042pin_trait!(SckAPin, Instance); 947pin_trait!(SckPin, Instance, SubBlockInstance);
1043pin_trait!(SckBPin, Instance); 948pin_trait!(FsPin, Instance, SubBlockInstance);
1044pin_trait!(FsAPin, Instance); 949pin_trait!(SdPin, Instance, SubBlockInstance);
1045pin_trait!(FsBPin, Instance); 950pin_trait!(MclkPin, Instance, SubBlockInstance);
1046pin_trait!(SdAPin, Instance); 951
1047pin_trait!(SdBPin, Instance); 952dma_trait!(Dma, Instance, SubBlockInstance);
1048pin_trait!(MclkAPin, Instance);
1049pin_trait!(MclkBPin, Instance);
1050
1051dma_trait!(DmaA, Instance);
1052dma_trait!(DmaB, Instance);
1053 953
1054foreach_peripheral!( 954foreach_peripheral!(
1055 (sai, $inst:ident) => { 955 (sai, $inst:ident) => {
@@ -1060,13 +960,3 @@ foreach_peripheral!(
1060 impl Instance for peripherals::$inst {} 960 impl Instance for peripherals::$inst {}
1061 }; 961 };
1062); 962);
1063
1064impl<'d, T: Instance> SetConfig for Sai<'d, T> {
1065 type Config = Config;
1066 type ConfigError = ();
1067 fn set_config(&mut self, _config: &Self::Config) -> Result<(), ()> {
1068 // self.reconfigure(*config);
1069
1070 Ok(())
1071 }
1072}
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 27a12062c..debe26c88 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -1,3 +1,4 @@
1//! Secure Digital / MultiMedia Card (SDMMC)
1#![macro_use] 2#![macro_use]
2 3
3use core::default::Default; 4use core::default::Default;
@@ -53,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000);
53 54
54/// The signalling scheme used on the SDMMC bus 55/// The signalling scheme used on the SDMMC bus
55#[non_exhaustive] 56#[non_exhaustive]
57#[allow(missing_docs)]
56#[derive(Debug, Copy, Clone, PartialEq, Eq)] 58#[derive(Debug, Copy, Clone, PartialEq, Eq)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))] 59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub enum Signalling { 60pub enum Signalling {
@@ -69,6 +71,9 @@ impl Default for Signalling {
69 } 71 }
70} 72}
71 73
74/// Aligned data block for SDMMC transfers.
75///
76/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements.
72#[repr(align(4))] 77#[repr(align(4))]
73#[derive(Debug, Clone, PartialEq, Eq)] 78#[derive(Debug, Clone, PartialEq, Eq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -93,17 +98,23 @@ impl DerefMut for DataBlock {
93#[derive(Debug, Copy, Clone, PartialEq, Eq)] 98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))] 99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95pub enum Error { 100pub enum Error {
101 /// Timeout reported by the hardware
96 Timeout, 102 Timeout,
103 /// Timeout reported by the software driver.
97 SoftwareTimeout, 104 SoftwareTimeout,
105 /// Unsupported card version.
98 UnsupportedCardVersion, 106 UnsupportedCardVersion,
107 /// Unsupported card type.
99 UnsupportedCardType, 108 UnsupportedCardType,
109 /// CRC error.
100 Crc, 110 Crc,
101 DataCrcFail, 111 /// No card inserted.
102 RxOverFlow,
103 NoCard, 112 NoCard,
113 /// Bad clock supplied to the SDMMC peripheral.
104 BadClock, 114 BadClock,
115 /// Signaling switch failed.
105 SignalingSwitchFailed, 116 SignalingSwitchFailed,
106 PeripheralBusy, 117 /// ST bit error.
107 #[cfg(sdmmc_v1)] 118 #[cfg(sdmmc_v1)]
108 StBitErr, 119 StBitErr,
109} 120}
@@ -282,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
282 293
283#[cfg(sdmmc_v1)] 294#[cfg(sdmmc_v1)]
284impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { 295impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
296 /// Create a new SDMMC driver, with 1 data lane.
285 pub fn new_1bit( 297 pub fn new_1bit(
286 sdmmc: impl Peripheral<P = T> + 'd, 298 sdmmc: impl Peripheral<P = T> + 'd,
287 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 299 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -316,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
316 ) 328 )
317 } 329 }
318 330
331 /// Create a new SDMMC driver, with 4 data lanes.
319 pub fn new_4bit( 332 pub fn new_4bit(
320 sdmmc: impl Peripheral<P = T> + 'd, 333 sdmmc: impl Peripheral<P = T> + 'd,
321 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 334 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -362,6 +375,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
362 375
363#[cfg(sdmmc_v2)] 376#[cfg(sdmmc_v2)]
364impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { 377impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
378 /// Create a new SDMMC driver, with 1 data lane.
365 pub fn new_1bit( 379 pub fn new_1bit(
366 sdmmc: impl Peripheral<P = T> + 'd, 380 sdmmc: impl Peripheral<P = T> + 'd,
367 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 381 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -395,6 +409,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
395 ) 409 )
396 } 410 }
397 411
412 /// Create a new SDMMC driver, with 4 data lanes.
398 pub fn new_4bit( 413 pub fn new_4bit(
399 sdmmc: impl Peripheral<P = T> + 'd, 414 sdmmc: impl Peripheral<P = T> + 'd,
400 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 415 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -496,7 +511,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
496 } 511 }
497 512
498 /// Data transfer is in progress 513 /// Data transfer is in progress
499 #[inline(always)] 514 #[inline]
500 fn data_active() -> bool { 515 fn data_active() -> bool {
501 let regs = T::regs(); 516 let regs = T::regs();
502 517
@@ -508,7 +523,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
508 } 523 }
509 524
510 /// Coammand transfer is in progress 525 /// Coammand transfer is in progress
511 #[inline(always)] 526 #[inline]
512 fn cmd_active() -> bool { 527 fn cmd_active() -> bool {
513 let regs = T::regs(); 528 let regs = T::regs();
514 529
@@ -520,7 +535,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
520 } 535 }
521 536
522 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 537 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
523 #[inline(always)] 538 #[inline]
524 fn wait_idle() { 539 fn wait_idle() {
525 while Self::data_active() || Self::cmd_active() {} 540 while Self::data_active() || Self::cmd_active() {}
526 } 541 }
@@ -836,7 +851,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
836 } 851 }
837 852
838 /// Clear flags in interrupt clear register 853 /// Clear flags in interrupt clear register
839 #[inline(always)] 854 #[inline]
840 fn clear_interrupt_flags() { 855 fn clear_interrupt_flags() {
841 let regs = T::regs(); 856 let regs = T::regs();
842 regs.icr().write(|w| { 857 regs.icr().write(|w| {
@@ -1151,7 +1166,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1151 Ok(()) 1166 Ok(())
1152 } 1167 }
1153 1168
1154 #[inline(always)] 1169 /// Read a data block.
1170 #[inline]
1155 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { 1171 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
1156 let card_capacity = self.card()?.card_type; 1172 let card_capacity = self.card()?.card_type;
1157 1173
@@ -1203,6 +1219,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1203 res 1219 res
1204 } 1220 }
1205 1221
1222 /// Write a data block.
1206 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { 1223 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1207 let card = self.card.as_mut().ok_or(Error::NoCard)?; 1224 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1208 1225
@@ -1282,7 +1299,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1282 /// 1299 ///
1283 /// Returns Error::NoCard if [`init_card`](#method.init_card) 1300 /// Returns Error::NoCard if [`init_card`](#method.init_card)
1284 /// has not previously succeeded 1301 /// has not previously succeeded
1285 #[inline(always)] 1302 #[inline]
1286 pub fn card(&self) -> Result<&Card, Error> { 1303 pub fn card(&self) -> Result<&Card, Error> {
1287 self.card.as_ref().ok_or(Error::NoCard) 1304 self.card.as_ref().ok_or(Error::NoCard)
1288 } 1305 }
@@ -1418,7 +1435,9 @@ pub(crate) mod sealed {
1418 pub trait Pins<T: Instance> {} 1435 pub trait Pins<T: Instance> {}
1419} 1436}
1420 1437
1438/// SDMMC instance trait.
1421pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 1439pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
1440
1422pin_trait!(CkPin, Instance); 1441pin_trait!(CkPin, Instance);
1423pin_trait!(CmdPin, Instance); 1442pin_trait!(CmdPin, Instance);
1424pin_trait!(D0Pin, Instance); 1443pin_trait!(D0Pin, Instance);
@@ -1433,7 +1452,10 @@ pin_trait!(D7Pin, Instance);
1433#[cfg(sdmmc_v1)] 1452#[cfg(sdmmc_v1)]
1434dma_trait!(SdmmcDma, Instance); 1453dma_trait!(SdmmcDma, Instance);
1435 1454
1436// SDMMCv2 uses internal DMA 1455/// DMA instance trait.
1456///
1457/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of
1458/// using ST's system-wide DMA peripheral.
1437#[cfg(sdmmc_v2)] 1459#[cfg(sdmmc_v2)]
1438pub trait SdmmcDma<T: Instance> {} 1460pub trait SdmmcDma<T: Instance> {}
1439#[cfg(sdmmc_v2)] 1461#[cfg(sdmmc_v2)]
@@ -1516,53 +1538,3 @@ foreach_peripheral!(
1516 impl Instance for peripherals::$inst {} 1538 impl Instance for peripherals::$inst {}
1517 }; 1539 };
1518); 1540);
1519
1520#[cfg(feature = "embedded-sdmmc")]
1521mod sdmmc_rs {
1522 use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
1523
1524 use super::*;
1525
1526 impl<'d, T: Instance, Dma: SdmmcDma<T>> BlockDevice for Sdmmc<'d, T, Dma> {
1527 type Error = Error;
1528
1529 async fn read(
1530 &mut self,
1531 blocks: &mut [Block],
1532 start_block_idx: BlockIdx,
1533 _reason: &str,
1534 ) -> Result<(), Self::Error> {
1535 let mut address = start_block_idx.0;
1536
1537 for block in blocks.iter_mut() {
1538 let block: &mut [u8; 512] = &mut block.contents;
1539
1540 // NOTE(unsafe) Block uses align(4)
1541 let block = unsafe { &mut *(block as *mut _ as *mut DataBlock) };
1542 self.read_block(address, block).await?;
1543 address += 1;
1544 }
1545 Ok(())
1546 }
1547
1548 async fn write(&mut self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
1549 let mut address = start_block_idx.0;
1550
1551 for block in blocks.iter() {
1552 let block: &[u8; 512] = &block.contents;
1553
1554 // NOTE(unsafe) DataBlock uses align 4
1555 let block = unsafe { &*(block as *const _ as *const DataBlock) };
1556 self.write_block(address, block).await?;
1557 address += 1;
1558 }
1559 Ok(())
1560 }
1561
1562 fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
1563 let card = self.card()?;
1564 let count = card.csd.block_count();
1565 Ok(BlockCount(count))
1566 }
1567 }
1568}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 92599c75e..23f027e70 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1,3 +1,4 @@
1//! Serial Peripheral Interface (SPI)
1#![macro_use] 2#![macro_use]
2 3
3use core::ptr; 4use core::ptr;
@@ -15,27 +16,38 @@ use crate::rcc::RccPeripheral;
15use crate::time::Hertz; 16use crate::time::Hertz;
16use crate::{peripherals, Peripheral}; 17use crate::{peripherals, Peripheral};
17 18
19/// SPI error.
18#[derive(Debug, PartialEq, Eq)] 20#[derive(Debug, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Error { 22pub enum Error {
23 /// Invalid framing.
21 Framing, 24 Framing,
25 /// CRC error (only if hardware CRC checking is enabled).
22 Crc, 26 Crc,
27 /// Mode fault
23 ModeFault, 28 ModeFault,
29 /// Overrun.
24 Overrun, 30 Overrun,
25} 31}
26 32
27// TODO move upwards in the tree 33/// SPI bit order
28#[derive(Copy, Clone)] 34#[derive(Copy, Clone)]
29pub enum BitOrder { 35pub enum BitOrder {
36 /// Least significant bit first.
30 LsbFirst, 37 LsbFirst,
38 /// Most significant bit first.
31 MsbFirst, 39 MsbFirst,
32} 40}
33 41
42/// SPI configuration.
34#[non_exhaustive] 43#[non_exhaustive]
35#[derive(Copy, Clone)] 44#[derive(Copy, Clone)]
36pub struct Config { 45pub struct Config {
46 /// SPI mode.
37 pub mode: Mode, 47 pub mode: Mode,
48 /// Bit order.
38 pub bit_order: BitOrder, 49 pub bit_order: BitOrder,
50 /// Clock frequency.
39 pub frequency: Hertz, 51 pub frequency: Hertz,
40} 52}
41 53
@@ -72,6 +84,7 @@ impl Config {
72 } 84 }
73} 85}
74 86
87/// SPI driver.
75pub struct Spi<'d, T: Instance, Tx, Rx> { 88pub struct Spi<'d, T: Instance, Tx, Rx> {
76 _peri: PeripheralRef<'d, T>, 89 _peri: PeripheralRef<'d, T>,
77 sck: Option<PeripheralRef<'d, AnyPin>>, 90 sck: Option<PeripheralRef<'d, AnyPin>>,
@@ -83,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> {
83} 96}
84 97
85impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { 98impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
99 /// Create a new SPI driver.
86 pub fn new( 100 pub fn new(
87 peri: impl Peripheral<P = T> + 'd, 101 peri: impl Peripheral<P = T> + 'd,
88 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 102 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -117,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
117 ) 131 )
118 } 132 }
119 133
134 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
120 pub fn new_rxonly( 135 pub fn new_rxonly(
121 peri: impl Peripheral<P = T> + 'd, 136 peri: impl Peripheral<P = T> + 'd,
122 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 137 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -142,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
142 ) 157 )
143 } 158 }
144 159
160 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
145 pub fn new_txonly( 161 pub fn new_txonly(
146 peri: impl Peripheral<P = T> + 'd, 162 peri: impl Peripheral<P = T> + 'd,
147 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 163 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -167,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
167 ) 183 )
168 } 184 }
169 185
186 /// Create a new SPI driver, in TX-only mode, without SCK pin.
187 ///
188 /// This can be useful for bit-banging non-SPI protocols.
170 pub fn new_txonly_nosck( 189 pub fn new_txonly_nosck(
171 peri: impl Peripheral<P = T> + 'd, 190 peri: impl Peripheral<P = T> + 'd,
172 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 191 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@@ -292,7 +311,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
292 w.set_ssom(vals::Ssom::ASSERTED); 311 w.set_ssom(vals::Ssom::ASSERTED);
293 w.set_midi(0); 312 w.set_midi(0);
294 w.set_mssi(0); 313 w.set_mssi(0);
295 w.set_afcntr(vals::Afcntr::CONTROLLED); 314 w.set_afcntr(true);
296 w.set_ssiop(vals::Ssiop::ACTIVEHIGH); 315 w.set_ssiop(vals::Ssiop::ACTIVEHIGH);
297 }); 316 });
298 T::REGS.cfg1().modify(|w| { 317 T::REGS.cfg1().modify(|w| {
@@ -354,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
354 Ok(()) 373 Ok(())
355 } 374 }
356 375
376 /// Get current SPI configuration.
357 pub fn get_current_config(&self) -> Config { 377 pub fn get_current_config(&self) -> Config {
358 #[cfg(any(spi_v1, spi_f1, spi_v2))] 378 #[cfg(any(spi_v1, spi_f1, spi_v2))]
359 let cfg = T::REGS.cr1().read(); 379 let cfg = T::REGS.cr1().read();
@@ -443,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
443 self.current_word_size = word_size; 463 self.current_word_size = word_size;
444 } 464 }
445 465
466 /// SPI write, using DMA.
446 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 467 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
447 where 468 where
448 Tx: TxDma<T>, 469 Tx: TxDma<T>,
@@ -476,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
476 Ok(()) 497 Ok(())
477 } 498 }
478 499
500 /// SPI read, using DMA.
479 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 501 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
480 where 502 where
481 Tx: TxDma<T>, 503 Tx: TxDma<T>,
@@ -579,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
579 Ok(()) 601 Ok(())
580 } 602 }
581 603
604 /// Bidirectional transfer, using DMA.
605 ///
606 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
607 ///
608 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
609 /// If `write` is shorter it is padded with zero bytes.
582 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> 610 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error>
583 where 611 where
584 Tx: TxDma<T>, 612 Tx: TxDma<T>,
@@ -587,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
587 self.transfer_inner(read, write).await 615 self.transfer_inner(read, write).await
588 } 616 }
589 617
618 /// In-place bidirectional transfer, using DMA.
619 ///
620 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
590 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 621 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
591 where 622 where
592 Tx: TxDma<T>, 623 Tx: TxDma<T>,
@@ -595,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
595 self.transfer_inner(data, data).await 626 self.transfer_inner(data, data).await
596 } 627 }
597 628
629 /// Blocking write.
598 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { 630 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
599 T::REGS.cr1().modify(|w| w.set_spe(true)); 631 T::REGS.cr1().modify(|w| w.set_spe(true));
600 flush_rx_fifo(T::REGS); 632 flush_rx_fifo(T::REGS);
@@ -605,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
605 Ok(()) 637 Ok(())
606 } 638 }
607 639
640 /// Blocking read.
608 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 641 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
609 T::REGS.cr1().modify(|w| w.set_spe(true)); 642 T::REGS.cr1().modify(|w| w.set_spe(true));
610 flush_rx_fifo(T::REGS); 643 flush_rx_fifo(T::REGS);
@@ -615,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
615 Ok(()) 648 Ok(())
616 } 649 }
617 650
651 /// Blocking in-place bidirectional transfer.
652 ///
653 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
618 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 654 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
619 T::REGS.cr1().modify(|w| w.set_spe(true)); 655 T::REGS.cr1().modify(|w| w.set_spe(true));
620 flush_rx_fifo(T::REGS); 656 flush_rx_fifo(T::REGS);
@@ -625,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
625 Ok(()) 661 Ok(())
626 } 662 }
627 663
664 /// Blocking bidirectional transfer.
665 ///
666 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
667 ///
668 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
669 /// If `write` is shorter it is padded with zero bytes.
628 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 670 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
629 T::REGS.cr1().modify(|w| w.set_spe(true)); 671 T::REGS.cr1().modify(|w| w.set_spe(true));
630 flush_rx_fifo(T::REGS); 672 flush_rx_fifo(T::REGS);
@@ -945,6 +987,7 @@ pub(crate) mod sealed {
945 } 987 }
946} 988}
947 989
990/// Word sizes usable for SPI.
948pub trait Word: word::Word + sealed::Word {} 991pub trait Word: word::Word + sealed::Word {}
949 992
950macro_rules! impl_word { 993macro_rules! impl_word {
@@ -1024,7 +1067,9 @@ mod word_impl {
1024 impl_word!(u32, 32 - 1); 1067 impl_word!(u32, 32 - 1);
1025} 1068}
1026 1069
1070/// SPI instance trait.
1027pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 1071pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
1072
1028pin_trait!(SckPin, Instance); 1073pin_trait!(SckPin, Instance);
1029pin_trait!(MosiPin, Instance); 1074pin_trait!(MosiPin, Instance);
1030pin_trait!(MisoPin, Instance); 1075pin_trait!(MisoPin, Instance);
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index a0bc33944..17690aefc 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -8,14 +8,17 @@ use core::ops::{Div, Mul};
8pub struct Hertz(pub u32); 8pub struct Hertz(pub u32);
9 9
10impl Hertz { 10impl Hertz {
11 /// Create a `Hertz` from the given hertz.
11 pub const fn hz(hertz: u32) -> Self { 12 pub const fn hz(hertz: u32) -> Self {
12 Self(hertz) 13 Self(hertz)
13 } 14 }
14 15
16 /// Create a `Hertz` from the given kilohertz.
15 pub const fn khz(kilohertz: u32) -> Self { 17 pub const fn khz(kilohertz: u32) -> Self {
16 Self(kilohertz * 1_000) 18 Self(kilohertz * 1_000)
17 } 19 }
18 20
21 /// Create a `Hertz` from the given megahertz.
19 pub const fn mhz(megahertz: u32) -> Self { 22 pub const fn mhz(megahertz: u32) -> Self {
20 Self(megahertz * 1_000_000) 23 Self(megahertz * 1_000_000)
21 } 24 }
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index e2a4cc4da..9981800b2 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -43,7 +43,10 @@ type T = peripherals::TIM3;
43type T = peripherals::TIM4; 43type T = peripherals::TIM4;
44#[cfg(time_driver_tim5)] 44#[cfg(time_driver_tim5)]
45type T = peripherals::TIM5; 45type T = peripherals::TIM5;
46 46#[cfg(time_driver_tim9)]
47type T = peripherals::TIM9;
48#[cfg(time_driver_tim11)]
49type T = peripherals::TIM11;
47#[cfg(time_driver_tim12)] 50#[cfg(time_driver_tim12)]
48type T = peripherals::TIM12; 51type T = peripherals::TIM12;
49#[cfg(time_driver_tim15)] 52#[cfg(time_driver_tim15)]
@@ -82,6 +85,22 @@ foreach_interrupt! {
82 DRIVER.on_interrupt() 85 DRIVER.on_interrupt()
83 } 86 }
84 }; 87 };
88 (TIM9, timer, $block:ident, UP, $irq:ident) => {
89 #[cfg(time_driver_tim9)]
90 #[cfg(feature = "rt")]
91 #[interrupt]
92 fn $irq() {
93 DRIVER.on_interrupt()
94 }
95 };
96 (TIM11, timer, $block:ident, UP, $irq:ident) => {
97 #[cfg(time_driver_tim11)]
98 #[cfg(feature = "rt")]
99 #[interrupt]
100 fn $irq() {
101 DRIVER.on_interrupt()
102 }
103 };
85 (TIM12, timer, $block:ident, UP, $irq:ident) => { 104 (TIM12, timer, $block:ident, UP, $irq:ident) => {
86 #[cfg(time_driver_tim12)] 105 #[cfg(time_driver_tim12)]
87 #[cfg(feature = "rt")] 106 #[cfg(feature = "rt")]
@@ -455,16 +474,29 @@ impl Driver for RtcDriver {
455 return false; 474 return false;
456 } 475 }
457 476
458 let safe_timestamp = timestamp.max(t + 3);
459
460 // Write the CCR value regardless of whether we're going to enable it now or not. 477 // Write the CCR value regardless of whether we're going to enable it now or not.
461 // This way, when we enable it later, the right value is already set. 478 // This way, when we enable it later, the right value is already set.
462 r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); 479 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
463 480
464 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 481 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
465 let diff = timestamp - t; 482 let diff = timestamp - t;
466 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); 483 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
467 484
485 // Reevaluate if the alarm timestamp is still in the future
486 let t = self.now();
487 if timestamp <= t {
488 // If alarm timestamp has passed since we set it, we have a race condition and
489 // the alarm may or may not have fired.
490 // Disarm the alarm and return `false` to indicate that.
491 // It is the caller's responsibility to handle this ambiguity.
492 r.dier().modify(|w| w.set_ccie(n + 1, false));
493
494 alarm.timestamp.set(u64::MAX);
495
496 return false;
497 }
498
499 // We're confident the alarm will ring in the future.
468 true 500 true
469 }) 501 })
470 } 502 }
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 6654366cd..71d7110b5 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -1,3 +1,5 @@
1//! PWM driver with complementary output support.
2
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -11,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 13use crate::time::Hertz;
12use crate::Peripheral; 14use crate::Peripheral;
13 15
14pub struct ComplementaryPwmPin<'d, Perip, Channel> { 16/// Complementary PWM pin wrapper.
17///
18/// This wraps a pin to make it usable with PWM.
19pub struct ComplementaryPwmPin<'d, T, C> {
15 _pin: PeripheralRef<'d, AnyPin>, 20 _pin: PeripheralRef<'d, AnyPin>,
16 phantom: PhantomData<(Perip, Channel)>, 21 phantom: PhantomData<(T, C)>,
17} 22}
18 23
19macro_rules! complementary_channel_impl { 24macro_rules! complementary_channel_impl {
20 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { 26 impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
22 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { 27 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
28 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
23 into_ref!(pin); 29 into_ref!(pin);
24 critical_section::with(|_| { 30 critical_section::with(|_| {
25 pin.set_low(); 31 pin.set_low();
@@ -41,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
41complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); 47complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
42complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); 48complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
43 49
50/// PWM driver with support for standard and complementary outputs.
44pub struct ComplementaryPwm<'d, T> { 51pub struct ComplementaryPwm<'d, T> {
45 inner: PeripheralRef<'d, T>, 52 inner: PeripheralRef<'d, T>,
46} 53}
47 54
48impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver.
49 pub fn new( 57 pub fn new(
50 tim: impl Peripheral<P = T> + 'd, 58 tim: impl Peripheral<P = T> + 'd,
51 _ch1: Option<PwmPin<'d, T, Ch1>>, 59 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -70,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
70 let mut this = Self { inner: tim }; 78 let mut this = Self { inner: tim };
71 79
72 this.inner.set_counting_mode(counting_mode); 80 this.inner.set_counting_mode(counting_mode);
73 this.set_freq(freq); 81 this.set_frequency(freq);
74 this.inner.start(); 82 this.inner.start();
75 83
76 this.inner.enable_outputs(); 84 this.inner.enable_outputs();
@@ -86,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
86 this 94 this
87 } 95 }
88 96
97 /// Enable the given channel.
89 pub fn enable(&mut self, channel: Channel) { 98 pub fn enable(&mut self, channel: Channel) {
90 self.inner.enable_channel(channel, true); 99 self.inner.enable_channel(channel, true);
91 self.inner.enable_complementary_channel(channel, true); 100 self.inner.enable_complementary_channel(channel, true);
92 } 101 }
93 102
103 /// Disable the given channel.
94 pub fn disable(&mut self, channel: Channel) { 104 pub fn disable(&mut self, channel: Channel) {
95 self.inner.enable_complementary_channel(channel, false); 105 self.inner.enable_complementary_channel(channel, false);
96 self.inner.enable_channel(channel, false); 106 self.inner.enable_channel(channel, false);
97 } 107 }
98 108
99 pub fn set_freq(&mut self, freq: Hertz) { 109 /// Set PWM frequency.
110 ///
111 /// Note: when you call this, the max duty value changes, so you will have to
112 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
113 pub fn set_frequency(&mut self, freq: Hertz) {
100 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 114 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
101 2u8 115 2u8
102 } else { 116 } else {
@@ -105,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
105 self.inner.set_frequency(freq * multiplier); 119 self.inner.set_frequency(freq * multiplier);
106 } 120 }
107 121
122 /// Get max duty value.
123 ///
124 /// This value depends on the configured frequency and the timer's clock rate from RCC.
108 pub fn get_max_duty(&self) -> u16 { 125 pub fn get_max_duty(&self) -> u16 {
109 self.inner.get_max_compare_value() + 1 126 self.inner.get_max_compare_value() + 1
110 } 127 }
111 128
129 /// Set the duty for a given channel.
130 ///
131 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
112 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 132 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
113 assert!(duty <= self.get_max_duty()); 133 assert!(duty <= self.get_max_duty());
114 self.inner.set_compare_value(channel, duty) 134 self.inner.set_compare_value(channel, duty)
115 } 135 }
116 136
137 /// Set the output polarity for a given channel.
117 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 138 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
118 self.inner.set_output_polarity(channel, polarity); 139 self.inner.set_output_polarity(channel, polarity);
119 self.inner.set_complementary_output_polarity(channel, polarity); 140 self.inner.set_complementary_output_polarity(channel, polarity);
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 2313a5b94..74120adad 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,3 +1,5 @@
1//! Timers, PWM, quadrature decoder.
2
1pub mod complementary_pwm; 3pub mod complementary_pwm;
2pub mod qei; 4pub mod qei;
3pub mod simple_pwm; 5pub mod simple_pwm;
@@ -8,23 +10,34 @@ use crate::interrupt;
8use crate::rcc::RccPeripheral; 10use crate::rcc::RccPeripheral;
9use crate::time::Hertz; 11use crate::time::Hertz;
10 12
13/// Low-level timer access.
11#[cfg(feature = "unstable-pac")] 14#[cfg(feature = "unstable-pac")]
12pub mod low_level { 15pub mod low_level {
13 pub use super::sealed::*; 16 pub use super::sealed::*;
14} 17}
15 18
16pub(crate) mod sealed { 19pub(crate) mod sealed {
17
18 use super::*; 20 use super::*;
21
22 /// Basic 16-bit timer instance.
19 pub trait Basic16bitInstance: RccPeripheral { 23 pub trait Basic16bitInstance: RccPeripheral {
24 /// Interrupt for this timer.
20 type Interrupt: interrupt::typelevel::Interrupt; 25 type Interrupt: interrupt::typelevel::Interrupt;
21 26
27 /// Get access to the basic 16bit timer registers.
28 ///
29 /// Note: This works even if the timer is more capable, because registers
30 /// for the less capable timers are a subset. This allows writing a driver
31 /// for a given set of capabilities, and having it transparently work with
32 /// more capable timers.
22 fn regs() -> crate::pac::timer::TimBasic; 33 fn regs() -> crate::pac::timer::TimBasic;
23 34
35 /// Start the timer.
24 fn start(&mut self) { 36 fn start(&mut self) {
25 Self::regs().cr1().modify(|r| r.set_cen(true)); 37 Self::regs().cr1().modify(|r| r.set_cen(true));
26 } 38 }
27 39
40 /// Stop the timer.
28 fn stop(&mut self) { 41 fn stop(&mut self) {
29 Self::regs().cr1().modify(|r| r.set_cen(false)); 42 Self::regs().cr1().modify(|r| r.set_cen(false));
30 } 43 }
@@ -60,6 +73,9 @@ pub(crate) mod sealed {
60 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 73 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
61 } 74 }
62 75
76 /// Clear update interrupt.
77 ///
78 /// Returns whether the update interrupt flag was set.
63 fn clear_update_interrupt(&mut self) -> bool { 79 fn clear_update_interrupt(&mut self) -> bool {
64 let regs = Self::regs(); 80 let regs = Self::regs();
65 let sr = regs.sr().read(); 81 let sr = regs.sr().read();
@@ -73,14 +89,17 @@ pub(crate) mod sealed {
73 } 89 }
74 } 90 }
75 91
92 /// Enable/disable the update interrupt.
76 fn enable_update_interrupt(&mut self, enable: bool) { 93 fn enable_update_interrupt(&mut self, enable: bool) {
77 Self::regs().dier().write(|r| r.set_uie(enable)); 94 Self::regs().dier().write(|r| r.set_uie(enable));
78 } 95 }
79 96
80 fn set_autoreload_preload(&mut self, enable: vals::Arpe) { 97 /// Enable/disable autoreload preload.
98 fn set_autoreload_preload(&mut self, enable: bool) {
81 Self::regs().cr1().modify(|r| r.set_arpe(enable)); 99 Self::regs().cr1().modify(|r| r.set_arpe(enable));
82 } 100 }
83 101
102 /// Get the timer frequency.
84 fn get_frequency(&self) -> Hertz { 103 fn get_frequency(&self) -> Hertz {
85 let timer_f = Self::frequency(); 104 let timer_f = Self::frequency();
86 105
@@ -92,9 +111,17 @@ pub(crate) mod sealed {
92 } 111 }
93 } 112 }
94 113
114 /// Gneral-purpose 16-bit timer instance.
95 pub trait GeneralPurpose16bitInstance: Basic16bitInstance { 115 pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
116 /// Get access to the general purpose 16bit timer registers.
117 ///
118 /// Note: This works even if the timer is more capable, because registers
119 /// for the less capable timers are a subset. This allows writing a driver
120 /// for a given set of capabilities, and having it transparently work with
121 /// more capable timers.
96 fn regs_gp16() -> crate::pac::timer::TimGp16; 122 fn regs_gp16() -> crate::pac::timer::TimGp16;
97 123
124 /// Set counting mode.
98 fn set_counting_mode(&mut self, mode: CountingMode) { 125 fn set_counting_mode(&mut self, mode: CountingMode) {
99 let (cms, dir) = mode.into(); 126 let (cms, dir) = mode.into();
100 127
@@ -107,19 +134,29 @@ pub(crate) mod sealed {
107 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) 134 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
108 } 135 }
109 136
137 /// Get counting mode.
110 fn get_counting_mode(&self) -> CountingMode { 138 fn get_counting_mode(&self) -> CountingMode {
111 let cr1 = Self::regs_gp16().cr1().read(); 139 let cr1 = Self::regs_gp16().cr1().read();
112 (cr1.cms(), cr1.dir()).into() 140 (cr1.cms(), cr1.dir()).into()
113 } 141 }
114 142
143 /// Set clock divider.
115 fn set_clock_division(&mut self, ckd: vals::Ckd) { 144 fn set_clock_division(&mut self, ckd: vals::Ckd) {
116 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); 145 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
117 } 146 }
118 } 147 }
119 148
149 /// Gneral-purpose 32-bit timer instance.
120 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { 150 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
151 /// Get access to the general purpose 32bit timer registers.
152 ///
153 /// Note: This works even if the timer is more capable, because registers
154 /// for the less capable timers are a subset. This allows writing a driver
155 /// for a given set of capabilities, and having it transparently work with
156 /// more capable timers.
121 fn regs_gp32() -> crate::pac::timer::TimGp32; 157 fn regs_gp32() -> crate::pac::timer::TimGp32;
122 158
159 /// Set timer frequency.
123 fn set_frequency(&mut self, frequency: Hertz) { 160 fn set_frequency(&mut self, frequency: Hertz) {
124 let f = frequency.0; 161 let f = frequency.0;
125 assert!(f > 0); 162 assert!(f > 0);
@@ -137,6 +174,7 @@ pub(crate) mod sealed {
137 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 174 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
138 } 175 }
139 176
177 /// Get timer frequency.
140 fn get_frequency(&self) -> Hertz { 178 fn get_frequency(&self) -> Hertz {
141 let timer_f = Self::frequency(); 179 let timer_f = Self::frequency();
142 180
@@ -148,141 +186,177 @@ pub(crate) mod sealed {
148 } 186 }
149 } 187 }
150 188
189 /// Advanced control timer instance.
151 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { 190 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
191 /// Get access to the advanced timer registers.
152 fn regs_advanced() -> crate::pac::timer::TimAdv; 192 fn regs_advanced() -> crate::pac::timer::TimAdv;
153 } 193 }
154 194
195 /// Capture/Compare 16-bit timer instance.
155 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { 196 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
197 /// Set input capture filter.
156 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { 198 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
157 let raw_channel = channel.raw(); 199 let raw_channel = channel.index();
158 Self::regs_gp16() 200 Self::regs_gp16()
159 .ccmr_input(raw_channel / 2) 201 .ccmr_input(raw_channel / 2)
160 .modify(|r| r.set_icf(raw_channel % 2, icf)); 202 .modify(|r| r.set_icf(raw_channel % 2, icf));
161 } 203 }
162 204
205 /// Clear input interrupt.
163 fn clear_input_interrupt(&mut self, channel: Channel) { 206 fn clear_input_interrupt(&mut self, channel: Channel) {
164 Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false)); 207 Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
165 } 208 }
166 209
210 /// Enable input interrupt.
167 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { 211 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
168 Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable)); 212 Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
169 } 213 }
214
215 /// Set input capture prescaler.
170 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { 216 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
171 let raw_channel = channel.raw(); 217 let raw_channel = channel.index();
172 Self::regs_gp16() 218 Self::regs_gp16()
173 .ccmr_input(raw_channel / 2) 219 .ccmr_input(raw_channel / 2)
174 .modify(|r| r.set_icpsc(raw_channel % 2, factor)); 220 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
175 } 221 }
176 222
223 /// Set input TI selection.
177 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { 224 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
178 let raw_channel = channel.raw(); 225 let raw_channel = channel.index();
179 Self::regs_gp16() 226 Self::regs_gp16()
180 .ccmr_input(raw_channel / 2) 227 .ccmr_input(raw_channel / 2)
181 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); 228 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
182 } 229 }
230
231 /// Set input capture mode.
183 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { 232 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
184 Self::regs_gp16().ccer().modify(|r| match mode { 233 Self::regs_gp16().ccer().modify(|r| match mode {
185 InputCaptureMode::Rising => { 234 InputCaptureMode::Rising => {
186 r.set_ccnp(channel.raw(), false); 235 r.set_ccnp(channel.index(), false);
187 r.set_ccp(channel.raw(), false); 236 r.set_ccp(channel.index(), false);
188 } 237 }
189 InputCaptureMode::Falling => { 238 InputCaptureMode::Falling => {
190 r.set_ccnp(channel.raw(), false); 239 r.set_ccnp(channel.index(), false);
191 r.set_ccp(channel.raw(), true); 240 r.set_ccp(channel.index(), true);
192 } 241 }
193 InputCaptureMode::BothEdges => { 242 InputCaptureMode::BothEdges => {
194 r.set_ccnp(channel.raw(), true); 243 r.set_ccnp(channel.index(), true);
195 r.set_ccp(channel.raw(), true); 244 r.set_ccp(channel.index(), true);
196 } 245 }
197 }); 246 });
198 } 247 }
248
249 /// Enable timer outputs.
199 fn enable_outputs(&mut self); 250 fn enable_outputs(&mut self);
200 251
252 /// Set output compare mode.
201 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { 253 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
202 let r = Self::regs_gp16(); 254 let r = Self::regs_gp16();
203 let raw_channel: usize = channel.raw(); 255 let raw_channel: usize = channel.index();
204 r.ccmr_output(raw_channel / 2) 256 r.ccmr_output(raw_channel / 2)
205 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 257 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
206 } 258 }
207 259
260 /// Set output polarity.
208 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 261 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
209 Self::regs_gp16() 262 Self::regs_gp16()
210 .ccer() 263 .ccer()
211 .modify(|w| w.set_ccp(channel.raw(), polarity.into())); 264 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
212 } 265 }
213 266
267 /// Enable/disable a channel.
214 fn enable_channel(&mut self, channel: Channel, enable: bool) { 268 fn enable_channel(&mut self, channel: Channel, enable: bool) {
215 Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable)); 269 Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
216 } 270 }
217 271
272 /// Set compare value for a channel.
218 fn set_compare_value(&mut self, channel: Channel, value: u16) { 273 fn set_compare_value(&mut self, channel: Channel, value: u16) {
219 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 274 Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
220 } 275 }
221 276
277 /// Get capture value for a channel.
222 fn get_capture_value(&mut self, channel: Channel) -> u16 { 278 fn get_capture_value(&mut self, channel: Channel) -> u16 {
223 Self::regs_gp16().ccr(channel.raw()).read().ccr() 279 Self::regs_gp16().ccr(channel.index()).read().ccr()
224 } 280 }
225 281
282 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
226 fn get_max_compare_value(&self) -> u16 { 283 fn get_max_compare_value(&self) -> u16 {
227 Self::regs_gp16().arr().read().arr() 284 Self::regs_gp16().arr().read().arr()
228 } 285 }
229 286
287 /// Get compare value for a channel.
230 fn get_compare_value(&self, channel: Channel) -> u16 { 288 fn get_compare_value(&self, channel: Channel) -> u16 {
231 Self::regs_gp16().ccr(channel.raw()).read().ccr() 289 Self::regs_gp16().ccr(channel.index()).read().ccr()
232 } 290 }
233 } 291 }
234 292
293 /// Capture/Compare 16-bit timer instance with complementary pin support.
235 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { 294 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
295 /// Set complementary output polarity.
236 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 296 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
237 Self::regs_advanced() 297 Self::regs_advanced()
238 .ccer() 298 .ccer()
239 .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); 299 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
240 } 300 }
241 301
302 /// Set clock divider for the dead time.
242 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { 303 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
243 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 304 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
244 } 305 }
245 306
307 /// Set dead time, as a fraction of the max duty value.
246 fn set_dead_time_value(&mut self, value: u8) { 308 fn set_dead_time_value(&mut self, value: u8) {
247 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 309 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
248 } 310 }
249 311
312 /// Enable/disable a complementary channel.
250 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 313 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
251 Self::regs_advanced() 314 Self::regs_advanced()
252 .ccer() 315 .ccer()
253 .modify(|w| w.set_ccne(channel.raw(), enable)); 316 .modify(|w| w.set_ccne(channel.index(), enable));
254 } 317 }
255 } 318 }
256 319
320 /// Capture/Compare 32-bit timer instance.
257 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { 321 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
322 /// Set comapre value for a channel.
258 fn set_compare_value(&mut self, channel: Channel, value: u32) { 323 fn set_compare_value(&mut self, channel: Channel, value: u32) {
259 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 324 Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value));
260 } 325 }
261 326
327 /// Get capture value for a channel.
262 fn get_capture_value(&mut self, channel: Channel) -> u32 { 328 fn get_capture_value(&mut self, channel: Channel) -> u32 {
263 Self::regs_gp32().ccr(channel.raw()).read().ccr() 329 Self::regs_gp32().ccr(channel.index()).read().ccr()
264 } 330 }
265 331
332 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
266 fn get_max_compare_value(&self) -> u32 { 333 fn get_max_compare_value(&self) -> u32 {
267 Self::regs_gp32().arr().read().arr() 334 Self::regs_gp32().arr().read().arr()
268 } 335 }
269 336
337 /// Get compare value for a channel.
270 fn get_compare_value(&self, channel: Channel) -> u32 { 338 fn get_compare_value(&self, channel: Channel) -> u32 {
271 Self::regs_gp32().ccr(channel.raw()).read().ccr() 339 Self::regs_gp32().ccr(channel.index()).read().ccr()
272 } 340 }
273 } 341 }
274} 342}
275 343
344/// Timer channel.
276#[derive(Clone, Copy)] 345#[derive(Clone, Copy)]
277pub enum Channel { 346pub enum Channel {
347 /// Channel 1.
278 Ch1, 348 Ch1,
349 /// Channel 2.
279 Ch2, 350 Ch2,
351 /// Channel 3.
280 Ch3, 352 Ch3,
353 /// Channel 4.
281 Ch4, 354 Ch4,
282} 355}
283 356
284impl Channel { 357impl Channel {
285 pub fn raw(&self) -> usize { 358 /// Get the channel index (0..3)
359 pub fn index(&self) -> usize {
286 match self { 360 match self {
287 Channel::Ch1 => 0, 361 Channel::Ch1 => 0,
288 Channel::Ch2 => 1, 362 Channel::Ch2 => 1,
@@ -292,17 +366,25 @@ impl Channel {
292 } 366 }
293} 367}
294 368
369/// Input capture mode.
295#[derive(Clone, Copy)] 370#[derive(Clone, Copy)]
296pub enum InputCaptureMode { 371pub enum InputCaptureMode {
372 /// Rising edge only.
297 Rising, 373 Rising,
374 /// Falling edge only.
298 Falling, 375 Falling,
376 /// Both rising or falling edges.
299 BothEdges, 377 BothEdges,
300} 378}
301 379
380/// Input TI selection.
302#[derive(Clone, Copy)] 381#[derive(Clone, Copy)]
303pub enum InputTISelection { 382pub enum InputTISelection {
383 /// Normal
304 Normal, 384 Normal,
385 /// Alternate
305 Alternate, 386 Alternate,
387 /// TRC
306 TRC, 388 TRC,
307} 389}
308 390
@@ -316,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
316 } 398 }
317} 399}
318 400
401/// Timer counting mode.
319#[repr(u8)] 402#[repr(u8)]
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 403#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
321pub enum CountingMode { 404pub enum CountingMode {
@@ -342,6 +425,7 @@ pub enum CountingMode {
342} 425}
343 426
344impl CountingMode { 427impl CountingMode {
428 /// Return whether this mode is edge-aligned (up or down).
345 pub fn is_edge_aligned(&self) -> bool { 429 pub fn is_edge_aligned(&self) -> bool {
346 match self { 430 match self {
347 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, 431 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
@@ -349,6 +433,7 @@ impl CountingMode {
349 } 433 }
350 } 434 }
351 435
436 /// Return whether this mode is center-aligned.
352 pub fn is_center_aligned(&self) -> bool { 437 pub fn is_center_aligned(&self) -> bool {
353 match self { 438 match self {
354 CountingMode::CenterAlignedDownInterrupts 439 CountingMode::CenterAlignedDownInterrupts
@@ -383,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode {
383 } 468 }
384} 469}
385 470
471/// Output compare mode.
386#[derive(Clone, Copy)] 472#[derive(Clone, Copy)]
387pub enum OutputCompareMode { 473pub enum OutputCompareMode {
474 /// The comparison between the output compare register TIMx_CCRx and
475 /// the counter TIMx_CNT has no effect on the outputs.
476 /// (this mode is used to generate a timing base).
388 Frozen, 477 Frozen,
478 /// Set channel to active level on match. OCxREF signal is forced high when the
479 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
389 ActiveOnMatch, 480 ActiveOnMatch,
481 /// Set channel to inactive level on match. OCxREF signal is forced low when the
482 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
390 InactiveOnMatch, 483 InactiveOnMatch,
484 /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
391 Toggle, 485 Toggle,
486 /// Force inactive level - OCxREF is forced low.
392 ForceInactive, 487 ForceInactive,
488 /// Force active level - OCxREF is forced high.
393 ForceActive, 489 ForceActive,
490 /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
491 /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
492 /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
394 PwmMode1, 493 PwmMode1,
494 /// PWM mode 2 - In upcounting, channel is inactive as long as
495 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
496 /// TIMx_CNT>TIMx_CCRx else inactive.
395 PwmMode2, 497 PwmMode2,
498 // TODO: there's more modes here depending on the chip family.
396} 499}
397 500
398impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 501impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
@@ -410,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
410 } 513 }
411} 514}
412 515
516/// Timer output pin polarity.
413#[derive(Clone, Copy)] 517#[derive(Clone, Copy)]
414pub enum OutputPolarity { 518pub enum OutputPolarity {
519 /// Active high (higher duty value makes the pin spend more time high).
415 ActiveHigh, 520 ActiveHigh,
521 /// Active low (higher duty value makes the pin spend more time low).
416 ActiveLow, 522 ActiveLow,
417} 523}
418 524
@@ -425,24 +531,31 @@ impl From<OutputPolarity> for bool {
425 } 531 }
426} 532}
427 533
534/// Basic 16-bit timer instance.
428pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 535pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
429 536
537/// Gneral-purpose 16-bit timer instance.
430pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} 538pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
431 539
540/// Gneral-purpose 32-bit timer instance.
432pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} 541pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
433 542
543/// Advanced control timer instance.
434pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} 544pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
435 545
546/// Capture/Compare 16-bit timer instance.
436pub trait CaptureCompare16bitInstance: 547pub trait CaptureCompare16bitInstance:
437 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static 548 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
438{ 549{
439} 550}
440 551
552/// Capture/Compare 16-bit timer instance with complementary pin support.
441pub trait ComplementaryCaptureCompare16bitInstance: 553pub trait ComplementaryCaptureCompare16bitInstance:
442 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static 554 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
443{ 555{
444} 556}
445 557
558/// Capture/Compare 32-bit timer instance.
446pub trait CaptureCompare32bitInstance: 559pub trait CaptureCompare32bitInstance:
447 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static 560 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
448{ 561{
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 01d028bf9..59efb72ba 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -1,3 +1,5 @@
1//! Quadrature decoder using a timer.
2
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -7,23 +9,30 @@ use crate::gpio::sealed::AFType;
7use crate::gpio::AnyPin; 9use crate::gpio::AnyPin;
8use crate::Peripheral; 10use crate::Peripheral;
9 11
12/// Counting direction
10pub enum Direction { 13pub enum Direction {
14 /// Counting up.
11 Upcounting, 15 Upcounting,
16 /// Counting down.
12 Downcounting, 17 Downcounting,
13} 18}
14 19
15pub struct Ch1; 20/// Channel 1 marker type.
16pub struct Ch2; 21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
17 24
18pub struct QeiPin<'d, Perip, Channel> { 25/// Wrapper for using a pin with QEI.
26pub struct QeiPin<'d, T, Channel> {
19 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
20 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, Channel)>,
21} 29}
22 30
23macro_rules! channel_impl { 31macro_rules! channel_impl {
24 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
25 impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> {
26 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 34 #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")]
35 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
27 into_ref!(pin); 36 into_ref!(pin);
28 critical_section::with(|_| { 37 critical_section::with(|_| {
29 pin.set_low(); 38 pin.set_low();
@@ -43,11 +52,13 @@ macro_rules! channel_impl {
43channel_impl!(new_ch1, Ch1, Channel1Pin); 52channel_impl!(new_ch1, Ch1, Channel1Pin);
44channel_impl!(new_ch2, Ch2, Channel2Pin); 53channel_impl!(new_ch2, Ch2, Channel2Pin);
45 54
55/// Quadrature decoder driver.
46pub struct Qei<'d, T> { 56pub struct Qei<'d, T> {
47 _inner: PeripheralRef<'d, T>, 57 _inner: PeripheralRef<'d, T>,
48} 58}
49 59
50impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { 60impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
61 /// Create a new quadrature decoder driver.
51 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { 62 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
52 Self::new_inner(tim) 63 Self::new_inner(tim)
53 } 64 }
@@ -82,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
82 Self { _inner: tim } 93 Self { _inner: tim }
83 } 94 }
84 95
96 /// Get direction.
85 pub fn read_direction(&self) -> Direction { 97 pub fn read_direction(&self) -> Direction {
86 match T::regs_gp16().cr1().read().dir() { 98 match T::regs_gp16().cr1().read().dir() {
87 vals::Dir::DOWN => Direction::Downcounting, 99 vals::Dir::DOWN => Direction::Downcounting,
@@ -89,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
89 } 101 }
90 } 102 }
91 103
104 /// Get count.
92 pub fn count(&self) -> u16 { 105 pub fn count(&self) -> u16 {
93 T::regs_gp16().cnt().read().cnt() 106 T::regs_gp16().cnt().read().cnt()
94 } 107 }
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 1cf0ad728..e6072aa15 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -1,3 +1,5 @@
1//! Simple PWM driver.
2
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -9,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
9use crate::time::Hertz; 11use crate::time::Hertz;
10use crate::Peripheral; 12use crate::Peripheral;
11 13
12pub struct Ch1; 14/// Channel 1 marker type.
13pub struct Ch2; 15pub enum Ch1 {}
14pub struct Ch3; 16/// Channel 2 marker type.
15pub struct Ch4; 17pub enum Ch2 {}
16 18/// Channel 3 marker type.
17pub struct PwmPin<'d, Perip, Channel> { 19pub enum Ch3 {}
20/// Channel 4 marker type.
21pub enum Ch4 {}
22
23/// PWM pin wrapper.
24///
25/// This wraps a pin to make it usable with PWM.
26pub struct PwmPin<'d, T, C> {
18 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
19 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, C)>,
20} 29}
21 30
22macro_rules! channel_impl { 31macro_rules! channel_impl {
23 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
24 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> {
25 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { 34 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
35 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
26 into_ref!(pin); 36 into_ref!(pin);
27 critical_section::with(|_| { 37 critical_section::with(|_| {
28 pin.set_low(); 38 pin.set_low();
@@ -44,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
44channel_impl!(new_ch3, Ch3, Channel3Pin); 54channel_impl!(new_ch3, Ch3, Channel3Pin);
45channel_impl!(new_ch4, Ch4, Channel4Pin); 55channel_impl!(new_ch4, Ch4, Channel4Pin);
46 56
57/// Simple PWM driver.
47pub struct SimplePwm<'d, T> { 58pub struct SimplePwm<'d, T> {
48 inner: PeripheralRef<'d, T>, 59 inner: PeripheralRef<'d, T>,
49} 60}
50 61
51impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 62impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
63 /// Create a new simple PWM driver.
52 pub fn new( 64 pub fn new(
53 tim: impl Peripheral<P = T> + 'd, 65 tim: impl Peripheral<P = T> + 'd,
54 _ch1: Option<PwmPin<'d, T, Ch1>>, 66 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -69,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
69 let mut this = Self { inner: tim }; 81 let mut this = Self { inner: tim };
70 82
71 this.inner.set_counting_mode(counting_mode); 83 this.inner.set_counting_mode(counting_mode);
72 this.set_freq(freq); 84 this.set_frequency(freq);
73 this.inner.start(); 85 this.inner.start();
74 86
75 this.inner.enable_outputs(); 87 this.inner.enable_outputs();
@@ -85,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
85 this 97 this
86 } 98 }
87 99
100 /// Enable the given channel.
88 pub fn enable(&mut self, channel: Channel) { 101 pub fn enable(&mut self, channel: Channel) {
89 self.inner.enable_channel(channel, true); 102 self.inner.enable_channel(channel, true);
90 } 103 }
91 104
105 /// Disable the given channel.
92 pub fn disable(&mut self, channel: Channel) { 106 pub fn disable(&mut self, channel: Channel) {
93 self.inner.enable_channel(channel, false); 107 self.inner.enable_channel(channel, false);
94 } 108 }
95 109
96 pub fn set_freq(&mut self, freq: Hertz) { 110 /// Set PWM frequency.
111 ///
112 /// Note: when you call this, the max duty value changes, so you will have to
113 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
114 pub fn set_frequency(&mut self, freq: Hertz) {
97 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 115 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
98 2u8 116 2u8
99 } else { 117 } else {
@@ -102,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
102 self.inner.set_frequency(freq * multiplier); 120 self.inner.set_frequency(freq * multiplier);
103 } 121 }
104 122
123 /// Get max duty value.
124 ///
125 /// This value depends on the configured frequency and the timer's clock rate from RCC.
105 pub fn get_max_duty(&self) -> u16 { 126 pub fn get_max_duty(&self) -> u16 {
106 self.inner.get_max_compare_value() + 1 127 self.inner.get_max_compare_value() + 1
107 } 128 }
108 129
130 /// Set the duty for a given channel.
131 ///
132 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
109 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 133 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
110 assert!(duty <= self.get_max_duty()); 134 assert!(duty <= self.get_max_duty());
111 self.inner.set_compare_value(channel, duty) 135 self.inner.set_compare_value(channel, duty)
112 } 136 }
113 137
138 /// Set the output polarity for a given channel.
114 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 139 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
115 self.inner.set_output_polarity(channel, polarity); 140 self.inner.set_output_polarity(channel, polarity);
116 } 141 }
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs
index ffce7bd42..13f695821 100644
--- a/embassy-stm32/src/traits.rs
+++ b/embassy-stm32/src/traits.rs
@@ -1,16 +1,18 @@
1#![macro_use] 1#![macro_use]
2 2
3macro_rules! pin_trait { 3macro_rules! pin_trait {
4 ($signal:ident, $instance:path) => { 4 ($signal:ident, $instance:path $(, $mode:path)?) => {
5 pub trait $signal<T: $instance>: crate::gpio::Pin { 5 #[doc = concat!(stringify!($signal), " pin trait")]
6 pub trait $signal<T: $instance $(, M: $mode)?>: crate::gpio::Pin {
7 #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))]
6 fn af_num(&self) -> u8; 8 fn af_num(&self) -> u8;
7 } 9 }
8 }; 10 };
9} 11}
10 12
11macro_rules! pin_trait_impl { 13macro_rules! pin_trait_impl {
12 (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { 14 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => {
13 impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$pin { 15 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin {
14 fn af_num(&self) -> u8 { 16 fn af_num(&self) -> u8 {
15 $af 17 $af
16 } 18 }
@@ -21,8 +23,12 @@ macro_rules! pin_trait_impl {
21// ==================== 23// ====================
22 24
23macro_rules! dma_trait { 25macro_rules! dma_trait {
24 ($signal:ident, $instance:path) => { 26 ($signal:ident, $instance:path$(, $mode:path)?) => {
25 pub trait $signal<T: $instance>: crate::dma::Channel { 27 #[doc = concat!(stringify!($signal), " DMA request trait")]
28 pub trait $signal<T: $instance $(, M: $mode)?>: crate::dma::Channel {
29 #[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))]
30 /// Note: in some chips, ST calls this the "channel", and calls channels "streams".
31 /// `embassy-stm32` always uses the "channel" and "request number" names.
26 fn request(&self) -> crate::dma::Request; 32 fn request(&self) -> crate::dma::Request;
27 } 33 }
28 }; 34 };
@@ -31,8 +37,8 @@ macro_rules! dma_trait {
31#[allow(unused)] 37#[allow(unused)]
32macro_rules! dma_trait_impl { 38macro_rules! dma_trait_impl {
33 // DMAMUX 39 // DMAMUX
34 (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { 40 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => {
35 impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T 41 impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T
36 where 42 where
37 T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, 43 T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>,
38 { 44 {
@@ -43,8 +49,8 @@ macro_rules! dma_trait_impl {
43 }; 49 };
44 50
45 // DMAMUX 51 // DMAMUX
46 (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { 52 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => {
47 impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T 53 impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T
48 where 54 where
49 T: crate::dma::Channel, 55 T: crate::dma::Channel,
50 { 56 {
@@ -55,8 +61,8 @@ macro_rules! dma_trait_impl {
55 }; 61 };
56 62
57 // DMA/GPDMA, without DMAMUX 63 // DMA/GPDMA, without DMAMUX
58 (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { 64 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => {
59 impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$channel { 65 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel {
60 fn request(&self) -> crate::dma::Request { 66 fn request(&self) -> crate::dma::Request {
61 $request 67 $request
62 } 68 }
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs
index 6dcfcb96e..aa13586f8 100644
--- a/embassy-stm32/src/uid.rs
+++ b/embassy-stm32/src/uid.rs
@@ -1,3 +1,5 @@
1//! Unique ID (UID)
2
1/// Get this device's unique 96-bit ID. 3/// Get this device's unique 96-bit ID.
2pub fn uid() -> &'static [u8; 12] { 4pub fn uid() -> &'static [u8; 12] {
3 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } 5 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() }
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index a2e4ceaae..962547bd7 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -82,6 +82,7 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
82 } 82 }
83} 83}
84 84
85/// Buffered UART State
85pub struct State { 86pub struct State {
86 rx_waker: AtomicWaker, 87 rx_waker: AtomicWaker,
87 rx_buf: RingBuffer, 88 rx_buf: RingBuffer,
@@ -91,6 +92,7 @@ pub struct State {
91} 92}
92 93
93impl State { 94impl State {
95 /// Create new state
94 pub const fn new() -> Self { 96 pub const fn new() -> Self {
95 Self { 97 Self {
96 rx_buf: RingBuffer::new(), 98 rx_buf: RingBuffer::new(),
@@ -101,15 +103,18 @@ impl State {
101 } 103 }
102} 104}
103 105
106/// Bidirectional buffered UART
104pub struct BufferedUart<'d, T: BasicInstance> { 107pub struct BufferedUart<'d, T: BasicInstance> {
105 rx: BufferedUartRx<'d, T>, 108 rx: BufferedUartRx<'d, T>,
106 tx: BufferedUartTx<'d, T>, 109 tx: BufferedUartTx<'d, T>,
107} 110}
108 111
112/// Tx-only buffered UART
109pub struct BufferedUartTx<'d, T: BasicInstance> { 113pub struct BufferedUartTx<'d, T: BasicInstance> {
110 phantom: PhantomData<&'d mut T>, 114 phantom: PhantomData<&'d mut T>,
111} 115}
112 116
117/// Rx-only buffered UART
113pub struct BufferedUartRx<'d, T: BasicInstance> { 118pub struct BufferedUartRx<'d, T: BasicInstance> {
114 phantom: PhantomData<&'d mut T>, 119 phantom: PhantomData<&'d mut T>,
115} 120}
@@ -142,6 +147,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> {
142} 147}
143 148
144impl<'d, T: BasicInstance> BufferedUart<'d, T> { 149impl<'d, T: BasicInstance> BufferedUart<'d, T> {
150 /// Create a new bidirectional buffered UART driver
145 pub fn new( 151 pub fn new(
146 peri: impl Peripheral<P = T> + 'd, 152 peri: impl Peripheral<P = T> + 'd,
147 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 153 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -158,6 +164,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
158 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 164 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
159 } 165 }
160 166
167 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
161 pub fn new_with_rtscts( 168 pub fn new_with_rtscts(
162 peri: impl Peripheral<P = T> + 'd, 169 peri: impl Peripheral<P = T> + 'd,
163 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 170 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -185,6 +192,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
185 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 192 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
186 } 193 }
187 194
195 /// Create a new bidirectional buffered UART driver with a driver-enable pin
188 #[cfg(not(any(usart_v1, usart_v2)))] 196 #[cfg(not(any(usart_v1, usart_v2)))]
189 pub fn new_with_de( 197 pub fn new_with_de(
190 peri: impl Peripheral<P = T> + 'd, 198 peri: impl Peripheral<P = T> + 'd,
@@ -246,10 +254,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
246 }) 254 })
247 } 255 }
248 256
257 /// Split the driver into a Tx and Rx part (useful for sending to separate tasks)
249 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { 258 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
250 (self.tx, self.rx) 259 (self.tx, self.rx)
251 } 260 }
252 261
262 /// Reconfigure the driver
253 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 263 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
254 reconfigure::<T>(config)?; 264 reconfigure::<T>(config)?;
255 265
@@ -337,6 +347,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
337 } 347 }
338 } 348 }
339 349
350 /// Reconfigure the driver
340 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 351 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
341 reconfigure::<T>(config)?; 352 reconfigure::<T>(config)?;
342 353
@@ -418,6 +429,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
418 } 429 }
419 } 430 }
420 431
432 /// Reconfigure the driver
421 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 433 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
422 reconfigure::<T>(config)?; 434 reconfigure::<T>(config)?;
423 435
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index d5828a492..8a0c85d2c 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -1,4 +1,6 @@
1//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART)
1#![macro_use] 2#![macro_use]
3#![warn(missing_docs)]
2 4
3use core::future::poll_fn; 5use core::future::poll_fn;
4use core::marker::PhantomData; 6use core::marker::PhantomData;
@@ -76,21 +78,29 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
76 78
77#[derive(Clone, Copy, PartialEq, Eq, Debug)] 79#[derive(Clone, Copy, PartialEq, Eq, Debug)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))] 80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81/// Number of data bits
79pub enum DataBits { 82pub enum DataBits {
83 /// 8 Data Bits
80 DataBits8, 84 DataBits8,
85 /// 9 Data Bits
81 DataBits9, 86 DataBits9,
82} 87}
83 88
84#[derive(Clone, Copy, PartialEq, Eq, Debug)] 89#[derive(Clone, Copy, PartialEq, Eq, Debug)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))] 90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91/// Parity
86pub enum Parity { 92pub enum Parity {
93 /// No parity
87 ParityNone, 94 ParityNone,
95 /// Even Parity
88 ParityEven, 96 ParityEven,
97 /// Odd Parity
89 ParityOdd, 98 ParityOdd,
90} 99}
91 100
92#[derive(Clone, Copy, PartialEq, Eq, Debug)] 101#[derive(Clone, Copy, PartialEq, Eq, Debug)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))] 102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103/// Number of stop bits
94pub enum StopBits { 104pub enum StopBits {
95 #[doc = "1 stop bit"] 105 #[doc = "1 stop bit"]
96 STOP1, 106 STOP1,
@@ -105,26 +115,37 @@ pub enum StopBits {
105#[non_exhaustive] 115#[non_exhaustive]
106#[derive(Clone, Copy, PartialEq, Eq, Debug)] 116#[derive(Clone, Copy, PartialEq, Eq, Debug)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))] 117#[cfg_attr(feature = "defmt", derive(defmt::Format))]
118/// Config Error
108pub enum ConfigError { 119pub enum ConfigError {
120 /// Baudrate too low
109 BaudrateTooLow, 121 BaudrateTooLow,
122 /// Baudrate too high
110 BaudrateTooHigh, 123 BaudrateTooHigh,
124 /// Rx or Tx not enabled
111 RxOrTxNotEnabled, 125 RxOrTxNotEnabled,
112} 126}
113 127
114#[non_exhaustive] 128#[non_exhaustive]
115#[derive(Clone, Copy, PartialEq, Eq, Debug)] 129#[derive(Clone, Copy, PartialEq, Eq, Debug)]
130/// Config
116pub struct Config { 131pub struct Config {
132 /// Baud rate
117 pub baudrate: u32, 133 pub baudrate: u32,
134 /// Number of data bits
118 pub data_bits: DataBits, 135 pub data_bits: DataBits,
136 /// Number of stop bits
119 pub stop_bits: StopBits, 137 pub stop_bits: StopBits,
138 /// Parity type
120 pub parity: Parity, 139 pub parity: Parity,
121 /// if true, on read-like method, if there is a latent error pending, 140
122 /// read will abort, the error reported and cleared 141 /// If true: on a read-like method, if there is a latent error pending,
123 /// if false, the error is ignored and cleared 142 /// the read will abort and the error will be reported and cleared
143 ///
144 /// If false: the error is ignored and cleared
124 pub detect_previous_overrun: bool, 145 pub detect_previous_overrun: bool,
125 146
126 /// Set this to true if the line is considered noise free. 147 /// Set this to true if the line is considered noise free.
127 /// This will increase the receivers tolerance to clock deviations, 148 /// This will increase the receiver’s tolerance to clock deviations,
128 /// but will effectively disable noise detection. 149 /// but will effectively disable noise detection.
129 #[cfg(not(usart_v1))] 150 #[cfg(not(usart_v1))]
130 pub assume_noise_free: bool, 151 pub assume_noise_free: bool,
@@ -132,6 +153,14 @@ pub struct Config {
132 /// Set this to true to swap the RX and TX pins. 153 /// Set this to true to swap the RX and TX pins.
133 #[cfg(any(usart_v3, usart_v4))] 154 #[cfg(any(usart_v3, usart_v4))]
134 pub swap_rx_tx: bool, 155 pub swap_rx_tx: bool,
156
157 /// Set this to true to invert TX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
158 #[cfg(any(usart_v3, usart_v4))]
159 pub invert_tx: bool,
160
161 /// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
162 #[cfg(any(usart_v3, usart_v4))]
163 pub invert_rx: bool,
135} 164}
136 165
137impl Default for Config { 166impl Default for Config {
@@ -147,6 +176,10 @@ impl Default for Config {
147 assume_noise_free: false, 176 assume_noise_free: false,
148 #[cfg(any(usart_v3, usart_v4))] 177 #[cfg(any(usart_v3, usart_v4))]
149 swap_rx_tx: false, 178 swap_rx_tx: false,
179 #[cfg(any(usart_v3, usart_v4))]
180 invert_tx: false,
181 #[cfg(any(usart_v3, usart_v4))]
182 invert_rx: false,
150 } 183 }
151 } 184 }
152} 185}
@@ -175,6 +208,7 @@ enum ReadCompletionEvent {
175 Idle(usize), 208 Idle(usize),
176} 209}
177 210
211/// Bidirectional UART Driver
178pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { 212pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
179 tx: UartTx<'d, T, TxDma>, 213 tx: UartTx<'d, T, TxDma>,
180 rx: UartRx<'d, T, RxDma>, 214 rx: UartRx<'d, T, RxDma>,
@@ -190,6 +224,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma>
190 } 224 }
191} 225}
192 226
227/// Tx-only UART Driver
193pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { 228pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
194 phantom: PhantomData<&'d mut T>, 229 phantom: PhantomData<&'d mut T>,
195 tx_dma: PeripheralRef<'d, TxDma>, 230 tx_dma: PeripheralRef<'d, TxDma>,
@@ -204,6 +239,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
204 } 239 }
205} 240}
206 241
242/// Rx-only UART Driver
207pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { 243pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
208 _peri: PeripheralRef<'d, T>, 244 _peri: PeripheralRef<'d, T>,
209 rx_dma: PeripheralRef<'d, RxDma>, 245 rx_dma: PeripheralRef<'d, RxDma>,
@@ -234,6 +270,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
234 Self::new_inner(peri, tx, tx_dma, config) 270 Self::new_inner(peri, tx, tx_dma, config)
235 } 271 }
236 272
273 /// Create a new tx-only UART with a clear-to-send pin
237 pub fn new_with_cts( 274 pub fn new_with_cts(
238 peri: impl Peripheral<P = T> + 'd, 275 peri: impl Peripheral<P = T> + 'd,
239 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 276 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@@ -275,10 +312,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
275 }) 312 })
276 } 313 }
277 314
315 /// Reconfigure the driver
278 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 316 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
279 reconfigure::<T>(config) 317 reconfigure::<T>(config)
280 } 318 }
281 319
320 /// Initiate an asynchronous UART write
282 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> 321 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
283 where 322 where
284 TxDma: crate::usart::TxDma<T>, 323 TxDma: crate::usart::TxDma<T>,
@@ -295,6 +334,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
295 Ok(()) 334 Ok(())
296 } 335 }
297 336
337 /// Perform a blocking UART write
298 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 338 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
299 let r = T::regs(); 339 let r = T::regs();
300 for &b in buffer { 340 for &b in buffer {
@@ -304,6 +344,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
304 Ok(()) 344 Ok(())
305 } 345 }
306 346
347 /// Block until transmission complete
307 pub fn blocking_flush(&mut self) -> Result<(), Error> { 348 pub fn blocking_flush(&mut self) -> Result<(), Error> {
308 let r = T::regs(); 349 let r = T::regs();
309 while !sr(r).read().tc() {} 350 while !sr(r).read().tc() {}
@@ -325,6 +366,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
325 Self::new_inner(peri, rx, rx_dma, config) 366 Self::new_inner(peri, rx, rx_dma, config)
326 } 367 }
327 368
369 /// Create a new rx-only UART with a request-to-send pin
328 pub fn new_with_rts( 370 pub fn new_with_rts(
329 peri: impl Peripheral<P = T> + 'd, 371 peri: impl Peripheral<P = T> + 'd,
330 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 372 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -374,6 +416,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
374 }) 416 })
375 } 417 }
376 418
419 /// Reconfigure the driver
377 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 420 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
378 reconfigure::<T>(config) 421 reconfigure::<T>(config)
379 } 422 }
@@ -431,6 +474,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
431 Ok(sr.rxne()) 474 Ok(sr.rxne())
432 } 475 }
433 476
477 /// Initiate an asynchronous UART read
434 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> 478 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
435 where 479 where
436 RxDma: crate::usart::RxDma<T>, 480 RxDma: crate::usart::RxDma<T>,
@@ -440,6 +484,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
440 Ok(()) 484 Ok(())
441 } 485 }
442 486
487 /// Read a single u8 if there is one available, otherwise return WouldBlock
443 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 488 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
444 let r = T::regs(); 489 let r = T::regs();
445 if self.check_rx_flags()? { 490 if self.check_rx_flags()? {
@@ -449,6 +494,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
449 } 494 }
450 } 495 }
451 496
497 /// Perform a blocking read into `buffer`
452 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 498 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
453 let r = T::regs(); 499 let r = T::regs();
454 for b in buffer { 500 for b in buffer {
@@ -458,6 +504,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
458 Ok(()) 504 Ok(())
459 } 505 }
460 506
507 /// Initiate an asynchronous read with idle line detection enabled
461 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> 508 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
462 where 509 where
463 RxDma: crate::usart::RxDma<T>, 510 RxDma: crate::usart::RxDma<T>,
@@ -682,6 +729,7 @@ impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> {
682} 729}
683 730
684impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { 731impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
732 /// Create a new bidirectional UART
685 pub fn new( 733 pub fn new(
686 peri: impl Peripheral<P = T> + 'd, 734 peri: impl Peripheral<P = T> + 'd,
687 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 735 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -698,6 +746,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
698 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 746 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
699 } 747 }
700 748
749 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
701 pub fn new_with_rtscts( 750 pub fn new_with_rtscts(
702 peri: impl Peripheral<P = T> + 'd, 751 peri: impl Peripheral<P = T> + 'd,
703 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 752 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -725,6 +774,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
725 } 774 }
726 775
727 #[cfg(not(any(usart_v1, usart_v2)))] 776 #[cfg(not(any(usart_v1, usart_v2)))]
777 /// Create a new bidirectional UART with a driver-enable pin
728 pub fn new_with_de( 778 pub fn new_with_de(
729 peri: impl Peripheral<P = T> + 'd, 779 peri: impl Peripheral<P = T> + 'd,
730 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 780 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -800,6 +850,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
800 }) 850 })
801 } 851 }
802 852
853 /// Initiate an asynchronous write
803 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> 854 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
804 where 855 where
805 TxDma: crate::usart::TxDma<T>, 856 TxDma: crate::usart::TxDma<T>,
@@ -807,14 +858,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
807 self.tx.write(buffer).await 858 self.tx.write(buffer).await
808 } 859 }
809 860
861 /// Perform a blocking write
810 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 862 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
811 self.tx.blocking_write(buffer) 863 self.tx.blocking_write(buffer)
812 } 864 }
813 865
866 /// Block until transmission complete
814 pub fn blocking_flush(&mut self) -> Result<(), Error> { 867 pub fn blocking_flush(&mut self) -> Result<(), Error> {
815 self.tx.blocking_flush() 868 self.tx.blocking_flush()
816 } 869 }
817 870
871 /// Initiate an asynchronous read into `buffer`
818 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> 872 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
819 where 873 where
820 RxDma: crate::usart::RxDma<T>, 874 RxDma: crate::usart::RxDma<T>,
@@ -822,14 +876,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
822 self.rx.read(buffer).await 876 self.rx.read(buffer).await
823 } 877 }
824 878
879 /// Read a single `u8` or return `WouldBlock`
825 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 880 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
826 self.rx.nb_read() 881 self.rx.nb_read()
827 } 882 }
828 883
884 /// Perform a blocking read into `buffer`
829 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 885 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
830 self.rx.blocking_read(buffer) 886 self.rx.blocking_read(buffer)
831 } 887 }
832 888
889 /// Initiate an an asynchronous read with idle line detection enabled
833 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> 890 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
834 where 891 where
835 RxDma: crate::usart::RxDma<T>, 892 RxDma: crate::usart::RxDma<T>,
@@ -972,7 +1029,11 @@ fn configure(
972 }); 1029 });
973 1030
974 #[cfg(any(usart_v3, usart_v4))] 1031 #[cfg(any(usart_v3, usart_v4))]
975 w.set_swap(config.swap_rx_tx); 1032 {
1033 w.set_txinv(config.invert_tx);
1034 w.set_rxinv(config.invert_rx);
1035 w.set_swap(config.swap_rx_tx);
1036 }
976 }); 1037 });
977 1038
978 #[cfg(not(usart_v1))] 1039 #[cfg(not(usart_v1))]
@@ -1275,8 +1336,10 @@ pub(crate) mod sealed {
1275 } 1336 }
1276} 1337}
1277 1338
1339/// Basic UART driver instance
1278pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} 1340pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
1279 1341
1342/// Full UART driver instance
1280pub trait FullInstance: sealed::FullInstance {} 1343pub trait FullInstance: sealed::FullInstance {}
1281 1344
1282pin_trait!(RxPin, BasicInstance); 1345pin_trait!(RxPin, BasicInstance);
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b8d17e4e4..4391bfef7 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -11,6 +11,7 @@ use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config,
11use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
12use crate::usart::{Regs, Sr}; 12use crate::usart::{Regs, Sr};
13 13
14/// Rx-only Ring-buffered UART Driver
14pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { 15pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> {
15 _peri: PeripheralRef<'d, T>, 16 _peri: PeripheralRef<'d, T>,
16 ring_buf: ReadableRingBuffer<'d, RxDma, u8>, 17 ring_buf: ReadableRingBuffer<'d, RxDma, u8>,
@@ -27,8 +28,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUar
27 28
28impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { 29impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
29 /// Turn the `UartRx` into a buffered uart which can continously receive in the background 30 /// Turn the `UartRx` into a buffered uart which can continously receive in the background
30 /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the 31 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
31 /// DMA controller, and must be sufficiently large, such that it will not overflow. 32 /// DMA controller, and must be large enough to prevent overflows.
32 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { 33 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> {
33 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 34 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
34 35
@@ -39,7 +40,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
39 let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; 40 let rx_dma = unsafe { self.rx_dma.clone_unchecked() };
40 let _peri = unsafe { self._peri.clone_unchecked() }; 41 let _peri = unsafe { self._peri.clone_unchecked() };
41 42
42 let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; 43 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
43 44
44 // Don't disable the clock 45 // Don't disable the clock
45 mem::forget(self); 46 mem::forget(self);
@@ -49,6 +50,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
49} 50}
50 51
51impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> { 52impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> {
53 /// Clear the ring buffer and start receiving in the background
52 pub fn start(&mut self) -> Result<(), Error> { 54 pub fn start(&mut self) -> Result<(), Error> {
53 // Clear the ring buffer so that it is ready to receive data 55 // Clear the ring buffer so that it is ready to receive data
54 self.ring_buf.clear(); 56 self.ring_buf.clear();
@@ -64,6 +66,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
64 Err(err) 66 Err(err)
65 } 67 }
66 68
69 /// Cleanly stop and reconfigure the driver
67 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 70 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
68 self.teardown_uart(); 71 self.teardown_uart();
69 reconfigure::<T>(config) 72 reconfigure::<T>(config)
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index d0b289462..4debd4e54 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -1,3 +1,5 @@
1//! Universal Serial Bus (USB)
2
1use crate::interrupt; 3use crate::interrupt;
2use crate::rcc::RccPeripheral; 4use crate::rcc::RccPeripheral;
3 5
@@ -10,7 +12,9 @@ pub(crate) mod sealed {
10 } 12 }
11} 13}
12 14
15/// USB instance trait.
13pub trait Instance: sealed::Instance + RccPeripheral + 'static { 16pub trait Instance: sealed::Instance + RccPeripheral + 'static {
17 /// Interrupt for this USB instance.
14 type Interrupt: interrupt::typelevel::Interrupt; 18 type Interrupt: interrupt::typelevel::Interrupt;
15} 19}
16 20
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 295dc9198..04b1b35e8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -244,6 +244,7 @@ struct EndpointData {
244 used_out: bool, 244 used_out: bool,
245} 245}
246 246
247/// USB driver.
247pub struct Driver<'d, T: Instance> { 248pub struct Driver<'d, T: Instance> {
248 phantom: PhantomData<&'d mut T>, 249 phantom: PhantomData<&'d mut T>,
249 alloc: [EndpointData; EP_COUNT], 250 alloc: [EndpointData; EP_COUNT],
@@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> {
251} 252}
252 253
253impl<'d, T: Instance> Driver<'d, T> { 254impl<'d, T: Instance> Driver<'d, T> {
255 /// Create a new USB driver.
254 pub fn new( 256 pub fn new(
255 _usb: impl Peripheral<P = T> + 'd, 257 _usb: impl Peripheral<P = T> + 'd,
256 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 258 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
465 } 467 }
466} 468}
467 469
470/// USB bus.
468pub struct Bus<'d, T: Instance> { 471pub struct Bus<'d, T: Instance> {
469 phantom: PhantomData<&'d mut T>, 472 phantom: PhantomData<&'d mut T>,
470 ep_types: [EpType; EP_COUNT - 1], 473 ep_types: [EpType; EP_COUNT - 1],
@@ -640,6 +643,7 @@ trait Dir {
640 fn waker(i: usize) -> &'static AtomicWaker; 643 fn waker(i: usize) -> &'static AtomicWaker;
641} 644}
642 645
646/// Marker type for the "IN" direction.
643pub enum In {} 647pub enum In {}
644impl Dir for In { 648impl Dir for In {
645 fn dir() -> Direction { 649 fn dir() -> Direction {
@@ -652,6 +656,7 @@ impl Dir for In {
652 } 656 }
653} 657}
654 658
659/// Marker type for the "OUT" direction.
655pub enum Out {} 660pub enum Out {}
656impl Dir for Out { 661impl Dir for Out {
657 fn dir() -> Direction { 662 fn dir() -> Direction {
@@ -664,6 +669,7 @@ impl Dir for Out {
664 } 669 }
665} 670}
666 671
672/// USB endpoint.
667pub struct Endpoint<'d, T: Instance, D> { 673pub struct Endpoint<'d, T: Instance, D> {
668 _phantom: PhantomData<(&'d mut T, D)>, 674 _phantom: PhantomData<(&'d mut T, D)>,
669 info: EndpointInfo, 675 info: EndpointInfo,
@@ -695,10 +701,10 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
695 } 701 }
696 702
697 async fn wait_enabled(&mut self) { 703 async fn wait_enabled(&mut self) {
698 trace!("wait_enabled OUT WAITING"); 704 trace!("wait_enabled IN WAITING");
699 let index = self.info.addr.index(); 705 let index = self.info.addr.index();
700 poll_fn(|cx| { 706 poll_fn(|cx| {
701 EP_OUT_WAKERS[index].register(cx.waker()); 707 EP_IN_WAKERS[index].register(cx.waker());
702 let regs = T::regs(); 708 let regs = T::regs();
703 if regs.epr(index).read().stat_tx() == Stat::DISABLED { 709 if regs.epr(index).read().stat_tx() == Stat::DISABLED {
704 Poll::Pending 710 Poll::Pending
@@ -707,7 +713,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
707 } 713 }
708 }) 714 })
709 .await; 715 .await;
710 trace!("wait_enabled OUT OK"); 716 trace!("wait_enabled IN OK");
711 } 717 }
712} 718}
713 719
@@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
813 } 819 }
814} 820}
815 821
822/// USB control pipe.
816pub struct ControlPipe<'d, T: Instance> { 823pub struct ControlPipe<'d, T: Instance> {
817 _phantom: PhantomData<&'d mut T>, 824 _phantom: PhantomData<&'d mut T>,
818 max_packet_size: u16, 825 max_packet_size: u16,
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs
index be54a3d10..0649e684b 100644
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ b/embassy-stm32/src/usb_otg/mod.rs
@@ -1,3 +1,5 @@
1//! USB On The Go (OTG)
2
1use crate::rcc::RccPeripheral; 3use crate::rcc::RccPeripheral;
2use crate::{interrupt, peripherals}; 4use crate::{interrupt, peripherals};
3 5
@@ -18,7 +20,9 @@ pub(crate) mod sealed {
18 } 20 }
19} 21}
20 22
23/// USB OTG instance.
21pub trait Instance: sealed::Instance + RccPeripheral { 24pub trait Instance: sealed::Instance + RccPeripheral {
25 /// Interrupt for this USB OTG instance.
22 type Interrupt: interrupt::typelevel::Interrupt; 26 type Interrupt: interrupt::typelevel::Interrupt;
23} 27}
24 28
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index ba77bfb16..190fb274f 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -204,6 +204,7 @@ pub enum PhyType {
204} 204}
205 205
206impl PhyType { 206impl PhyType {
207 /// Get whether this PHY is any of the internal types.
207 pub fn internal(&self) -> bool { 208 pub fn internal(&self) -> bool {
208 match self { 209 match self {
209 PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, 210 PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
@@ -211,6 +212,7 @@ impl PhyType {
211 } 212 }
212 } 213 }
213 214
215 /// Get whether this PHY is any of the high-speed types.
214 pub fn high_speed(&self) -> bool { 216 pub fn high_speed(&self) -> bool {
215 match self { 217 match self {
216 PhyType::InternalFullSpeed => false, 218 PhyType::InternalFullSpeed => false,
@@ -218,7 +220,7 @@ impl PhyType {
218 } 220 }
219 } 221 }
220 222
221 pub fn to_dspd(&self) -> vals::Dspd { 223 fn to_dspd(&self) -> vals::Dspd {
222 match self { 224 match self {
223 PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, 225 PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
224 PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, 226 PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
@@ -230,6 +232,7 @@ impl PhyType {
230/// Indicates that [State::ep_out_buffers] is empty. 232/// Indicates that [State::ep_out_buffers] is empty.
231const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; 233const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
232 234
235/// USB OTG driver state.
233pub struct State<const EP_COUNT: usize> { 236pub struct State<const EP_COUNT: usize> {
234 /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. 237 /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true.
235 ep0_setup_data: UnsafeCell<[u8; 8]>, 238 ep0_setup_data: UnsafeCell<[u8; 8]>,
@@ -247,6 +250,7 @@ unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {}
247unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {} 250unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {}
248 251
249impl<const EP_COUNT: usize> State<EP_COUNT> { 252impl<const EP_COUNT: usize> State<EP_COUNT> {
253 /// Create a new State.
250 pub const fn new() -> Self { 254 pub const fn new() -> Self {
251 const NEW_AW: AtomicWaker = AtomicWaker::new(); 255 const NEW_AW: AtomicWaker = AtomicWaker::new();
252 const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); 256 const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _);
@@ -271,6 +275,7 @@ struct EndpointData {
271 fifo_size_words: u16, 275 fifo_size_words: u16,
272} 276}
273 277
278/// USB driver config.
274#[non_exhaustive] 279#[non_exhaustive]
275#[derive(Clone, Copy, PartialEq, Eq, Debug)] 280#[derive(Clone, Copy, PartialEq, Eq, Debug)]
276pub struct Config { 281pub struct Config {
@@ -297,6 +302,7 @@ impl Default for Config {
297 } 302 }
298} 303}
299 304
305/// USB driver.
300pub struct Driver<'d, T: Instance> { 306pub struct Driver<'d, T: Instance> {
301 config: Config, 307 config: Config,
302 phantom: PhantomData<&'d mut T>, 308 phantom: PhantomData<&'d mut T>,
@@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
527 } 533 }
528} 534}
529 535
536/// USB bus.
530pub struct Bus<'d, T: Instance> { 537pub struct Bus<'d, T: Instance> {
531 config: Config, 538 config: Config,
532 phantom: PhantomData<&'d mut T>, 539 phantom: PhantomData<&'d mut T>,
@@ -1092,6 +1099,7 @@ trait Dir {
1092 fn dir() -> Direction; 1099 fn dir() -> Direction;
1093} 1100}
1094 1101
1102/// Marker type for the "IN" direction.
1095pub enum In {} 1103pub enum In {}
1096impl Dir for In { 1104impl Dir for In {
1097 fn dir() -> Direction { 1105 fn dir() -> Direction {
@@ -1099,6 +1107,7 @@ impl Dir for In {
1099 } 1107 }
1100} 1108}
1101 1109
1110/// Marker type for the "OUT" direction.
1102pub enum Out {} 1111pub enum Out {}
1103impl Dir for Out { 1112impl Dir for Out {
1104 fn dir() -> Direction { 1113 fn dir() -> Direction {
@@ -1106,6 +1115,7 @@ impl Dir for Out {
1106 } 1115 }
1107} 1116}
1108 1117
1118/// USB endpoint.
1109pub struct Endpoint<'d, T: Instance, D> { 1119pub struct Endpoint<'d, T: Instance, D> {
1110 _phantom: PhantomData<(&'d mut T, D)>, 1120 _phantom: PhantomData<(&'d mut T, D)>,
1111 info: EndpointInfo, 1121 info: EndpointInfo,
@@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1299 } 1309 }
1300} 1310}
1301 1311
1312/// USB control pipe.
1302pub struct ControlPipe<'d, T: Instance> { 1313pub struct ControlPipe<'d, T: Instance> {
1303 _phantom: PhantomData<&'d mut T>, 1314 _phantom: PhantomData<&'d mut T>,
1304 max_packet_size: u16, 1315 max_packet_size: u16,
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index c7c2694e0..dc701ef64 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -1,3 +1,4 @@
1//! Watchdog Timer (IWDG, WWDG)
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2 3
3use embassy_hal_internal::{into_ref, Peripheral}; 4use embassy_hal_internal::{into_ref, Peripheral};
@@ -5,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr};
5 6
6use crate::rcc::LSI_FREQ; 7use crate::rcc::LSI_FREQ;
7 8
9/// Independent watchdog (IWDG) driver.
8pub struct IndependentWatchdog<'d, T: Instance> { 10pub struct IndependentWatchdog<'d, T: Instance> {
9 wdg: PhantomData<&'d mut T>, 11 wdg: PhantomData<&'d mut T>,
10} 12}
@@ -63,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
63 IndependentWatchdog { wdg: PhantomData } 65 IndependentWatchdog { wdg: PhantomData }
64 } 66 }
65 67
68 /// Unleash (start) the watchdog.
66 pub fn unleash(&mut self) { 69 pub fn unleash(&mut self) {
67 T::regs().kr().write(|w| w.set_key(Key::START)); 70 T::regs().kr().write(|w| w.set_key(Key::START));
68 } 71 }
69 72
73 /// Pet (reload, refresh) the watchdog.
70 pub fn pet(&mut self) { 74 pub fn pet(&mut self) {
71 T::regs().kr().write(|w| w.set_key(Key::RESET)); 75 T::regs().kr().write(|w| w.set_key(Key::RESET));
72 } 76 }
@@ -78,6 +82,7 @@ mod sealed {
78 } 82 }
79} 83}
80 84
85/// IWDG instance trait.
81pub trait Instance: sealed::Instance {} 86pub trait Instance: sealed::Instance {}
82 87
83foreach_peripheral!( 88foreach_peripheral!(
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index bea67d8be..d75750ce7 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -111,6 +111,20 @@ where
111 poll_fn(move |cx| self.poll_wait(cx)) 111 poll_fn(move |cx| self.poll_wait(cx))
112 } 112 }
113 113
114 /// non-blocking method to try and take the signal value.
115 pub fn try_take(&self) -> Option<T> {
116 self.state.lock(|cell| {
117 let state = cell.replace(State::None);
118 match state {
119 State::Signaled(res) => Some(res),
120 state => {
121 cell.set(state);
122 None
123 }
124 }
125 })
126 }
127
114 /// non-blocking method to check whether this signal has been signaled. 128 /// non-blocking method to check whether this signal has been signaled.
115 pub fn signaled(&self) -> bool { 129 pub fn signaled(&self) -> bool {
116 self.state.lock(|cell| { 130 self.state.lock(|cell| {
diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md
index d8c0c7d08..99f6ef7ac 100644
--- a/embassy-time/CHANGELOG.md
+++ b/embassy-time/CHANGELOG.md
@@ -24,8 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
24 24
25## 0.1.3 - 2023-08-28 25## 0.1.3 - 2023-08-28
26 26
27- Update `embedded-hal-async` to `1.0.0-rc.2` 27- Update `embedded-hal-async` to `1.0.0-rc.3`
28- Update `embedded-hal v1` to `1.0.0-rc.2` 28- Update `embedded-hal v1` to `1.0.0-rc.3`
29 29
30## 0.1.2 - 2023-07-05 30## 0.1.2 - 2023-07-05
31 31
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 94e79382f..7259169cd 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -32,217 +32,391 @@ features = ["defmt", "std"]
32std = ["tick-hz-1_000_000", "critical-section/std"] 32std = ["tick-hz-1_000_000", "critical-section/std"]
33wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] 33wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"]
34 34
35# Display a timestamp of the number of seconds since startup next to defmt log messages 35## Display a timestamp of the number of seconds since startup next to defmt log messages
36# To use this you must have a time driver provided. 36## To use this you must have a time driver provided.
37defmt-timestamp-uptime = ["defmt"] 37defmt-timestamp-uptime = ["defmt"]
38 38
39# Create a global, generic queue that can be used with any executor 39## Create a `MockDriver` that can be manually advanced for testing purposes.
40# To use this you must have a time driver provided. 40mock-driver = ["tick-hz-1_000_000"]
41
42#! ### Generic Queue
43
44## Create a global, generic queue that can be used with any executor.
45## To use this you must have a time driver provided.
41generic-queue = [] 46generic-queue = []
42 47
43# Set the number of timers for the generic queue. 48#! The following features set how many timers are used for the generic queue. At most one
44# 49#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used.
45# At most 1 `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. 50#!
46# 51#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the
47# When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the 52#! end user to pick.
48# end user to pick. 53
54## Generic Queue with 8 timers
49generic-queue-8 = ["generic-queue"] 55generic-queue-8 = ["generic-queue"]
56## Generic Queue with 16 timers
50generic-queue-16 = ["generic-queue"] 57generic-queue-16 = ["generic-queue"]
58## Generic Queue with 32 timers
51generic-queue-32 = ["generic-queue"] 59generic-queue-32 = ["generic-queue"]
60## Generic Queue with 64 timers
52generic-queue-64 = ["generic-queue"] 61generic-queue-64 = ["generic-queue"]
62## Generic Queue with 128 timers
53generic-queue-128 = ["generic-queue"] 63generic-queue-128 = ["generic-queue"]
54 64
55# Create a `MockDriver` that can be manually advanced for testing purposes. 65#! ### Tick Rate
56mock-driver = ["tick-hz-1_000_000"] 66#!
57 67#! At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used.
58# Set the `embassy_time` tick rate. 68#!
59# 69#! If the time driver in use supports using arbitrary tick rates, you can enable one `tick-*`
60# At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. 70#! feature from your binary crate to set the tick rate. The driver will use configured tick rate.
61# 71#! If the time driver supports a fixed tick rate, it will enable one feature itself, so you should
62# If the time driver in use supports using arbitrary tick rates, you can enable one `tick-*` 72#! not enable one. Check the time driver documentation for details.
63# feature from your binary crate to set the tick rate. The driver will use configured tick rate. 73#!
64# If the time driver supports a fixed tick rate, it will enable one feature itself, so you should 74#! When using embassy-time from libraries, you should *not* enable any `tick-*` feature, to allow the
65# not enable one. Check the time driver documentation for details. 75#! end user or the driver to pick.
66# 76#! <details>
67# When using embassy-time from libraries, you should *not* enable any `tick-*` feature, to allow the 77#! <summary>Available tick rates:</summary>
68# end user or the driver to pick. 78#! <!-- Next line must be left empty for the features to render correctly! -->
79#!
69 80
70# BEGIN TICKS 81# BEGIN TICKS
71# Generated by gen_tick.py. DO NOT EDIT. 82# Generated by gen_tick.py. DO NOT EDIT.
83## 1Hz Tick Rate
72tick-hz-1 = [] 84tick-hz-1 = []
73tick-hz-10 = [] 85## 2Hz Tick Rate
74tick-hz-100 = []
75tick-hz-1_000 = []
76tick-hz-10_000 = []
77tick-hz-100_000 = []
78tick-hz-1_000_000 = []
79tick-hz-10_000_000 = []
80tick-hz-100_000_000 = []
81tick-hz-1_000_000_000 = []
82tick-hz-2 = [] 86tick-hz-2 = []
87## 4Hz Tick Rate
83tick-hz-4 = [] 88tick-hz-4 = []
89## 8Hz Tick Rate
84tick-hz-8 = [] 90tick-hz-8 = []
91## 10Hz Tick Rate
92tick-hz-10 = []
93## 16Hz Tick Rate
85tick-hz-16 = [] 94tick-hz-16 = []
95## 32Hz Tick Rate
86tick-hz-32 = [] 96tick-hz-32 = []
97## 64Hz Tick Rate
87tick-hz-64 = [] 98tick-hz-64 = []
99## 100Hz Tick Rate
100tick-hz-100 = []
101## 128Hz Tick Rate
88tick-hz-128 = [] 102tick-hz-128 = []
103## 256Hz Tick Rate
89tick-hz-256 = [] 104tick-hz-256 = []
105## 512Hz Tick Rate
90tick-hz-512 = [] 106tick-hz-512 = []
107## 1.0kHz Tick Rate
108tick-hz-1_000 = []
109## 1.024kHz Tick Rate
91tick-hz-1_024 = [] 110tick-hz-1_024 = []
92tick-hz-2_048 = [] 111## 2.0kHz Tick Rate
93tick-hz-4_096 = []
94tick-hz-8_192 = []
95tick-hz-16_384 = []
96tick-hz-32_768 = []
97tick-hz-65_536 = []
98tick-hz-131_072 = []
99tick-hz-262_144 = []
100tick-hz-524_288 = []
101tick-hz-1_048_576 = []
102tick-hz-2_097_152 = []
103tick-hz-4_194_304 = []
104tick-hz-8_388_608 = []
105tick-hz-16_777_216 = []
106tick-hz-2_000 = [] 112tick-hz-2_000 = []
113## 2.048kHz Tick Rate
114tick-hz-2_048 = []
115## 4.0kHz Tick Rate
107tick-hz-4_000 = [] 116tick-hz-4_000 = []
117## 4.096kHz Tick Rate
118tick-hz-4_096 = []
119## 8.0kHz Tick Rate
108tick-hz-8_000 = [] 120tick-hz-8_000 = []
121## 8.192kHz Tick Rate
122tick-hz-8_192 = []
123## 10.0kHz Tick Rate
124tick-hz-10_000 = []
125## 16.0kHz Tick Rate
109tick-hz-16_000 = [] 126tick-hz-16_000 = []
110tick-hz-32_000 = [] 127## 16.384kHz Tick Rate
111tick-hz-64_000 = [] 128tick-hz-16_384 = []
112tick-hz-128_000 = [] 129## 20.0kHz Tick Rate
113tick-hz-256_000 = []
114tick-hz-512_000 = []
115tick-hz-1_024_000 = []
116tick-hz-2_048_000 = []
117tick-hz-4_096_000 = []
118tick-hz-8_192_000 = []
119tick-hz-16_384_000 = []
120tick-hz-32_768_000 = []
121tick-hz-65_536_000 = []
122tick-hz-131_072_000 = []
123tick-hz-262_144_000 = []
124tick-hz-524_288_000 = []
125tick-hz-20_000 = [] 130tick-hz-20_000 = []
131## 32.0kHz Tick Rate
132tick-hz-32_000 = []
133## 32.768kHz Tick Rate
134tick-hz-32_768 = []
135## 40.0kHz Tick Rate
126tick-hz-40_000 = [] 136tick-hz-40_000 = []
137## 64.0kHz Tick Rate
138tick-hz-64_000 = []
139## 65.536kHz Tick Rate
140tick-hz-65_536 = []
141## 80.0kHz Tick Rate
127tick-hz-80_000 = [] 142tick-hz-80_000 = []
143## 100.0kHz Tick Rate
144tick-hz-100_000 = []
145## 128.0kHz Tick Rate
146tick-hz-128_000 = []
147## 131.072kHz Tick Rate
148tick-hz-131_072 = []
149## 160.0kHz Tick Rate
128tick-hz-160_000 = [] 150tick-hz-160_000 = []
151## 256.0kHz Tick Rate
152tick-hz-256_000 = []
153## 262.144kHz Tick Rate
154tick-hz-262_144 = []
155## 320.0kHz Tick Rate
129tick-hz-320_000 = [] 156tick-hz-320_000 = []
157## 512.0kHz Tick Rate
158tick-hz-512_000 = []
159## 524.288kHz Tick Rate
160tick-hz-524_288 = []
161## 640.0kHz Tick Rate
130tick-hz-640_000 = [] 162tick-hz-640_000 = []
163## 1.0MHz Tick Rate
164tick-hz-1_000_000 = []
165## 1.024MHz Tick Rate
166tick-hz-1_024_000 = []
167## 1.048576MHz Tick Rate
168tick-hz-1_048_576 = []
169## 1.28MHz Tick Rate
131tick-hz-1_280_000 = [] 170tick-hz-1_280_000 = []
132tick-hz-2_560_000 = [] 171## 2.0MHz Tick Rate
133tick-hz-5_120_000 = []
134tick-hz-10_240_000 = []
135tick-hz-20_480_000 = []
136tick-hz-40_960_000 = []
137tick-hz-81_920_000 = []
138tick-hz-163_840_000 = []
139tick-hz-327_680_000 = []
140tick-hz-655_360_000 = []
141tick-hz-1_310_720_000 = []
142tick-hz-2_621_440_000 = []
143tick-hz-5_242_880_000 = []
144tick-hz-2_000_000 = [] 172tick-hz-2_000_000 = []
173## 2.048MHz Tick Rate
174tick-hz-2_048_000 = []
175## 2.097152MHz Tick Rate
176tick-hz-2_097_152 = []
177## 2.56MHz Tick Rate
178tick-hz-2_560_000 = []
179## 3.0MHz Tick Rate
145tick-hz-3_000_000 = [] 180tick-hz-3_000_000 = []
181## 4.0MHz Tick Rate
146tick-hz-4_000_000 = [] 182tick-hz-4_000_000 = []
183## 4.096MHz Tick Rate
184tick-hz-4_096_000 = []
185## 4.194304MHz Tick Rate
186tick-hz-4_194_304 = []
187## 5.12MHz Tick Rate
188tick-hz-5_120_000 = []
189## 6.0MHz Tick Rate
147tick-hz-6_000_000 = [] 190tick-hz-6_000_000 = []
191## 8.0MHz Tick Rate
148tick-hz-8_000_000 = [] 192tick-hz-8_000_000 = []
193## 8.192MHz Tick Rate
194tick-hz-8_192_000 = []
195## 8.388608MHz Tick Rate
196tick-hz-8_388_608 = []
197## 9.0MHz Tick Rate
149tick-hz-9_000_000 = [] 198tick-hz-9_000_000 = []
199## 10.0MHz Tick Rate
200tick-hz-10_000_000 = []
201## 10.24MHz Tick Rate
202tick-hz-10_240_000 = []
203## 12.0MHz Tick Rate
150tick-hz-12_000_000 = [] 204tick-hz-12_000_000 = []
205## 16.0MHz Tick Rate
151tick-hz-16_000_000 = [] 206tick-hz-16_000_000 = []
207## 16.384MHz Tick Rate
208tick-hz-16_384_000 = []
209## 16.777216MHz Tick Rate
210tick-hz-16_777_216 = []
211## 18.0MHz Tick Rate
152tick-hz-18_000_000 = [] 212tick-hz-18_000_000 = []
213## 20.0MHz Tick Rate
214tick-hz-20_000_000 = []
215## 20.48MHz Tick Rate
216tick-hz-20_480_000 = []
217## 24.0MHz Tick Rate
153tick-hz-24_000_000 = [] 218tick-hz-24_000_000 = []
219## 30.0MHz Tick Rate
220tick-hz-30_000_000 = []
221## 32.0MHz Tick Rate
154tick-hz-32_000_000 = [] 222tick-hz-32_000_000 = []
223## 32.768MHz Tick Rate
224tick-hz-32_768_000 = []
225## 36.0MHz Tick Rate
155tick-hz-36_000_000 = [] 226tick-hz-36_000_000 = []
156tick-hz-48_000_000 = [] 227## 40.0MHz Tick Rate
157tick-hz-64_000_000 = []
158tick-hz-72_000_000 = []
159tick-hz-96_000_000 = []
160tick-hz-128_000_000 = []
161tick-hz-144_000_000 = []
162tick-hz-192_000_000 = []
163tick-hz-256_000_000 = []
164tick-hz-288_000_000 = []
165tick-hz-384_000_000 = []
166tick-hz-512_000_000 = []
167tick-hz-576_000_000 = []
168tick-hz-768_000_000 = []
169tick-hz-20_000_000 = []
170tick-hz-30_000_000 = []
171tick-hz-40_000_000 = [] 228tick-hz-40_000_000 = []
229## 40.96MHz Tick Rate
230tick-hz-40_960_000 = []
231## 48.0MHz Tick Rate
232tick-hz-48_000_000 = []
233## 50.0MHz Tick Rate
172tick-hz-50_000_000 = [] 234tick-hz-50_000_000 = []
235## 60.0MHz Tick Rate
173tick-hz-60_000_000 = [] 236tick-hz-60_000_000 = []
237## 64.0MHz Tick Rate
238tick-hz-64_000_000 = []
239## 65.536MHz Tick Rate
240tick-hz-65_536_000 = []
241## 70.0MHz Tick Rate
174tick-hz-70_000_000 = [] 242tick-hz-70_000_000 = []
243## 72.0MHz Tick Rate
244tick-hz-72_000_000 = []
245## 80.0MHz Tick Rate
175tick-hz-80_000_000 = [] 246tick-hz-80_000_000 = []
247## 81.92MHz Tick Rate
248tick-hz-81_920_000 = []
249## 90.0MHz Tick Rate
176tick-hz-90_000_000 = [] 250tick-hz-90_000_000 = []
251## 96.0MHz Tick Rate
252tick-hz-96_000_000 = []
253## 100.0MHz Tick Rate
254tick-hz-100_000_000 = []
255## 110.0MHz Tick Rate
177tick-hz-110_000_000 = [] 256tick-hz-110_000_000 = []
257## 120.0MHz Tick Rate
178tick-hz-120_000_000 = [] 258tick-hz-120_000_000 = []
259## 128.0MHz Tick Rate
260tick-hz-128_000_000 = []
261## 130.0MHz Tick Rate
179tick-hz-130_000_000 = [] 262tick-hz-130_000_000 = []
263## 131.072MHz Tick Rate
264tick-hz-131_072_000 = []
265## 140.0MHz Tick Rate
180tick-hz-140_000_000 = [] 266tick-hz-140_000_000 = []
267## 144.0MHz Tick Rate
268tick-hz-144_000_000 = []
269## 150.0MHz Tick Rate
181tick-hz-150_000_000 = [] 270tick-hz-150_000_000 = []
271## 160.0MHz Tick Rate
182tick-hz-160_000_000 = [] 272tick-hz-160_000_000 = []
273## 163.84MHz Tick Rate
274tick-hz-163_840_000 = []
275## 170.0MHz Tick Rate
183tick-hz-170_000_000 = [] 276tick-hz-170_000_000 = []
277## 180.0MHz Tick Rate
184tick-hz-180_000_000 = [] 278tick-hz-180_000_000 = []
279## 190.0MHz Tick Rate
185tick-hz-190_000_000 = [] 280tick-hz-190_000_000 = []
281## 192.0MHz Tick Rate
282tick-hz-192_000_000 = []
283## 200.0MHz Tick Rate
186tick-hz-200_000_000 = [] 284tick-hz-200_000_000 = []
285## 210.0MHz Tick Rate
187tick-hz-210_000_000 = [] 286tick-hz-210_000_000 = []
287## 220.0MHz Tick Rate
188tick-hz-220_000_000 = [] 288tick-hz-220_000_000 = []
289## 230.0MHz Tick Rate
189tick-hz-230_000_000 = [] 290tick-hz-230_000_000 = []
291## 240.0MHz Tick Rate
190tick-hz-240_000_000 = [] 292tick-hz-240_000_000 = []
293## 250.0MHz Tick Rate
191tick-hz-250_000_000 = [] 294tick-hz-250_000_000 = []
295## 256.0MHz Tick Rate
296tick-hz-256_000_000 = []
297## 260.0MHz Tick Rate
192tick-hz-260_000_000 = [] 298tick-hz-260_000_000 = []
299## 262.144MHz Tick Rate
300tick-hz-262_144_000 = []
301## 270.0MHz Tick Rate
193tick-hz-270_000_000 = [] 302tick-hz-270_000_000 = []
303## 280.0MHz Tick Rate
194tick-hz-280_000_000 = [] 304tick-hz-280_000_000 = []
305## 288.0MHz Tick Rate
306tick-hz-288_000_000 = []
307## 290.0MHz Tick Rate
195tick-hz-290_000_000 = [] 308tick-hz-290_000_000 = []
309## 300.0MHz Tick Rate
196tick-hz-300_000_000 = [] 310tick-hz-300_000_000 = []
311## 320.0MHz Tick Rate
197tick-hz-320_000_000 = [] 312tick-hz-320_000_000 = []
313## 327.68MHz Tick Rate
314tick-hz-327_680_000 = []
315## 340.0MHz Tick Rate
198tick-hz-340_000_000 = [] 316tick-hz-340_000_000 = []
317## 360.0MHz Tick Rate
199tick-hz-360_000_000 = [] 318tick-hz-360_000_000 = []
319## 380.0MHz Tick Rate
200tick-hz-380_000_000 = [] 320tick-hz-380_000_000 = []
321## 384.0MHz Tick Rate
322tick-hz-384_000_000 = []
323## 400.0MHz Tick Rate
201tick-hz-400_000_000 = [] 324tick-hz-400_000_000 = []
325## 420.0MHz Tick Rate
202tick-hz-420_000_000 = [] 326tick-hz-420_000_000 = []
327## 440.0MHz Tick Rate
203tick-hz-440_000_000 = [] 328tick-hz-440_000_000 = []
329## 460.0MHz Tick Rate
204tick-hz-460_000_000 = [] 330tick-hz-460_000_000 = []
331## 480.0MHz Tick Rate
205tick-hz-480_000_000 = [] 332tick-hz-480_000_000 = []
333## 500.0MHz Tick Rate
206tick-hz-500_000_000 = [] 334tick-hz-500_000_000 = []
335## 512.0MHz Tick Rate
336tick-hz-512_000_000 = []
337## 520.0MHz Tick Rate
207tick-hz-520_000_000 = [] 338tick-hz-520_000_000 = []
339## 524.288MHz Tick Rate
340tick-hz-524_288_000 = []
341## 540.0MHz Tick Rate
208tick-hz-540_000_000 = [] 342tick-hz-540_000_000 = []
343## 560.0MHz Tick Rate
209tick-hz-560_000_000 = [] 344tick-hz-560_000_000 = []
345## 576.0MHz Tick Rate
346tick-hz-576_000_000 = []
347## 580.0MHz Tick Rate
210tick-hz-580_000_000 = [] 348tick-hz-580_000_000 = []
349## 600.0MHz Tick Rate
211tick-hz-600_000_000 = [] 350tick-hz-600_000_000 = []
351## 620.0MHz Tick Rate
212tick-hz-620_000_000 = [] 352tick-hz-620_000_000 = []
353## 640.0MHz Tick Rate
213tick-hz-640_000_000 = [] 354tick-hz-640_000_000 = []
355## 655.36MHz Tick Rate
356tick-hz-655_360_000 = []
357## 660.0MHz Tick Rate
214tick-hz-660_000_000 = [] 358tick-hz-660_000_000 = []
359## 680.0MHz Tick Rate
215tick-hz-680_000_000 = [] 360tick-hz-680_000_000 = []
361## 700.0MHz Tick Rate
216tick-hz-700_000_000 = [] 362tick-hz-700_000_000 = []
363## 720.0MHz Tick Rate
217tick-hz-720_000_000 = [] 364tick-hz-720_000_000 = []
365## 740.0MHz Tick Rate
218tick-hz-740_000_000 = [] 366tick-hz-740_000_000 = []
367## 760.0MHz Tick Rate
219tick-hz-760_000_000 = [] 368tick-hz-760_000_000 = []
369## 768.0MHz Tick Rate
370tick-hz-768_000_000 = []
371## 780.0MHz Tick Rate
220tick-hz-780_000_000 = [] 372tick-hz-780_000_000 = []
373## 800.0MHz Tick Rate
221tick-hz-800_000_000 = [] 374tick-hz-800_000_000 = []
375## 820.0MHz Tick Rate
222tick-hz-820_000_000 = [] 376tick-hz-820_000_000 = []
377## 840.0MHz Tick Rate
223tick-hz-840_000_000 = [] 378tick-hz-840_000_000 = []
379## 860.0MHz Tick Rate
224tick-hz-860_000_000 = [] 380tick-hz-860_000_000 = []
381## 880.0MHz Tick Rate
225tick-hz-880_000_000 = [] 382tick-hz-880_000_000 = []
383## 900.0MHz Tick Rate
226tick-hz-900_000_000 = [] 384tick-hz-900_000_000 = []
385## 920.0MHz Tick Rate
227tick-hz-920_000_000 = [] 386tick-hz-920_000_000 = []
387## 940.0MHz Tick Rate
228tick-hz-940_000_000 = [] 388tick-hz-940_000_000 = []
389## 960.0MHz Tick Rate
229tick-hz-960_000_000 = [] 390tick-hz-960_000_000 = []
391## 980.0MHz Tick Rate
230tick-hz-980_000_000 = [] 392tick-hz-980_000_000 = []
393## 1.0GHz Tick Rate
394tick-hz-1_000_000_000 = []
395## 1.31072GHz Tick Rate
396tick-hz-1_310_720_000 = []
397## 2.62144GHz Tick Rate
398tick-hz-2_621_440_000 = []
399## 5.24288GHz Tick Rate
400tick-hz-5_242_880_000 = []
231# END TICKS 401# END TICKS
232 402
403#! </details>
404
233[dependencies] 405[dependencies]
234defmt = { version = "0.3", optional = true } 406defmt = { version = "0.3", optional = true }
235log = { version = "0.4.14", optional = true } 407log = { version = "0.4.14", optional = true }
236 408
237embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } 409embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
238embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 410embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
239embedded-hal-async = { version = "=1.0.0-rc.2" } 411embedded-hal-async = { version = "=1.0.0-rc.3" }
240 412
241futures-util = { version = "0.3.17", default-features = false } 413futures-util = { version = "0.3.17", default-features = false }
242critical-section = "1.1" 414critical-section = "1.1"
243cfg-if = "1.0.0" 415cfg-if = "1.0.0"
244heapless = "0.8" 416heapless = "0.8"
245 417
418document-features = "0.2.7"
419
246# WASM dependencies 420# WASM dependencies
247wasm-bindgen = { version = "0.2.81", optional = true } 421wasm-bindgen = { version = "0.2.81", optional = true }
248js-sys = { version = "0.3", optional = true } 422js-sys = { version = "0.3", optional = true }
diff --git a/embassy-time/README.md b/embassy-time/README.md
index 2be80ff9c..a4e150c14 100644
--- a/embassy-time/README.md
+++ b/embassy-time/README.md
@@ -3,25 +3,40 @@
3Timekeeping, delays and timeouts. 3Timekeeping, delays and timeouts.
4 4
5Timekeeping is done with elapsed time since system boot. Time is represented in 5Timekeeping is done with elapsed time since system boot. Time is represented in
6ticks, where the tick rate is defined by the current driver, usually to match 6ticks, where the tick rate is defined either by the driver (in the case of a fixed-rate
7the tick rate of the hardware. 7tick) or chosen by the user with a [tick rate](#tick-rate) feature. The chosen
8tick rate applies to everything in `embassy-time` and thus determines the maximum
9timing resolution of <code>(1 / tick_rate) seconds</code>.
8 10
9Tick counts are 64 bits. At the highest supported tick rate of 1Mhz this supports 11Tick counts are 64 bits. The default tick rate of 1Mhz supports
10representing time spans of up to ~584558 years, which is big enough for all practical 12representing time spans of up to ~584558 years, which is big enough for all practical
11purposes and allows not having to worry about overflows. 13purposes and allows not having to worry about overflows.
12 14
15## Time driver
16
17The `time` module is backed by a global "time driver" specified at build time.
18Only one driver can be active in a program.
19
20All methods and structs transparently call into the active driver. This makes it
21possible for libraries to use `embassy_time` in a driver-agnostic way without
22requiring generic parameters.
23
24For more details, check the [`driver`] module.
25
26## Instants and Durations
27
13[`Instant`] represents a given instant of time (relative to system boot), and [`Duration`] 28[`Instant`] represents a given instant of time (relative to system boot), and [`Duration`]
14represents the duration of a span of time. They implement the math operations you'd expect, 29represents the duration of a span of time. They implement the math operations you'd expect,
15like addition and substraction. 30like addition and substraction.
16 31
17# Delays and timeouts 32## Delays and timeouts
18 33
19[`Timer`] allows performing async delays. [`Ticker`] allows periodic delays without drifting over time. 34[`Timer`] allows performing async delays. [`Ticker`] allows periodic delays without drifting over time.
20 35
21An implementation of the `embedded-hal` delay traits is provided by [`Delay`], for compatibility 36An implementation of the `embedded-hal` delay traits is provided by [`Delay`], for compatibility
22with libraries from the ecosystem. 37with libraries from the ecosystem.
23 38
24# Wall-clock time 39## Wall-clock time
25 40
26The `time` module deals exclusively with a monotonically increasing tick count. 41The `time` module deals exclusively with a monotonically increasing tick count.
27Therefore it has no direct support for wall-clock time ("real life" datetimes 42Therefore it has no direct support for wall-clock time ("real life" datetimes
@@ -30,14 +45,3 @@ like `2021-08-24 13:33:21`).
30If persistence across reboots is not needed, support can be built on top of 45If persistence across reboots is not needed, support can be built on top of
31`embassy_time` by storing the offset between "seconds elapsed since boot" 46`embassy_time` by storing the offset between "seconds elapsed since boot"
32and "seconds since unix epoch". 47and "seconds since unix epoch".
33
34# Time driver
35
36The `time` module is backed by a global "time driver" specified at build time.
37Only one driver can be active in a program.
38
39All methods and structs transparently call into the active driver. This makes it
40possible for libraries to use `embassy_time` in a driver-agnostic way without
41requiring generic parameters.
42
43For more details, check the [`driver`] module.
diff --git a/embassy-time/gen_tick.py b/embassy-time/gen_tick.py
index d4a175914..8961fb7e6 100644
--- a/embassy-time/gen_tick.py
+++ b/embassy-time/gen_tick.py
@@ -1,5 +1,4 @@
1import os 1import os
2import toml
3from glob import glob 2from glob import glob
4 3
5abspath = os.path.abspath(__file__) 4abspath = os.path.abspath(__file__)
@@ -25,11 +24,11 @@ for i in range(15, 50):
25 ticks.append(20 * i * 1_000_000) 24 ticks.append(20 * i * 1_000_000)
26 25
27seen = set() 26seen = set()
28ticks = [x for x in ticks if not (x in seen or seen.add(x))] 27ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))])
29 28
30# ========= Update Cargo.toml 29# ========= Update Cargo.toml
31 30
32things = {f'tick-hz-{hz:_}': [] for hz in ticks} 31things = [(hz, f'tick-hz-{hz:_}') for hz in ticks]
33 32
34SEPARATOR_START = '# BEGIN TICKS\n' 33SEPARATOR_START = '# BEGIN TICKS\n'
35SEPARATOR_END = '# END TICKS\n' 34SEPARATOR_END = '# END TICKS\n'
@@ -38,8 +37,22 @@ with open('Cargo.toml', 'r') as f:
38 data = f.read() 37 data = f.read()
39before, data = data.split(SEPARATOR_START, maxsplit=1) 38before, data = data.split(SEPARATOR_START, maxsplit=1)
40_, after = data.split(SEPARATOR_END, maxsplit=1) 39_, after = data.split(SEPARATOR_END, maxsplit=1)
41data = before + SEPARATOR_START + HELP + \ 40
42 toml.dumps(things) + SEPARATOR_END + after 41data = before + SEPARATOR_START + HELP
42for freq, feature in things:
43 if freq >= 1_000_000_000:
44 freq_human = f"{freq / 1_000_000_000}GHz"
45 elif freq >= 1_000_000:
46 freq_human = f"{freq / 1_000_000}MHz"
47 elif freq >= 1_000:
48 freq_human = f"{freq / 1000}kHz"
49 else:
50 freq_human = f"{freq}Hz"
51
52 data += f"## {freq_human} Tick Rate\n"
53 data += f"{feature} = []\n"
54data += SEPARATOR_END + after
55
43with open('Cargo.toml', 'w') as f: 56with open('Cargo.toml', 'w') as f:
44 f.write(data) 57 f.write(data)
45 58
diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs
index 5fe7becaf..2afa454fe 100644
--- a/embassy-time/src/driver.rs
+++ b/embassy-time/src/driver.rs
@@ -7,11 +7,16 @@
7//! - Define a struct `MyDriver` 7//! - Define a struct `MyDriver`
8//! - Implement [`Driver`] for it 8//! - Implement [`Driver`] for it
9//! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl). 9//! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl).
10//! - Enable the Cargo features `embassy-executor/time` and one of `embassy-time/tick-*` corresponding to the 10//! - Enable the Cargo feature `embassy-executor/time`
11//! tick rate of your driver.
12//! 11//!
13//! If you wish to make the tick rate configurable by the end user, you should do so by exposing your own 12//! If your driver has a single set tick rate, enable the corresponding [`tick-hz-*`](crate#tick-rate) feature,
14//! Cargo features and having each enable the corresponding `embassy-time/tick-*`. 13//! which will prevent users from needing to configure it themselves (or selecting an incorrect configuration).
14//!
15//! If your driver supports a small number of set tick rates, expose your own cargo features and have each one
16//! enable the corresponding `embassy-time/tick-*`.
17//!
18//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by
19//! enabling a feature on `embassy-time`.
15//! 20//!
16//! # Linkage details 21//! # Linkage details
17//! 22//!
@@ -108,6 +113,10 @@ pub trait Driver: Send + Sync + 'static {
108 /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. 113 /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`.
109 /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set, 114 /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set,
110 /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously. 115 /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously.
116 /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the
117 /// past. This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false`
118 /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the
119 /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.)
111 /// 120 ///
112 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. 121 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
113 /// 122 ///
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index 82a7ee0df..a59ee68d2 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -6,6 +6,9 @@
6#![allow(clippy::new_without_default)] 6#![allow(clippy::new_without_default)]
7#![warn(missing_docs)] 7#![warn(missing_docs)]
8 8
9//! ## Feature flags
10#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
11
9// This mod MUST go first, so that the others see its macros. 12// This mod MUST go first, so that the others see its macros.
10pub(crate) mod fmt; 13pub(crate) mod fmt;
11 14
@@ -37,10 +40,7 @@ pub use timer::{with_timeout, Ticker, TimeoutError, Timer};
37 40
38/// Ticks per second of the global timebase. 41/// Ticks per second of the global timebase.
39/// 42///
40/// This value is specified by the `tick-*` Cargo features, which 43/// This value is specified by the [`tick-*` Cargo features](crate#tick-rate)
41/// should be set by the time driver. Some drivers support a fixed tick rate, others
42/// allow you to choose a tick rate with Cargo features of their own. You should not
43/// set the `tick-*` features for embassy yourself as an end user.
44pub const TICK_HZ: u64 = tick::TICK_HZ; 44pub const TICK_HZ: u64 = tick::TICK_HZ;
45 45
46const fn gcd(a: u64, b: u64) -> u64 { 46const fn gcd(a: u64, b: u64) -> u64 {
diff --git a/embassy-time/src/tick.rs b/embassy-time/src/tick.rs
index 834e7c095..916ae9498 100644
--- a/embassy-time/src/tick.rs
+++ b/embassy-time/src/tick.rs
@@ -2,232 +2,204 @@
2 2
3#[cfg(feature = "tick-hz-1")] 3#[cfg(feature = "tick-hz-1")]
4pub const TICK_HZ: u64 = 1; 4pub const TICK_HZ: u64 = 1;
5#[cfg(feature = "tick-hz-10")]
6pub const TICK_HZ: u64 = 10;
7#[cfg(feature = "tick-hz-100")]
8pub const TICK_HZ: u64 = 100;
9#[cfg(feature = "tick-hz-1_000")]
10pub const TICK_HZ: u64 = 1_000;
11#[cfg(feature = "tick-hz-10_000")]
12pub const TICK_HZ: u64 = 10_000;
13#[cfg(feature = "tick-hz-100_000")]
14pub const TICK_HZ: u64 = 100_000;
15#[cfg(feature = "tick-hz-1_000_000")]
16pub const TICK_HZ: u64 = 1_000_000;
17#[cfg(feature = "tick-hz-10_000_000")]
18pub const TICK_HZ: u64 = 10_000_000;
19#[cfg(feature = "tick-hz-100_000_000")]
20pub const TICK_HZ: u64 = 100_000_000;
21#[cfg(feature = "tick-hz-1_000_000_000")]
22pub const TICK_HZ: u64 = 1_000_000_000;
23#[cfg(feature = "tick-hz-2")] 5#[cfg(feature = "tick-hz-2")]
24pub const TICK_HZ: u64 = 2; 6pub const TICK_HZ: u64 = 2;
25#[cfg(feature = "tick-hz-4")] 7#[cfg(feature = "tick-hz-4")]
26pub const TICK_HZ: u64 = 4; 8pub const TICK_HZ: u64 = 4;
27#[cfg(feature = "tick-hz-8")] 9#[cfg(feature = "tick-hz-8")]
28pub const TICK_HZ: u64 = 8; 10pub const TICK_HZ: u64 = 8;
11#[cfg(feature = "tick-hz-10")]
12pub const TICK_HZ: u64 = 10;
29#[cfg(feature = "tick-hz-16")] 13#[cfg(feature = "tick-hz-16")]
30pub const TICK_HZ: u64 = 16; 14pub const TICK_HZ: u64 = 16;
31#[cfg(feature = "tick-hz-32")] 15#[cfg(feature = "tick-hz-32")]
32pub const TICK_HZ: u64 = 32; 16pub const TICK_HZ: u64 = 32;
33#[cfg(feature = "tick-hz-64")] 17#[cfg(feature = "tick-hz-64")]
34pub const TICK_HZ: u64 = 64; 18pub const TICK_HZ: u64 = 64;
19#[cfg(feature = "tick-hz-100")]
20pub const TICK_HZ: u64 = 100;
35#[cfg(feature = "tick-hz-128")] 21#[cfg(feature = "tick-hz-128")]
36pub const TICK_HZ: u64 = 128; 22pub const TICK_HZ: u64 = 128;
37#[cfg(feature = "tick-hz-256")] 23#[cfg(feature = "tick-hz-256")]
38pub const TICK_HZ: u64 = 256; 24pub const TICK_HZ: u64 = 256;
39#[cfg(feature = "tick-hz-512")] 25#[cfg(feature = "tick-hz-512")]
40pub const TICK_HZ: u64 = 512; 26pub const TICK_HZ: u64 = 512;
27#[cfg(feature = "tick-hz-1_000")]
28pub const TICK_HZ: u64 = 1_000;
41#[cfg(feature = "tick-hz-1_024")] 29#[cfg(feature = "tick-hz-1_024")]
42pub const TICK_HZ: u64 = 1_024; 30pub const TICK_HZ: u64 = 1_024;
43#[cfg(feature = "tick-hz-2_048")]
44pub const TICK_HZ: u64 = 2_048;
45#[cfg(feature = "tick-hz-4_096")]
46pub const TICK_HZ: u64 = 4_096;
47#[cfg(feature = "tick-hz-8_192")]
48pub const TICK_HZ: u64 = 8_192;
49#[cfg(feature = "tick-hz-16_384")]
50pub const TICK_HZ: u64 = 16_384;
51#[cfg(feature = "tick-hz-32_768")]
52pub const TICK_HZ: u64 = 32_768;
53#[cfg(feature = "tick-hz-65_536")]
54pub const TICK_HZ: u64 = 65_536;
55#[cfg(feature = "tick-hz-131_072")]
56pub const TICK_HZ: u64 = 131_072;
57#[cfg(feature = "tick-hz-262_144")]
58pub const TICK_HZ: u64 = 262_144;
59#[cfg(feature = "tick-hz-524_288")]
60pub const TICK_HZ: u64 = 524_288;
61#[cfg(feature = "tick-hz-1_048_576")]
62pub const TICK_HZ: u64 = 1_048_576;
63#[cfg(feature = "tick-hz-2_097_152")]
64pub const TICK_HZ: u64 = 2_097_152;
65#[cfg(feature = "tick-hz-4_194_304")]
66pub const TICK_HZ: u64 = 4_194_304;
67#[cfg(feature = "tick-hz-8_388_608")]
68pub const TICK_HZ: u64 = 8_388_608;
69#[cfg(feature = "tick-hz-16_777_216")]
70pub const TICK_HZ: u64 = 16_777_216;
71#[cfg(feature = "tick-hz-2_000")] 31#[cfg(feature = "tick-hz-2_000")]
72pub const TICK_HZ: u64 = 2_000; 32pub const TICK_HZ: u64 = 2_000;
33#[cfg(feature = "tick-hz-2_048")]
34pub const TICK_HZ: u64 = 2_048;
73#[cfg(feature = "tick-hz-4_000")] 35#[cfg(feature = "tick-hz-4_000")]
74pub const TICK_HZ: u64 = 4_000; 36pub const TICK_HZ: u64 = 4_000;
37#[cfg(feature = "tick-hz-4_096")]
38pub const TICK_HZ: u64 = 4_096;
75#[cfg(feature = "tick-hz-8_000")] 39#[cfg(feature = "tick-hz-8_000")]
76pub const TICK_HZ: u64 = 8_000; 40pub const TICK_HZ: u64 = 8_000;
41#[cfg(feature = "tick-hz-8_192")]
42pub const TICK_HZ: u64 = 8_192;
43#[cfg(feature = "tick-hz-10_000")]
44pub const TICK_HZ: u64 = 10_000;
77#[cfg(feature = "tick-hz-16_000")] 45#[cfg(feature = "tick-hz-16_000")]
78pub const TICK_HZ: u64 = 16_000; 46pub const TICK_HZ: u64 = 16_000;
79#[cfg(feature = "tick-hz-32_000")] 47#[cfg(feature = "tick-hz-16_384")]
80pub const TICK_HZ: u64 = 32_000; 48pub const TICK_HZ: u64 = 16_384;
81#[cfg(feature = "tick-hz-64_000")]
82pub const TICK_HZ: u64 = 64_000;
83#[cfg(feature = "tick-hz-128_000")]
84pub const TICK_HZ: u64 = 128_000;
85#[cfg(feature = "tick-hz-256_000")]
86pub const TICK_HZ: u64 = 256_000;
87#[cfg(feature = "tick-hz-512_000")]
88pub const TICK_HZ: u64 = 512_000;
89#[cfg(feature = "tick-hz-1_024_000")]
90pub const TICK_HZ: u64 = 1_024_000;
91#[cfg(feature = "tick-hz-2_048_000")]
92pub const TICK_HZ: u64 = 2_048_000;
93#[cfg(feature = "tick-hz-4_096_000")]
94pub const TICK_HZ: u64 = 4_096_000;
95#[cfg(feature = "tick-hz-8_192_000")]
96pub const TICK_HZ: u64 = 8_192_000;
97#[cfg(feature = "tick-hz-16_384_000")]
98pub const TICK_HZ: u64 = 16_384_000;
99#[cfg(feature = "tick-hz-32_768_000")]
100pub const TICK_HZ: u64 = 32_768_000;
101#[cfg(feature = "tick-hz-65_536_000")]
102pub const TICK_HZ: u64 = 65_536_000;
103#[cfg(feature = "tick-hz-131_072_000")]
104pub const TICK_HZ: u64 = 131_072_000;
105#[cfg(feature = "tick-hz-262_144_000")]
106pub const TICK_HZ: u64 = 262_144_000;
107#[cfg(feature = "tick-hz-524_288_000")]
108pub const TICK_HZ: u64 = 524_288_000;
109#[cfg(feature = "tick-hz-20_000")] 49#[cfg(feature = "tick-hz-20_000")]
110pub const TICK_HZ: u64 = 20_000; 50pub const TICK_HZ: u64 = 20_000;
51#[cfg(feature = "tick-hz-32_000")]
52pub const TICK_HZ: u64 = 32_000;
53#[cfg(feature = "tick-hz-32_768")]
54pub const TICK_HZ: u64 = 32_768;
111#[cfg(feature = "tick-hz-40_000")] 55#[cfg(feature = "tick-hz-40_000")]
112pub const TICK_HZ: u64 = 40_000; 56pub const TICK_HZ: u64 = 40_000;
57#[cfg(feature = "tick-hz-64_000")]
58pub const TICK_HZ: u64 = 64_000;
59#[cfg(feature = "tick-hz-65_536")]
60pub const TICK_HZ: u64 = 65_536;
113#[cfg(feature = "tick-hz-80_000")] 61#[cfg(feature = "tick-hz-80_000")]
114pub const TICK_HZ: u64 = 80_000; 62pub const TICK_HZ: u64 = 80_000;
63#[cfg(feature = "tick-hz-100_000")]
64pub const TICK_HZ: u64 = 100_000;
65#[cfg(feature = "tick-hz-128_000")]
66pub const TICK_HZ: u64 = 128_000;
67#[cfg(feature = "tick-hz-131_072")]
68pub const TICK_HZ: u64 = 131_072;
115#[cfg(feature = "tick-hz-160_000")] 69#[cfg(feature = "tick-hz-160_000")]
116pub const TICK_HZ: u64 = 160_000; 70pub const TICK_HZ: u64 = 160_000;
71#[cfg(feature = "tick-hz-256_000")]
72pub const TICK_HZ: u64 = 256_000;
73#[cfg(feature = "tick-hz-262_144")]
74pub const TICK_HZ: u64 = 262_144;
117#[cfg(feature = "tick-hz-320_000")] 75#[cfg(feature = "tick-hz-320_000")]
118pub const TICK_HZ: u64 = 320_000; 76pub const TICK_HZ: u64 = 320_000;
77#[cfg(feature = "tick-hz-512_000")]
78pub const TICK_HZ: u64 = 512_000;
79#[cfg(feature = "tick-hz-524_288")]
80pub const TICK_HZ: u64 = 524_288;
119#[cfg(feature = "tick-hz-640_000")] 81#[cfg(feature = "tick-hz-640_000")]
120pub const TICK_HZ: u64 = 640_000; 82pub const TICK_HZ: u64 = 640_000;
83#[cfg(feature = "tick-hz-1_000_000")]
84pub const TICK_HZ: u64 = 1_000_000;
85#[cfg(feature = "tick-hz-1_024_000")]
86pub const TICK_HZ: u64 = 1_024_000;
87#[cfg(feature = "tick-hz-1_048_576")]
88pub const TICK_HZ: u64 = 1_048_576;
121#[cfg(feature = "tick-hz-1_280_000")] 89#[cfg(feature = "tick-hz-1_280_000")]
122pub const TICK_HZ: u64 = 1_280_000; 90pub const TICK_HZ: u64 = 1_280_000;
123#[cfg(feature = "tick-hz-2_560_000")]
124pub const TICK_HZ: u64 = 2_560_000;
125#[cfg(feature = "tick-hz-5_120_000")]
126pub const TICK_HZ: u64 = 5_120_000;
127#[cfg(feature = "tick-hz-10_240_000")]
128pub const TICK_HZ: u64 = 10_240_000;
129#[cfg(feature = "tick-hz-20_480_000")]
130pub const TICK_HZ: u64 = 20_480_000;
131#[cfg(feature = "tick-hz-40_960_000")]
132pub const TICK_HZ: u64 = 40_960_000;
133#[cfg(feature = "tick-hz-81_920_000")]
134pub const TICK_HZ: u64 = 81_920_000;
135#[cfg(feature = "tick-hz-163_840_000")]
136pub const TICK_HZ: u64 = 163_840_000;
137#[cfg(feature = "tick-hz-327_680_000")]
138pub const TICK_HZ: u64 = 327_680_000;
139#[cfg(feature = "tick-hz-655_360_000")]
140pub const TICK_HZ: u64 = 655_360_000;
141#[cfg(feature = "tick-hz-1_310_720_000")]
142pub const TICK_HZ: u64 = 1_310_720_000;
143#[cfg(feature = "tick-hz-2_621_440_000")]
144pub const TICK_HZ: u64 = 2_621_440_000;
145#[cfg(feature = "tick-hz-5_242_880_000")]
146pub const TICK_HZ: u64 = 5_242_880_000;
147#[cfg(feature = "tick-hz-2_000_000")] 91#[cfg(feature = "tick-hz-2_000_000")]
148pub const TICK_HZ: u64 = 2_000_000; 92pub const TICK_HZ: u64 = 2_000_000;
93#[cfg(feature = "tick-hz-2_048_000")]
94pub const TICK_HZ: u64 = 2_048_000;
95#[cfg(feature = "tick-hz-2_097_152")]
96pub const TICK_HZ: u64 = 2_097_152;
97#[cfg(feature = "tick-hz-2_560_000")]
98pub const TICK_HZ: u64 = 2_560_000;
149#[cfg(feature = "tick-hz-3_000_000")] 99#[cfg(feature = "tick-hz-3_000_000")]
150pub const TICK_HZ: u64 = 3_000_000; 100pub const TICK_HZ: u64 = 3_000_000;
151#[cfg(feature = "tick-hz-4_000_000")] 101#[cfg(feature = "tick-hz-4_000_000")]
152pub const TICK_HZ: u64 = 4_000_000; 102pub const TICK_HZ: u64 = 4_000_000;
103#[cfg(feature = "tick-hz-4_096_000")]
104pub const TICK_HZ: u64 = 4_096_000;
105#[cfg(feature = "tick-hz-4_194_304")]
106pub const TICK_HZ: u64 = 4_194_304;
107#[cfg(feature = "tick-hz-5_120_000")]
108pub const TICK_HZ: u64 = 5_120_000;
153#[cfg(feature = "tick-hz-6_000_000")] 109#[cfg(feature = "tick-hz-6_000_000")]
154pub const TICK_HZ: u64 = 6_000_000; 110pub const TICK_HZ: u64 = 6_000_000;
155#[cfg(feature = "tick-hz-8_000_000")] 111#[cfg(feature = "tick-hz-8_000_000")]
156pub const TICK_HZ: u64 = 8_000_000; 112pub const TICK_HZ: u64 = 8_000_000;
113#[cfg(feature = "tick-hz-8_192_000")]
114pub const TICK_HZ: u64 = 8_192_000;
115#[cfg(feature = "tick-hz-8_388_608")]
116pub const TICK_HZ: u64 = 8_388_608;
157#[cfg(feature = "tick-hz-9_000_000")] 117#[cfg(feature = "tick-hz-9_000_000")]
158pub const TICK_HZ: u64 = 9_000_000; 118pub const TICK_HZ: u64 = 9_000_000;
119#[cfg(feature = "tick-hz-10_000_000")]
120pub const TICK_HZ: u64 = 10_000_000;
121#[cfg(feature = "tick-hz-10_240_000")]
122pub const TICK_HZ: u64 = 10_240_000;
159#[cfg(feature = "tick-hz-12_000_000")] 123#[cfg(feature = "tick-hz-12_000_000")]
160pub const TICK_HZ: u64 = 12_000_000; 124pub const TICK_HZ: u64 = 12_000_000;
161#[cfg(feature = "tick-hz-16_000_000")] 125#[cfg(feature = "tick-hz-16_000_000")]
162pub const TICK_HZ: u64 = 16_000_000; 126pub const TICK_HZ: u64 = 16_000_000;
127#[cfg(feature = "tick-hz-16_384_000")]
128pub const TICK_HZ: u64 = 16_384_000;
129#[cfg(feature = "tick-hz-16_777_216")]
130pub const TICK_HZ: u64 = 16_777_216;
163#[cfg(feature = "tick-hz-18_000_000")] 131#[cfg(feature = "tick-hz-18_000_000")]
164pub const TICK_HZ: u64 = 18_000_000; 132pub const TICK_HZ: u64 = 18_000_000;
133#[cfg(feature = "tick-hz-20_000_000")]
134pub const TICK_HZ: u64 = 20_000_000;
135#[cfg(feature = "tick-hz-20_480_000")]
136pub const TICK_HZ: u64 = 20_480_000;
165#[cfg(feature = "tick-hz-24_000_000")] 137#[cfg(feature = "tick-hz-24_000_000")]
166pub const TICK_HZ: u64 = 24_000_000; 138pub const TICK_HZ: u64 = 24_000_000;
139#[cfg(feature = "tick-hz-30_000_000")]
140pub const TICK_HZ: u64 = 30_000_000;
167#[cfg(feature = "tick-hz-32_000_000")] 141#[cfg(feature = "tick-hz-32_000_000")]
168pub const TICK_HZ: u64 = 32_000_000; 142pub const TICK_HZ: u64 = 32_000_000;
143#[cfg(feature = "tick-hz-32_768_000")]
144pub const TICK_HZ: u64 = 32_768_000;
169#[cfg(feature = "tick-hz-36_000_000")] 145#[cfg(feature = "tick-hz-36_000_000")]
170pub const TICK_HZ: u64 = 36_000_000; 146pub const TICK_HZ: u64 = 36_000_000;
171#[cfg(feature = "tick-hz-48_000_000")]
172pub const TICK_HZ: u64 = 48_000_000;
173#[cfg(feature = "tick-hz-64_000_000")]
174pub const TICK_HZ: u64 = 64_000_000;
175#[cfg(feature = "tick-hz-72_000_000")]
176pub const TICK_HZ: u64 = 72_000_000;
177#[cfg(feature = "tick-hz-96_000_000")]
178pub const TICK_HZ: u64 = 96_000_000;
179#[cfg(feature = "tick-hz-128_000_000")]
180pub const TICK_HZ: u64 = 128_000_000;
181#[cfg(feature = "tick-hz-144_000_000")]
182pub const TICK_HZ: u64 = 144_000_000;
183#[cfg(feature = "tick-hz-192_000_000")]
184pub const TICK_HZ: u64 = 192_000_000;
185#[cfg(feature = "tick-hz-256_000_000")]
186pub const TICK_HZ: u64 = 256_000_000;
187#[cfg(feature = "tick-hz-288_000_000")]
188pub const TICK_HZ: u64 = 288_000_000;
189#[cfg(feature = "tick-hz-384_000_000")]
190pub const TICK_HZ: u64 = 384_000_000;
191#[cfg(feature = "tick-hz-512_000_000")]
192pub const TICK_HZ: u64 = 512_000_000;
193#[cfg(feature = "tick-hz-576_000_000")]
194pub const TICK_HZ: u64 = 576_000_000;
195#[cfg(feature = "tick-hz-768_000_000")]
196pub const TICK_HZ: u64 = 768_000_000;
197#[cfg(feature = "tick-hz-20_000_000")]
198pub const TICK_HZ: u64 = 20_000_000;
199#[cfg(feature = "tick-hz-30_000_000")]
200pub const TICK_HZ: u64 = 30_000_000;
201#[cfg(feature = "tick-hz-40_000_000")] 147#[cfg(feature = "tick-hz-40_000_000")]
202pub const TICK_HZ: u64 = 40_000_000; 148pub const TICK_HZ: u64 = 40_000_000;
149#[cfg(feature = "tick-hz-40_960_000")]
150pub const TICK_HZ: u64 = 40_960_000;
151#[cfg(feature = "tick-hz-48_000_000")]
152pub const TICK_HZ: u64 = 48_000_000;
203#[cfg(feature = "tick-hz-50_000_000")] 153#[cfg(feature = "tick-hz-50_000_000")]
204pub const TICK_HZ: u64 = 50_000_000; 154pub const TICK_HZ: u64 = 50_000_000;
205#[cfg(feature = "tick-hz-60_000_000")] 155#[cfg(feature = "tick-hz-60_000_000")]
206pub const TICK_HZ: u64 = 60_000_000; 156pub const TICK_HZ: u64 = 60_000_000;
157#[cfg(feature = "tick-hz-64_000_000")]
158pub const TICK_HZ: u64 = 64_000_000;
159#[cfg(feature = "tick-hz-65_536_000")]
160pub const TICK_HZ: u64 = 65_536_000;
207#[cfg(feature = "tick-hz-70_000_000")] 161#[cfg(feature = "tick-hz-70_000_000")]
208pub const TICK_HZ: u64 = 70_000_000; 162pub const TICK_HZ: u64 = 70_000_000;
163#[cfg(feature = "tick-hz-72_000_000")]
164pub const TICK_HZ: u64 = 72_000_000;
209#[cfg(feature = "tick-hz-80_000_000")] 165#[cfg(feature = "tick-hz-80_000_000")]
210pub const TICK_HZ: u64 = 80_000_000; 166pub const TICK_HZ: u64 = 80_000_000;
167#[cfg(feature = "tick-hz-81_920_000")]
168pub const TICK_HZ: u64 = 81_920_000;
211#[cfg(feature = "tick-hz-90_000_000")] 169#[cfg(feature = "tick-hz-90_000_000")]
212pub const TICK_HZ: u64 = 90_000_000; 170pub const TICK_HZ: u64 = 90_000_000;
171#[cfg(feature = "tick-hz-96_000_000")]
172pub const TICK_HZ: u64 = 96_000_000;
173#[cfg(feature = "tick-hz-100_000_000")]
174pub const TICK_HZ: u64 = 100_000_000;
213#[cfg(feature = "tick-hz-110_000_000")] 175#[cfg(feature = "tick-hz-110_000_000")]
214pub const TICK_HZ: u64 = 110_000_000; 176pub const TICK_HZ: u64 = 110_000_000;
215#[cfg(feature = "tick-hz-120_000_000")] 177#[cfg(feature = "tick-hz-120_000_000")]
216pub const TICK_HZ: u64 = 120_000_000; 178pub const TICK_HZ: u64 = 120_000_000;
179#[cfg(feature = "tick-hz-128_000_000")]
180pub const TICK_HZ: u64 = 128_000_000;
217#[cfg(feature = "tick-hz-130_000_000")] 181#[cfg(feature = "tick-hz-130_000_000")]
218pub const TICK_HZ: u64 = 130_000_000; 182pub const TICK_HZ: u64 = 130_000_000;
183#[cfg(feature = "tick-hz-131_072_000")]
184pub const TICK_HZ: u64 = 131_072_000;
219#[cfg(feature = "tick-hz-140_000_000")] 185#[cfg(feature = "tick-hz-140_000_000")]
220pub const TICK_HZ: u64 = 140_000_000; 186pub const TICK_HZ: u64 = 140_000_000;
187#[cfg(feature = "tick-hz-144_000_000")]
188pub const TICK_HZ: u64 = 144_000_000;
221#[cfg(feature = "tick-hz-150_000_000")] 189#[cfg(feature = "tick-hz-150_000_000")]
222pub const TICK_HZ: u64 = 150_000_000; 190pub const TICK_HZ: u64 = 150_000_000;
223#[cfg(feature = "tick-hz-160_000_000")] 191#[cfg(feature = "tick-hz-160_000_000")]
224pub const TICK_HZ: u64 = 160_000_000; 192pub const TICK_HZ: u64 = 160_000_000;
193#[cfg(feature = "tick-hz-163_840_000")]
194pub const TICK_HZ: u64 = 163_840_000;
225#[cfg(feature = "tick-hz-170_000_000")] 195#[cfg(feature = "tick-hz-170_000_000")]
226pub const TICK_HZ: u64 = 170_000_000; 196pub const TICK_HZ: u64 = 170_000_000;
227#[cfg(feature = "tick-hz-180_000_000")] 197#[cfg(feature = "tick-hz-180_000_000")]
228pub const TICK_HZ: u64 = 180_000_000; 198pub const TICK_HZ: u64 = 180_000_000;
229#[cfg(feature = "tick-hz-190_000_000")] 199#[cfg(feature = "tick-hz-190_000_000")]
230pub const TICK_HZ: u64 = 190_000_000; 200pub const TICK_HZ: u64 = 190_000_000;
201#[cfg(feature = "tick-hz-192_000_000")]
202pub const TICK_HZ: u64 = 192_000_000;
231#[cfg(feature = "tick-hz-200_000_000")] 203#[cfg(feature = "tick-hz-200_000_000")]
232pub const TICK_HZ: u64 = 200_000_000; 204pub const TICK_HZ: u64 = 200_000_000;
233#[cfg(feature = "tick-hz-210_000_000")] 205#[cfg(feature = "tick-hz-210_000_000")]
@@ -240,24 +212,34 @@ pub const TICK_HZ: u64 = 230_000_000;
240pub const TICK_HZ: u64 = 240_000_000; 212pub const TICK_HZ: u64 = 240_000_000;
241#[cfg(feature = "tick-hz-250_000_000")] 213#[cfg(feature = "tick-hz-250_000_000")]
242pub const TICK_HZ: u64 = 250_000_000; 214pub const TICK_HZ: u64 = 250_000_000;
215#[cfg(feature = "tick-hz-256_000_000")]
216pub const TICK_HZ: u64 = 256_000_000;
243#[cfg(feature = "tick-hz-260_000_000")] 217#[cfg(feature = "tick-hz-260_000_000")]
244pub const TICK_HZ: u64 = 260_000_000; 218pub const TICK_HZ: u64 = 260_000_000;
219#[cfg(feature = "tick-hz-262_144_000")]
220pub const TICK_HZ: u64 = 262_144_000;
245#[cfg(feature = "tick-hz-270_000_000")] 221#[cfg(feature = "tick-hz-270_000_000")]
246pub const TICK_HZ: u64 = 270_000_000; 222pub const TICK_HZ: u64 = 270_000_000;
247#[cfg(feature = "tick-hz-280_000_000")] 223#[cfg(feature = "tick-hz-280_000_000")]
248pub const TICK_HZ: u64 = 280_000_000; 224pub const TICK_HZ: u64 = 280_000_000;
225#[cfg(feature = "tick-hz-288_000_000")]
226pub const TICK_HZ: u64 = 288_000_000;
249#[cfg(feature = "tick-hz-290_000_000")] 227#[cfg(feature = "tick-hz-290_000_000")]
250pub const TICK_HZ: u64 = 290_000_000; 228pub const TICK_HZ: u64 = 290_000_000;
251#[cfg(feature = "tick-hz-300_000_000")] 229#[cfg(feature = "tick-hz-300_000_000")]
252pub const TICK_HZ: u64 = 300_000_000; 230pub const TICK_HZ: u64 = 300_000_000;
253#[cfg(feature = "tick-hz-320_000_000")] 231#[cfg(feature = "tick-hz-320_000_000")]
254pub const TICK_HZ: u64 = 320_000_000; 232pub const TICK_HZ: u64 = 320_000_000;
233#[cfg(feature = "tick-hz-327_680_000")]
234pub const TICK_HZ: u64 = 327_680_000;
255#[cfg(feature = "tick-hz-340_000_000")] 235#[cfg(feature = "tick-hz-340_000_000")]
256pub const TICK_HZ: u64 = 340_000_000; 236pub const TICK_HZ: u64 = 340_000_000;
257#[cfg(feature = "tick-hz-360_000_000")] 237#[cfg(feature = "tick-hz-360_000_000")]
258pub const TICK_HZ: u64 = 360_000_000; 238pub const TICK_HZ: u64 = 360_000_000;
259#[cfg(feature = "tick-hz-380_000_000")] 239#[cfg(feature = "tick-hz-380_000_000")]
260pub const TICK_HZ: u64 = 380_000_000; 240pub const TICK_HZ: u64 = 380_000_000;
241#[cfg(feature = "tick-hz-384_000_000")]
242pub const TICK_HZ: u64 = 384_000_000;
261#[cfg(feature = "tick-hz-400_000_000")] 243#[cfg(feature = "tick-hz-400_000_000")]
262pub const TICK_HZ: u64 = 400_000_000; 244pub const TICK_HZ: u64 = 400_000_000;
263#[cfg(feature = "tick-hz-420_000_000")] 245#[cfg(feature = "tick-hz-420_000_000")]
@@ -270,12 +252,18 @@ pub const TICK_HZ: u64 = 460_000_000;
270pub const TICK_HZ: u64 = 480_000_000; 252pub const TICK_HZ: u64 = 480_000_000;
271#[cfg(feature = "tick-hz-500_000_000")] 253#[cfg(feature = "tick-hz-500_000_000")]
272pub const TICK_HZ: u64 = 500_000_000; 254pub const TICK_HZ: u64 = 500_000_000;
255#[cfg(feature = "tick-hz-512_000_000")]
256pub const TICK_HZ: u64 = 512_000_000;
273#[cfg(feature = "tick-hz-520_000_000")] 257#[cfg(feature = "tick-hz-520_000_000")]
274pub const TICK_HZ: u64 = 520_000_000; 258pub const TICK_HZ: u64 = 520_000_000;
259#[cfg(feature = "tick-hz-524_288_000")]
260pub const TICK_HZ: u64 = 524_288_000;
275#[cfg(feature = "tick-hz-540_000_000")] 261#[cfg(feature = "tick-hz-540_000_000")]
276pub const TICK_HZ: u64 = 540_000_000; 262pub const TICK_HZ: u64 = 540_000_000;
277#[cfg(feature = "tick-hz-560_000_000")] 263#[cfg(feature = "tick-hz-560_000_000")]
278pub const TICK_HZ: u64 = 560_000_000; 264pub const TICK_HZ: u64 = 560_000_000;
265#[cfg(feature = "tick-hz-576_000_000")]
266pub const TICK_HZ: u64 = 576_000_000;
279#[cfg(feature = "tick-hz-580_000_000")] 267#[cfg(feature = "tick-hz-580_000_000")]
280pub const TICK_HZ: u64 = 580_000_000; 268pub const TICK_HZ: u64 = 580_000_000;
281#[cfg(feature = "tick-hz-600_000_000")] 269#[cfg(feature = "tick-hz-600_000_000")]
@@ -284,6 +272,8 @@ pub const TICK_HZ: u64 = 600_000_000;
284pub const TICK_HZ: u64 = 620_000_000; 272pub const TICK_HZ: u64 = 620_000_000;
285#[cfg(feature = "tick-hz-640_000_000")] 273#[cfg(feature = "tick-hz-640_000_000")]
286pub const TICK_HZ: u64 = 640_000_000; 274pub const TICK_HZ: u64 = 640_000_000;
275#[cfg(feature = "tick-hz-655_360_000")]
276pub const TICK_HZ: u64 = 655_360_000;
287#[cfg(feature = "tick-hz-660_000_000")] 277#[cfg(feature = "tick-hz-660_000_000")]
288pub const TICK_HZ: u64 = 660_000_000; 278pub const TICK_HZ: u64 = 660_000_000;
289#[cfg(feature = "tick-hz-680_000_000")] 279#[cfg(feature = "tick-hz-680_000_000")]
@@ -296,6 +286,8 @@ pub const TICK_HZ: u64 = 720_000_000;
296pub const TICK_HZ: u64 = 740_000_000; 286pub const TICK_HZ: u64 = 740_000_000;
297#[cfg(feature = "tick-hz-760_000_000")] 287#[cfg(feature = "tick-hz-760_000_000")]
298pub const TICK_HZ: u64 = 760_000_000; 288pub const TICK_HZ: u64 = 760_000_000;
289#[cfg(feature = "tick-hz-768_000_000")]
290pub const TICK_HZ: u64 = 768_000_000;
299#[cfg(feature = "tick-hz-780_000_000")] 291#[cfg(feature = "tick-hz-780_000_000")]
300pub const TICK_HZ: u64 = 780_000_000; 292pub const TICK_HZ: u64 = 780_000_000;
301#[cfg(feature = "tick-hz-800_000_000")] 293#[cfg(feature = "tick-hz-800_000_000")]
@@ -318,155 +310,159 @@ pub const TICK_HZ: u64 = 940_000_000;
318pub const TICK_HZ: u64 = 960_000_000; 310pub const TICK_HZ: u64 = 960_000_000;
319#[cfg(feature = "tick-hz-980_000_000")] 311#[cfg(feature = "tick-hz-980_000_000")]
320pub const TICK_HZ: u64 = 980_000_000; 312pub const TICK_HZ: u64 = 980_000_000;
313#[cfg(feature = "tick-hz-1_000_000_000")]
314pub const TICK_HZ: u64 = 1_000_000_000;
315#[cfg(feature = "tick-hz-1_310_720_000")]
316pub const TICK_HZ: u64 = 1_310_720_000;
317#[cfg(feature = "tick-hz-2_621_440_000")]
318pub const TICK_HZ: u64 = 2_621_440_000;
319#[cfg(feature = "tick-hz-5_242_880_000")]
320pub const TICK_HZ: u64 = 5_242_880_000;
321#[cfg(not(any( 321#[cfg(not(any(
322 feature = "tick-hz-1", 322 feature = "tick-hz-1",
323 feature = "tick-hz-10",
324 feature = "tick-hz-100",
325 feature = "tick-hz-1_000",
326 feature = "tick-hz-10_000",
327 feature = "tick-hz-100_000",
328 feature = "tick-hz-1_000_000",
329 feature = "tick-hz-10_000_000",
330 feature = "tick-hz-100_000_000",
331 feature = "tick-hz-1_000_000_000",
332 feature = "tick-hz-2", 323 feature = "tick-hz-2",
333 feature = "tick-hz-4", 324 feature = "tick-hz-4",
334 feature = "tick-hz-8", 325 feature = "tick-hz-8",
326 feature = "tick-hz-10",
335 feature = "tick-hz-16", 327 feature = "tick-hz-16",
336 feature = "tick-hz-32", 328 feature = "tick-hz-32",
337 feature = "tick-hz-64", 329 feature = "tick-hz-64",
330 feature = "tick-hz-100",
338 feature = "tick-hz-128", 331 feature = "tick-hz-128",
339 feature = "tick-hz-256", 332 feature = "tick-hz-256",
340 feature = "tick-hz-512", 333 feature = "tick-hz-512",
334 feature = "tick-hz-1_000",
341 feature = "tick-hz-1_024", 335 feature = "tick-hz-1_024",
342 feature = "tick-hz-2_048",
343 feature = "tick-hz-4_096",
344 feature = "tick-hz-8_192",
345 feature = "tick-hz-16_384",
346 feature = "tick-hz-32_768",
347 feature = "tick-hz-65_536",
348 feature = "tick-hz-131_072",
349 feature = "tick-hz-262_144",
350 feature = "tick-hz-524_288",
351 feature = "tick-hz-1_048_576",
352 feature = "tick-hz-2_097_152",
353 feature = "tick-hz-4_194_304",
354 feature = "tick-hz-8_388_608",
355 feature = "tick-hz-16_777_216",
356 feature = "tick-hz-2_000", 336 feature = "tick-hz-2_000",
337 feature = "tick-hz-2_048",
357 feature = "tick-hz-4_000", 338 feature = "tick-hz-4_000",
339 feature = "tick-hz-4_096",
358 feature = "tick-hz-8_000", 340 feature = "tick-hz-8_000",
341 feature = "tick-hz-8_192",
342 feature = "tick-hz-10_000",
359 feature = "tick-hz-16_000", 343 feature = "tick-hz-16_000",
360 feature = "tick-hz-32_000", 344 feature = "tick-hz-16_384",
361 feature = "tick-hz-64_000",
362 feature = "tick-hz-128_000",
363 feature = "tick-hz-256_000",
364 feature = "tick-hz-512_000",
365 feature = "tick-hz-1_024_000",
366 feature = "tick-hz-2_048_000",
367 feature = "tick-hz-4_096_000",
368 feature = "tick-hz-8_192_000",
369 feature = "tick-hz-16_384_000",
370 feature = "tick-hz-32_768_000",
371 feature = "tick-hz-65_536_000",
372 feature = "tick-hz-131_072_000",
373 feature = "tick-hz-262_144_000",
374 feature = "tick-hz-524_288_000",
375 feature = "tick-hz-20_000", 345 feature = "tick-hz-20_000",
346 feature = "tick-hz-32_000",
347 feature = "tick-hz-32_768",
376 feature = "tick-hz-40_000", 348 feature = "tick-hz-40_000",
349 feature = "tick-hz-64_000",
350 feature = "tick-hz-65_536",
377 feature = "tick-hz-80_000", 351 feature = "tick-hz-80_000",
352 feature = "tick-hz-100_000",
353 feature = "tick-hz-128_000",
354 feature = "tick-hz-131_072",
378 feature = "tick-hz-160_000", 355 feature = "tick-hz-160_000",
356 feature = "tick-hz-256_000",
357 feature = "tick-hz-262_144",
379 feature = "tick-hz-320_000", 358 feature = "tick-hz-320_000",
359 feature = "tick-hz-512_000",
360 feature = "tick-hz-524_288",
380 feature = "tick-hz-640_000", 361 feature = "tick-hz-640_000",
362 feature = "tick-hz-1_000_000",
363 feature = "tick-hz-1_024_000",
364 feature = "tick-hz-1_048_576",
381 feature = "tick-hz-1_280_000", 365 feature = "tick-hz-1_280_000",
382 feature = "tick-hz-2_560_000",
383 feature = "tick-hz-5_120_000",
384 feature = "tick-hz-10_240_000",
385 feature = "tick-hz-20_480_000",
386 feature = "tick-hz-40_960_000",
387 feature = "tick-hz-81_920_000",
388 feature = "tick-hz-163_840_000",
389 feature = "tick-hz-327_680_000",
390 feature = "tick-hz-655_360_000",
391 feature = "tick-hz-1_310_720_000",
392 feature = "tick-hz-2_621_440_000",
393 feature = "tick-hz-5_242_880_000",
394 feature = "tick-hz-2_000_000", 366 feature = "tick-hz-2_000_000",
367 feature = "tick-hz-2_048_000",
368 feature = "tick-hz-2_097_152",
369 feature = "tick-hz-2_560_000",
395 feature = "tick-hz-3_000_000", 370 feature = "tick-hz-3_000_000",
396 feature = "tick-hz-4_000_000", 371 feature = "tick-hz-4_000_000",
372 feature = "tick-hz-4_096_000",
373 feature = "tick-hz-4_194_304",
374 feature = "tick-hz-5_120_000",
397 feature = "tick-hz-6_000_000", 375 feature = "tick-hz-6_000_000",
398 feature = "tick-hz-8_000_000", 376 feature = "tick-hz-8_000_000",
377 feature = "tick-hz-8_192_000",
378 feature = "tick-hz-8_388_608",
399 feature = "tick-hz-9_000_000", 379 feature = "tick-hz-9_000_000",
380 feature = "tick-hz-10_000_000",
381 feature = "tick-hz-10_240_000",
400 feature = "tick-hz-12_000_000", 382 feature = "tick-hz-12_000_000",
401 feature = "tick-hz-16_000_000", 383 feature = "tick-hz-16_000_000",
384 feature = "tick-hz-16_384_000",
385 feature = "tick-hz-16_777_216",
402 feature = "tick-hz-18_000_000", 386 feature = "tick-hz-18_000_000",
387 feature = "tick-hz-20_000_000",
388 feature = "tick-hz-20_480_000",
403 feature = "tick-hz-24_000_000", 389 feature = "tick-hz-24_000_000",
390 feature = "tick-hz-30_000_000",
404 feature = "tick-hz-32_000_000", 391 feature = "tick-hz-32_000_000",
392 feature = "tick-hz-32_768_000",
405 feature = "tick-hz-36_000_000", 393 feature = "tick-hz-36_000_000",
406 feature = "tick-hz-48_000_000",
407 feature = "tick-hz-64_000_000",
408 feature = "tick-hz-72_000_000",
409 feature = "tick-hz-96_000_000",
410 feature = "tick-hz-128_000_000",
411 feature = "tick-hz-144_000_000",
412 feature = "tick-hz-192_000_000",
413 feature = "tick-hz-256_000_000",
414 feature = "tick-hz-288_000_000",
415 feature = "tick-hz-384_000_000",
416 feature = "tick-hz-512_000_000",
417 feature = "tick-hz-576_000_000",
418 feature = "tick-hz-768_000_000",
419 feature = "tick-hz-20_000_000",
420 feature = "tick-hz-30_000_000",
421 feature = "tick-hz-40_000_000", 394 feature = "tick-hz-40_000_000",
395 feature = "tick-hz-40_960_000",
396 feature = "tick-hz-48_000_000",
422 feature = "tick-hz-50_000_000", 397 feature = "tick-hz-50_000_000",
423 feature = "tick-hz-60_000_000", 398 feature = "tick-hz-60_000_000",
399 feature = "tick-hz-64_000_000",
400 feature = "tick-hz-65_536_000",
424 feature = "tick-hz-70_000_000", 401 feature = "tick-hz-70_000_000",
402 feature = "tick-hz-72_000_000",
425 feature = "tick-hz-80_000_000", 403 feature = "tick-hz-80_000_000",
404 feature = "tick-hz-81_920_000",
426 feature = "tick-hz-90_000_000", 405 feature = "tick-hz-90_000_000",
406 feature = "tick-hz-96_000_000",
407 feature = "tick-hz-100_000_000",
427 feature = "tick-hz-110_000_000", 408 feature = "tick-hz-110_000_000",
428 feature = "tick-hz-120_000_000", 409 feature = "tick-hz-120_000_000",
410 feature = "tick-hz-128_000_000",
429 feature = "tick-hz-130_000_000", 411 feature = "tick-hz-130_000_000",
412 feature = "tick-hz-131_072_000",
430 feature = "tick-hz-140_000_000", 413 feature = "tick-hz-140_000_000",
414 feature = "tick-hz-144_000_000",
431 feature = "tick-hz-150_000_000", 415 feature = "tick-hz-150_000_000",
432 feature = "tick-hz-160_000_000", 416 feature = "tick-hz-160_000_000",
417 feature = "tick-hz-163_840_000",
433 feature = "tick-hz-170_000_000", 418 feature = "tick-hz-170_000_000",
434 feature = "tick-hz-180_000_000", 419 feature = "tick-hz-180_000_000",
435 feature = "tick-hz-190_000_000", 420 feature = "tick-hz-190_000_000",
421 feature = "tick-hz-192_000_000",
436 feature = "tick-hz-200_000_000", 422 feature = "tick-hz-200_000_000",
437 feature = "tick-hz-210_000_000", 423 feature = "tick-hz-210_000_000",
438 feature = "tick-hz-220_000_000", 424 feature = "tick-hz-220_000_000",
439 feature = "tick-hz-230_000_000", 425 feature = "tick-hz-230_000_000",
440 feature = "tick-hz-240_000_000", 426 feature = "tick-hz-240_000_000",
441 feature = "tick-hz-250_000_000", 427 feature = "tick-hz-250_000_000",
428 feature = "tick-hz-256_000_000",
442 feature = "tick-hz-260_000_000", 429 feature = "tick-hz-260_000_000",
430 feature = "tick-hz-262_144_000",
443 feature = "tick-hz-270_000_000", 431 feature = "tick-hz-270_000_000",
444 feature = "tick-hz-280_000_000", 432 feature = "tick-hz-280_000_000",
433 feature = "tick-hz-288_000_000",
445 feature = "tick-hz-290_000_000", 434 feature = "tick-hz-290_000_000",
446 feature = "tick-hz-300_000_000", 435 feature = "tick-hz-300_000_000",
447 feature = "tick-hz-320_000_000", 436 feature = "tick-hz-320_000_000",
437 feature = "tick-hz-327_680_000",
448 feature = "tick-hz-340_000_000", 438 feature = "tick-hz-340_000_000",
449 feature = "tick-hz-360_000_000", 439 feature = "tick-hz-360_000_000",
450 feature = "tick-hz-380_000_000", 440 feature = "tick-hz-380_000_000",
441 feature = "tick-hz-384_000_000",
451 feature = "tick-hz-400_000_000", 442 feature = "tick-hz-400_000_000",
452 feature = "tick-hz-420_000_000", 443 feature = "tick-hz-420_000_000",
453 feature = "tick-hz-440_000_000", 444 feature = "tick-hz-440_000_000",
454 feature = "tick-hz-460_000_000", 445 feature = "tick-hz-460_000_000",
455 feature = "tick-hz-480_000_000", 446 feature = "tick-hz-480_000_000",
456 feature = "tick-hz-500_000_000", 447 feature = "tick-hz-500_000_000",
448 feature = "tick-hz-512_000_000",
457 feature = "tick-hz-520_000_000", 449 feature = "tick-hz-520_000_000",
450 feature = "tick-hz-524_288_000",
458 feature = "tick-hz-540_000_000", 451 feature = "tick-hz-540_000_000",
459 feature = "tick-hz-560_000_000", 452 feature = "tick-hz-560_000_000",
453 feature = "tick-hz-576_000_000",
460 feature = "tick-hz-580_000_000", 454 feature = "tick-hz-580_000_000",
461 feature = "tick-hz-600_000_000", 455 feature = "tick-hz-600_000_000",
462 feature = "tick-hz-620_000_000", 456 feature = "tick-hz-620_000_000",
463 feature = "tick-hz-640_000_000", 457 feature = "tick-hz-640_000_000",
458 feature = "tick-hz-655_360_000",
464 feature = "tick-hz-660_000_000", 459 feature = "tick-hz-660_000_000",
465 feature = "tick-hz-680_000_000", 460 feature = "tick-hz-680_000_000",
466 feature = "tick-hz-700_000_000", 461 feature = "tick-hz-700_000_000",
467 feature = "tick-hz-720_000_000", 462 feature = "tick-hz-720_000_000",
468 feature = "tick-hz-740_000_000", 463 feature = "tick-hz-740_000_000",
469 feature = "tick-hz-760_000_000", 464 feature = "tick-hz-760_000_000",
465 feature = "tick-hz-768_000_000",
470 feature = "tick-hz-780_000_000", 466 feature = "tick-hz-780_000_000",
471 feature = "tick-hz-800_000_000", 467 feature = "tick-hz-800_000_000",
472 feature = "tick-hz-820_000_000", 468 feature = "tick-hz-820_000_000",
@@ -478,5 +474,9 @@ pub const TICK_HZ: u64 = 980_000_000;
478 feature = "tick-hz-940_000_000", 474 feature = "tick-hz-940_000_000",
479 feature = "tick-hz-960_000_000", 475 feature = "tick-hz-960_000_000",
480 feature = "tick-hz-980_000_000", 476 feature = "tick-hz-980_000_000",
477 feature = "tick-hz-1_000_000_000",
478 feature = "tick-hz-1_310_720_000",
479 feature = "tick-hz-2_621_440_000",
480 feature = "tick-hz-5_242_880_000",
481)))] 481)))]
482pub const TICK_HZ: u64 = 1_000_000; 482pub const TICK_HZ: u64 = 1_000_000;
diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs
index 574d715da..2705ba03f 100644
--- a/embassy-time/src/timer.rs
+++ b/embassy-time/src/timer.rs
@@ -47,9 +47,6 @@ impl Timer {
47 /// 47 ///
48 /// Example: 48 /// Example:
49 /// ``` no_run 49 /// ``` no_run
50 /// # #![feature(type_alias_impl_trait)]
51 /// #
52 /// # fn foo() {}
53 /// use embassy_time::{Duration, Timer}; 50 /// use embassy_time::{Duration, Timer};
54 /// 51 ///
55 /// #[embassy_executor::task] 52 /// #[embassy_executor::task]
@@ -132,8 +129,6 @@ impl Future for Timer {
132/// 129///
133/// For instance, consider the following code fragment. 130/// For instance, consider the following code fragment.
134/// ``` no_run 131/// ``` no_run
135/// # #![feature(type_alias_impl_trait)]
136/// #
137/// use embassy_time::{Duration, Timer}; 132/// use embassy_time::{Duration, Timer};
138/// # fn foo() {} 133/// # fn foo() {}
139/// 134///
@@ -152,8 +147,6 @@ impl Future for Timer {
152/// Example using ticker, which will consistently call `foo` once a second. 147/// Example using ticker, which will consistently call `foo` once a second.
153/// 148///
154/// ``` no_run 149/// ``` no_run
155/// # #![feature(type_alias_impl_trait)]
156/// #
157/// use embassy_time::{Duration, Ticker}; 150/// use embassy_time::{Duration, Ticker};
158/// # fn foo(){} 151/// # fn foo(){}
159/// 152///
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
new file mode 100644
index 000000000..ee110ee87
--- /dev/null
+++ b/embassy-usb-dfu/Cargo.toml
@@ -0,0 +1,32 @@
1[package]
2edition = "2021"
3name = "embassy-usb-dfu"
4version = "0.1.0"
5description = "An implementation of the USB DFU 1.1 protocol, using embassy-boot"
6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous"
12]
13
14# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
15
16[dependencies]
17bitflags = "2.4.1"
18cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
19defmt = { version = "0.3.5", optional = true }
20embassy-boot = { version = "0.1.1", path = "../embassy-boot/boot" }
21# embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
22embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
23embassy-sync = { version = "0.5.0", path = "../embassy-sync" }
24embassy-time = { version = "0.2.0", path = "../embassy-time" }
25embassy-usb = { version = "0.1.0", path = "../embassy-usb", default-features = false }
26embedded-storage = { version = "0.3.1" }
27esp32c3-hal = { version = "0.13.0", optional = true, default-features = false }
28
29[features]
30dfu = []
31application = []
32defmt = ["dep:defmt"]
diff --git a/embassy-usb-dfu/README.md b/embassy-usb-dfu/README.md
new file mode 100644
index 000000000..d8bc19bfd
--- /dev/null
+++ b/embassy-usb-dfu/README.md
@@ -0,0 +1,20 @@
1# embassy-usb-dfu
2
3An implementation of the USB DFU 1.1 protocol using embassy-boot. It has 2 components depending on which feature is enabled by the user.
4
5* DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention.
6* DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system.
7
8## Minimum supported Rust version (MSRV)
9
10Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
11
12## License
13
14This work is licensed under either of
15
16- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
17 <http://www.apache.org/licenses/LICENSE-2.0>)
18- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
19
20at your option.
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs
new file mode 100644
index 000000000..f0d7626f6
--- /dev/null
+++ b/embassy-usb-dfu/src/application.rs
@@ -0,0 +1,136 @@
1use core::marker::PhantomData;
2
3use embassy_boot::BlockingFirmwareState;
4use embassy_time::{Duration, Instant};
5use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
6use embassy_usb::driver::Driver;
7use embassy_usb::{Builder, Handler};
8use embedded_storage::nor_flash::NorFlash;
9
10use crate::consts::{
11 DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT,
12 USB_CLASS_APPN_SPEC,
13};
14use crate::Reset;
15
16/// Internal state for the DFU class
17pub struct Control<'d, STATE: NorFlash, RST: Reset> {
18 firmware_state: BlockingFirmwareState<'d, STATE>,
19 attrs: DfuAttributes,
20 state: State,
21 timeout: Option<Duration>,
22 detach_start: Option<Instant>,
23 _rst: PhantomData<RST>,
24}
25
26impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> {
27 /// Create a new DFU instance to expose a DFU interface.
28 pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self {
29 Control {
30 firmware_state,
31 attrs,
32 state: State::AppIdle,
33 detach_start: None,
34 timeout: None,
35 _rst: PhantomData,
36 }
37 }
38}
39
40impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
41 fn reset(&mut self) {
42 if let Some(start) = self.detach_start {
43 let delta = Instant::now() - start;
44 let timeout = self.timeout.unwrap();
45 trace!(
46 "Received RESET with delta = {}, timeout = {}",
47 delta.as_millis(),
48 timeout.as_millis()
49 );
50 if delta < timeout {
51 self.firmware_state
52 .mark_dfu()
53 .expect("Failed to mark DFU mode in bootloader");
54 RST::sys_reset()
55 }
56 }
57 }
58
59 fn control_out(
60 &mut self,
61 req: embassy_usb::control::Request,
62 _: &[u8],
63 ) -> Option<embassy_usb::control::OutResponse> {
64 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
65 return None;
66 }
67
68 trace!("Received request {}", req);
69
70 match Request::try_from(req.request) {
71 Ok(Request::Detach) => {
72 trace!("Received DETACH, awaiting USB reset");
73 self.detach_start = Some(Instant::now());
74 self.timeout = Some(Duration::from_millis(req.value as u64));
75 self.state = State::AppDetach;
76 Some(OutResponse::Accepted)
77 }
78 _ => None,
79 }
80 }
81
82 fn control_in<'a>(
83 &'a mut self,
84 req: embassy_usb::control::Request,
85 buf: &'a mut [u8],
86 ) -> Option<embassy_usb::control::InResponse<'a>> {
87 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
88 return None;
89 }
90
91 trace!("Received request {}", req);
92
93 match Request::try_from(req.request) {
94 Ok(Request::GetStatus) => {
95 buf[0..6].copy_from_slice(&[Status::Ok as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
96 Some(InResponse::Accepted(buf))
97 }
98 _ => None,
99 }
100 }
101}
102
103/// An implementation of the USB DFU 1.1 runtime protocol
104///
105/// This function will add a DFU interface descriptor to the provided Builder, and register the provided Control as a handler for the USB device. The USB builder can be used as normal once this is complete.
106/// The handler is responsive to DFU GetStatus and Detach commands.
107///
108/// Once a detach command, followed by a USB reset is received by the host, a magic number will be written into the bootloader state partition to indicate that
109/// it should expose a DFU device, and a software reset will be issued.
110///
111/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host.
112pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>(
113 builder: &mut Builder<'d, D>,
114 handler: &'d mut Control<'d, STATE, RST>,
115 timeout: Duration,
116) {
117 let mut func = builder.function(0x00, 0x00, 0x00);
118 let mut iface = func.interface();
119 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None);
120 let timeout = timeout.as_millis() as u16;
121 alt.descriptor(
122 DESC_DFU_FUNCTIONAL,
123 &[
124 handler.attrs.bits(),
125 (timeout & 0xff) as u8,
126 ((timeout >> 8) & 0xff) as u8,
127 0x40,
128 0x00, // 64B control buffer size for application side
129 0x10,
130 0x01, // DFU 1.1
131 ],
132 );
133
134 drop(func);
135 builder.handler(handler);
136}
diff --git a/embassy-usb-dfu/src/consts.rs b/embassy-usb-dfu/src/consts.rs
new file mode 100644
index 000000000..f8a056e5c
--- /dev/null
+++ b/embassy-usb-dfu/src/consts.rs
@@ -0,0 +1,101 @@
1//! USB DFU constants.
2pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE;
3pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01;
4#[allow(unused)]
5pub(crate) const DFU_PROTOCOL_DFU: u8 = 0x02;
6#[allow(unused)]
7pub(crate) const DFU_PROTOCOL_RT: u8 = 0x01;
8pub(crate) const DESC_DFU_FUNCTIONAL: u8 = 0x21;
9
10#[cfg(feature = "defmt")]
11defmt::bitflags! {
12 pub struct DfuAttributes: u8 {
13 const WILL_DETACH = 0b0000_1000;
14 const MANIFESTATION_TOLERANT = 0b0000_0100;
15 const CAN_UPLOAD = 0b0000_0010;
16 const CAN_DOWNLOAD = 0b0000_0001;
17 }
18}
19
20#[cfg(not(feature = "defmt"))]
21bitflags::bitflags! {
22 /// Attributes supported by the DFU controller.
23 pub struct DfuAttributes: u8 {
24 /// Generate WillDetache sequence on bus.
25 const WILL_DETACH = 0b0000_1000;
26 /// Device can communicate during manifestation phase.
27 const MANIFESTATION_TOLERANT = 0b0000_0100;
28 /// Capable of upload.
29 const CAN_UPLOAD = 0b0000_0010;
30 /// Capable of download.
31 const CAN_DOWNLOAD = 0b0000_0001;
32 }
33}
34
35#[derive(Copy, Clone, PartialEq, Eq)]
36#[repr(u8)]
37#[allow(unused)]
38pub(crate) enum State {
39 AppIdle = 0,
40 AppDetach = 1,
41 DfuIdle = 2,
42 DlSync = 3,
43 DlBusy = 4,
44 Download = 5,
45 ManifestSync = 6,
46 Manifest = 7,
47 ManifestWaitReset = 8,
48 UploadIdle = 9,
49 Error = 10,
50}
51
52#[derive(Copy, Clone, PartialEq, Eq)]
53#[repr(u8)]
54#[allow(unused)]
55pub(crate) enum Status {
56 Ok = 0x00,
57 ErrTarget = 0x01,
58 ErrFile = 0x02,
59 ErrWrite = 0x03,
60 ErrErase = 0x04,
61 ErrCheckErased = 0x05,
62 ErrProg = 0x06,
63 ErrVerify = 0x07,
64 ErrAddress = 0x08,
65 ErrNotDone = 0x09,
66 ErrFirmware = 0x0A,
67 ErrVendor = 0x0B,
68 ErrUsbr = 0x0C,
69 ErrPor = 0x0D,
70 ErrUnknown = 0x0E,
71 ErrStalledPkt = 0x0F,
72}
73
74#[derive(Copy, Clone, PartialEq, Eq)]
75#[repr(u8)]
76pub(crate) enum Request {
77 Detach = 0,
78 Dnload = 1,
79 Upload = 2,
80 GetStatus = 3,
81 ClrStatus = 4,
82 GetState = 5,
83 Abort = 6,
84}
85
86impl TryFrom<u8> for Request {
87 type Error = ();
88
89 fn try_from(value: u8) -> Result<Self, Self::Error> {
90 match value {
91 0 => Ok(Request::Detach),
92 1 => Ok(Request::Dnload),
93 2 => Ok(Request::Upload),
94 3 => Ok(Request::GetStatus),
95 4 => Ok(Request::ClrStatus),
96 5 => Ok(Request::GetState),
97 6 => Ok(Request::Abort),
98 _ => Err(()),
99 }
100 }
101}
diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs
new file mode 100644
index 000000000..e99aa70c3
--- /dev/null
+++ b/embassy-usb-dfu/src/dfu.rs
@@ -0,0 +1,190 @@
1use core::marker::PhantomData;
2
3use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater};
4use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
5use embassy_usb::driver::Driver;
6use embassy_usb::{Builder, Handler};
7use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind};
8
9use crate::consts::{
10 DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU,
11 USB_CLASS_APPN_SPEC,
12};
13use crate::Reset;
14
15/// Internal state for USB DFU
16pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> {
17 updater: BlockingFirmwareUpdater<'d, DFU, STATE>,
18 attrs: DfuAttributes,
19 state: State,
20 status: Status,
21 offset: usize,
22 _rst: PhantomData<RST>,
23}
24
25impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> {
26 /// Create a new DFU instance to handle DFU transfers.
27 pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self {
28 Self {
29 updater,
30 attrs,
31 state: State::DfuIdle,
32 status: Status::Ok,
33 offset: 0,
34 _rst: PhantomData,
35 }
36 }
37
38 fn reset_state(&mut self) {
39 self.offset = 0;
40 self.state = State::DfuIdle;
41 self.status = Status::Ok;
42 }
43}
44
45impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Handler
46 for Control<'d, DFU, STATE, RST, BLOCK_SIZE>
47{
48 fn control_out(
49 &mut self,
50 req: embassy_usb::control::Request,
51 data: &[u8],
52 ) -> Option<embassy_usb::control::OutResponse> {
53 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
54 return None;
55 }
56 match Request::try_from(req.request) {
57 Ok(Request::Abort) => {
58 self.reset_state();
59 Some(OutResponse::Accepted)
60 }
61 Ok(Request::Dnload) if self.attrs.contains(DfuAttributes::CAN_DOWNLOAD) => {
62 if req.value == 0 {
63 self.state = State::Download;
64 self.offset = 0;
65 }
66
67 let mut buf = AlignedBuffer([0; BLOCK_SIZE]);
68 buf.as_mut()[..data.len()].copy_from_slice(data);
69
70 if req.length == 0 {
71 match self.updater.mark_updated() {
72 Ok(_) => {
73 self.status = Status::Ok;
74 self.state = State::ManifestSync;
75 }
76 Err(e) => {
77 self.state = State::Error;
78 match e {
79 embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
80 NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
81 NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress,
82 _ => self.status = Status::ErrUnknown,
83 },
84 embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify,
85 embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown,
86 }
87 }
88 }
89 } else {
90 if self.state != State::Download {
91 // Unexpected DNLOAD while chip is waiting for a GETSTATUS
92 self.status = Status::ErrUnknown;
93 self.state = State::Error;
94 return Some(OutResponse::Rejected);
95 }
96 match self.updater.write_firmware(self.offset, buf.as_ref()) {
97 Ok(_) => {
98 self.status = Status::Ok;
99 self.state = State::DlSync;
100 self.offset += data.len();
101 }
102 Err(e) => {
103 self.state = State::Error;
104 match e {
105 embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
106 NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
107 NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress,
108 _ => self.status = Status::ErrUnknown,
109 },
110 embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify,
111 embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown,
112 }
113 }
114 }
115 }
116
117 Some(OutResponse::Accepted)
118 }
119 Ok(Request::Detach) => Some(OutResponse::Accepted), // Device is already in DFU mode
120 Ok(Request::ClrStatus) => {
121 self.reset_state();
122 Some(OutResponse::Accepted)
123 }
124 _ => None,
125 }
126 }
127
128 fn control_in<'a>(
129 &'a mut self,
130 req: embassy_usb::control::Request,
131 buf: &'a mut [u8],
132 ) -> Option<embassy_usb::control::InResponse<'a>> {
133 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
134 return None;
135 }
136 match Request::try_from(req.request) {
137 Ok(Request::GetStatus) => {
138 //TODO: Configurable poll timeout, ability to add string for Vendor error
139 buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
140 match self.state {
141 State::DlSync => self.state = State::Download,
142 State::ManifestSync => RST::sys_reset(),
143 _ => {}
144 }
145
146 Some(InResponse::Accepted(&buf[0..6]))
147 }
148 Ok(Request::GetState) => {
149 buf[0] = self.state as u8;
150 Some(InResponse::Accepted(&buf[0..1]))
151 }
152 Ok(Request::Upload) if self.attrs.contains(DfuAttributes::CAN_UPLOAD) => {
153 //TODO: FirmwareUpdater does not provide a way of reading the active partition, can't upload.
154 Some(InResponse::Rejected)
155 }
156 _ => None,
157 }
158 }
159}
160
161/// An implementation of the USB DFU 1.1 protocol
162///
163/// This function will add a DFU interface descriptor to the provided Builder, and register the provided Control as a handler for the USB device
164/// The handler is responsive to DFU GetState, GetStatus, Abort, and ClrStatus commands, as well as Download if configured by the user.
165///
166/// Once the host has initiated a DFU download operation, the chunks sent by the host will be written to the DFU partition.
167/// Once the final sync in the manifestation phase has been received, the handler will trigger a system reset to swap the new firmware.
168pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize>(
169 builder: &mut Builder<'d, D>,
170 handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>,
171) {
172 let mut func = builder.function(0x00, 0x00, 0x00);
173 let mut iface = func.interface();
174 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None);
175 alt.descriptor(
176 DESC_DFU_FUNCTIONAL,
177 &[
178 handler.attrs.bits(),
179 0xc4,
180 0x09, // 2500ms timeout, doesn't affect operation as DETACH not necessary in bootloader code
181 (BLOCK_SIZE & 0xff) as u8,
182 ((BLOCK_SIZE & 0xff00) >> 8) as u8,
183 0x10,
184 0x01, // DFU 1.1
185 ],
186 );
187
188 drop(func);
189 builder.handler(handler);
190}
diff --git a/embassy-usb-dfu/src/fmt.rs b/embassy-usb-dfu/src/fmt.rs
new file mode 100644
index 000000000..78e583c1c
--- /dev/null
+++ b/embassy-usb-dfu/src/fmt.rs
@@ -0,0 +1,258 @@
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
232#[allow(unused)]
233pub(crate) struct Bytes<'a>(pub &'a [u8]);
234
235impl<'a> Debug for Bytes<'a> {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{:#02x?}", self.0)
238 }
239}
240
241impl<'a> Display for Bytes<'a> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "{:#02x?}", self.0)
244 }
245}
246
247impl<'a> LowerHex for Bytes<'a> {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 write!(f, "{:#02x?}", self.0)
250 }
251}
252
253#[cfg(feature = "defmt")]
254impl<'a> defmt::Format for Bytes<'a> {
255 fn format(&self, fmt: defmt::Formatter) {
256 defmt::write!(fmt, "{:02x}", self.0)
257 }
258}
diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs
new file mode 100644
index 000000000..eaa4b6e33
--- /dev/null
+++ b/embassy-usb-dfu/src/lib.rs
@@ -0,0 +1,56 @@
1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4mod fmt;
5
6pub mod consts;
7
8#[cfg(feature = "dfu")]
9mod dfu;
10#[cfg(feature = "dfu")]
11pub use self::dfu::*;
12
13#[cfg(feature = "application")]
14mod application;
15#[cfg(feature = "application")]
16pub use self::application::*;
17
18#[cfg(any(
19 all(feature = "dfu", feature = "application"),
20 not(any(feature = "dfu", feature = "application"))
21))]
22compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `application` features");
23
24/// Provides a platform-agnostic interface for initiating a system reset.
25///
26/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a
27/// reset request without interfacing with any other peripherals.
28///
29/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function.
30pub trait Reset {
31 /// Reset the device.
32 fn sys_reset() -> !;
33}
34
35/// Reset immediately.
36#[cfg(feature = "esp32c3-hal")]
37pub struct ResetImmediate;
38
39#[cfg(feature = "esp32c3-hal")]
40impl Reset for ResetImmediate {
41 fn sys_reset() -> ! {
42 esp32c3_hal::reset::software_reset();
43 loop {}
44 }
45}
46
47/// Reset immediately.
48#[cfg(feature = "cortex-m")]
49pub struct ResetImmediate;
50
51#[cfg(feature = "cortex-m")]
52impl Reset for ResetImmediate {
53 fn sys_reset() -> ! {
54 cortex_m::peripheral::SCB::sys_reset()
55 }
56}
diff --git a/embassy-usb-logger/README.md b/embassy-usb-logger/README.md
index 81b0dcd0e..6cb18e87d 100644
--- a/embassy-usb-logger/README.md
+++ b/embassy-usb-logger/README.md
@@ -13,3 +13,17 @@ async fn logger_task(driver: Driver<'static, USB>) {
13 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver); 13 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
14} 14}
15``` 15```
16
17## Minimum supported Rust version (MSRV)
18
19Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
20
21## License
22
23This work is licensed under either of
24
25- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
26 <http://www.apache.org/licenses/LICENSE-2.0>)
27- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
28
29at your option.
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 5f11750b2..b52bac650 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] }
11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } 11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
12embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] } 12embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] }
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index 8b510ed35..f3abfddbc 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -1,7 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![feature(type_alias_impl_trait)]
5 4
6use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; 5use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 6use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/nrf/src/bin/b.rs b/examples/boot/application/nrf/src/bin/b.rs
index a88c3c56c..de97b6a22 100644
--- a/examples/boot/application/nrf/src/bin/b.rs
+++ b/examples/boot/application/nrf/src/bin/b.rs
@@ -1,7 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![feature(type_alias_impl_trait)]
5 4
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Level, Output, OutputDrive}; 6use embassy_nrf::gpio::{Level, Output, OutputDrive};
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
index 89ac5a8f6..08ce16877 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] }
11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } 11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] }
12embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] } 12embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] }
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index 6fd5d7f60..3f0bf90e2 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::cell::RefCell; 4use core::cell::RefCell;
6 5
diff --git a/examples/boot/application/rp/src/bin/b.rs b/examples/boot/application/rp/src/bin/b.rs
index 1eca5b4a2..a46d095bf 100644
--- a/examples/boot/application/rp/src/bin/b.rs
+++ b/examples/boot/application/rp/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use embassy_executor::Spawner; 4use embassy_executor::Spawner;
6use embassy_rp::gpio; 5use embassy_rp::gpio;
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 1a0f8cee5..248ec6dce 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index 8be39bfb7..96ae5c47b 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32f3/src/bin/b.rs b/examples/boot/application/stm32f3/src/bin/b.rs
index 8411f384c..22ba82d5e 100644
--- a/examples/boot/application/stm32f3/src/bin/b.rs
+++ b/examples/boot/application/stm32f3/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index e42d1d421..aa5f87615 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index 0c3819bed..a6107386a 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::cell::RefCell; 4use core::cell::RefCell;
6 5
diff --git a/examples/boot/application/stm32f7/src/bin/b.rs b/examples/boot/application/stm32f7/src/bin/b.rs
index 4c2ad06a2..190477204 100644
--- a/examples/boot/application/stm32f7/src/bin/b.rs
+++ b/examples/boot/application/stm32f7/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 8450d8639..78e33de28 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index f239e3732..b73506cf3 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::cell::RefCell; 4use core::cell::RefCell;
6 5
diff --git a/examples/boot/application/stm32h7/src/bin/b.rs b/examples/boot/application/stm32h7/src/bin/b.rs
index 5c03e2d0c..5f3f35207 100644
--- a/examples/boot/application/stm32h7/src/bin/b.rs
+++ b/examples/boot/application/stm32h7/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index d6684bedb..240afe4c6 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index 42e1a71eb..02f74bdef 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32l0/src/bin/b.rs b/examples/boot/application/stm32l0/src/bin/b.rs
index 52d42395f..6bf00f41a 100644
--- a/examples/boot/application/stm32l0/src/bin/b.rs
+++ b/examples/boot/application/stm32l0/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index cca8bf443..97f1e277b 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index 42e1a71eb..02f74bdef 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32l1/src/bin/b.rs b/examples/boot/application/stm32l1/src/bin/b.rs
index 52d42395f..6bf00f41a 100644
--- a/examples/boot/application/stm32l1/src/bin/b.rs
+++ b/examples/boot/application/stm32l1/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index 30d61056c..0c3830f97 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index eefa25f75..892446968 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32l4/src/bin/b.rs b/examples/boot/application/stm32l4/src/bin/b.rs
index 8411f384c..22ba82d5e 100644
--- a/examples/boot/application/stm32l4/src/bin/b.rs
+++ b/examples/boot/application/stm32l4/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32wb-dfu/.cargo/config.toml b/examples/boot/application/stm32wb-dfu/.cargo/config.toml
new file mode 100644
index 000000000..4f8094ff2
--- /dev/null
+++ b/examples/boot/application/stm32wb-dfu/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32WLE5JCIx"
4
5[build]
6target = "thumbv7em-none-eabihf"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
new file mode 100644
index 000000000..cdaee802e
--- /dev/null
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -0,0 +1,32 @@
1[package]
2edition = "2021"
3name = "embassy-boot-stm32wb-dfu-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" }
15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] }
16
17defmt = { version = "0.3", optional = true }
18defmt-rtt = { version = "0.4", optional = true }
19panic-reset = { version = "0.1.1" }
20embedded-hal = { version = "0.2.6" }
21
22cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
23cortex-m-rt = "0.7.0"
24
25[features]
26defmt = [
27 "dep:defmt",
28 "dep:defmt-rtt",
29 "embassy-stm32/defmt",
30 "embassy-boot-stm32/defmt",
31 "embassy-sync/defmt",
32]
diff --git a/examples/boot/application/stm32wb-dfu/README.md b/examples/boot/application/stm32wb-dfu/README.md
new file mode 100644
index 000000000..c8dce0387
--- /dev/null
+++ b/examples/boot/application/stm32wb-dfu/README.md
@@ -0,0 +1,29 @@
1# Examples using bootloader
2
3Example for STM32WL demonstrating the bootloader. The example consists of application binaries, 'a'
4which allows you to press a button to start the DFU process, and 'b' which is the updated
5application.
6
7
8## Prerequisites
9
10* `cargo-binutils`
11* `cargo-flash`
12* `embassy-boot-stm32`
13
14## Usage
15
16```
17# Flash bootloader
18cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4 --chip STM32WLE5JCIx
19# Build 'b'
20cargo build --release --bin b
21# Generate binary for 'b'
22cargo objcopy --release --bin b -- -O binary b.bin
23```
24
25# Flash `a` (which includes b.bin)
26
27```
28cargo flash --release --bin a --chip STM32WLE5JCIx
29```
diff --git a/examples/boot/application/stm32wb-dfu/build.rs b/examples/boot/application/stm32wb-dfu/build.rs
new file mode 100644
index 000000000..e1da69328
--- /dev/null
+++ b/examples/boot/application/stm32wb-dfu/build.rs
@@ -0,0 +1,37 @@
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 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
35 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
36 }
37}
diff --git a/examples/boot/application/stm32wb-dfu/memory.x b/examples/boot/application/stm32wb-dfu/memory.x
new file mode 100644
index 000000000..ff1b800d2
--- /dev/null
+++ b/examples/boot/application/stm32wb-dfu/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 128K
7 DFU : ORIGIN = 0x08028000, LENGTH = 132K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9}
10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
13
14__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
15__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
new file mode 100644
index 000000000..b2ccb9e1a
--- /dev/null
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -0,0 +1,63 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6#[cfg(feature = "defmt-rtt")]
7use defmt_rtt::*;
8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig};
9use embassy_executor::Spawner;
10use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::rcc::WPAN_DEFAULT;
12use embassy_stm32::usb::{self, Driver};
13use embassy_stm32::{bind_interrupts, peripherals};
14use embassy_sync::blocking_mutex::Mutex;
15use embassy_time::Duration;
16use embassy_usb::Builder;
17use embassy_usb_dfu::consts::DfuAttributes;
18use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate};
19use panic_reset as _;
20
21bind_interrupts!(struct Irqs {
22 USB_LP => usb::InterruptHandler<peripherals::USB>;
23});
24
25#[embassy_executor::main]
26async fn main(_spawner: Spawner) {
27 let mut config = embassy_stm32::Config::default();
28 config.rcc = WPAN_DEFAULT;
29 let p = embassy_stm32::init(config);
30 let flash = Flash::new_blocking(p.FLASH);
31 let flash = Mutex::new(RefCell::new(flash));
32
33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
35 let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0);
36 firmware_state.mark_booted().expect("Failed to mark booted");
37
38 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
39 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
40 config.manufacturer = Some("Embassy");
41 config.product = Some("USB-DFU Runtime example");
42 config.serial_number = Some("1235678");
43
44 let mut device_descriptor = [0; 256];
45 let mut config_descriptor = [0; 256];
46 let mut bos_descriptor = [0; 256];
47 let mut control_buf = [0; 64];
48 let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD);
49 let mut builder = Builder::new(
50 driver,
51 config,
52 &mut device_descriptor,
53 &mut config_descriptor,
54 &mut bos_descriptor,
55 &mut [],
56 &mut control_buf,
57 );
58
59 usb_dfu::<_, _, ResetImmediate>(&mut builder, &mut state, Duration::from_millis(2500));
60
61 let mut dev = builder.build();
62 dev.run().await
63}
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index 7489a2fe9..b5677e148 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index c837e47b5..d9665e6ee 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs
index 1ca3c6ea8..8dd15d8cd 100644
--- a/examples/boot/application/stm32wl/src/bin/b.rs
+++ b/examples/boot/application/stm32wl/src/bin/b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 5use defmt_rtt::*;
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
new file mode 100644
index 000000000..ada073970
--- /dev/null
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -0,0 +1,63 @@
1[package]
2edition = "2021"
3name = "stm32wb-dfu-bootloader-example"
4version = "0.1.0"
5description = "Example USB DFUbootloader for the STM32WB series of chips"
6license = "MIT OR Apache-2.0"
7
8[dependencies]
9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true }
11
12embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
16cortex-m-rt = { version = "0.7" }
17embedded-storage = "0.3.1"
18embedded-storage-async = "0.4.0"
19cfg-if = "1.0.0"
20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] }
21embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false }
22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" }
23
24[features]
25defmt = [
26 "dep:defmt",
27 "embassy-boot-stm32/defmt",
28 "embassy-stm32/defmt",
29 "embassy-usb/defmt",
30 "embassy-usb-dfu/defmt"
31]
32debug = ["defmt-rtt", "defmt"]
33
34[profile.dev]
35debug = 2
36debug-assertions = true
37incremental = false
38opt-level = 'z'
39overflow-checks = true
40
41[profile.release]
42codegen-units = 1
43debug = 2
44debug-assertions = false
45incremental = false
46lto = 'fat'
47opt-level = 'z'
48overflow-checks = false
49
50# do not optimize proc-macro crates = faster builds from scratch
51[profile.dev.build-override]
52codegen-units = 8
53debug = false
54debug-assertions = false
55opt-level = 0
56overflow-checks = false
57
58[profile.release.build-override]
59codegen-units = 8
60debug = false
61debug-assertions = false
62opt-level = 0
63overflow-checks = false
diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md
new file mode 100644
index 000000000..a82b730b9
--- /dev/null
+++ b/examples/boot/bootloader/stm32wb-dfu/README.md
@@ -0,0 +1,11 @@
1# Bootloader for STM32
2
3The bootloader uses `embassy-boot` to interact with the flash.
4
5# Usage
6
7Flash the bootloader
8
9```
10cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx
11```
diff --git a/examples/boot/bootloader/stm32wb-dfu/build.rs b/examples/boot/bootloader/stm32wb-dfu/build.rs
new file mode 100644
index 000000000..fd605991f
--- /dev/null
+++ b/examples/boot/bootloader/stm32wb-dfu/build.rs
@@ -0,0 +1,27 @@
1use std::env;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5
6fn main() {
7 // Put `memory.x` in our output directory and ensure it's
8 // on the linker search path.
9 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10 File::create(out.join("memory.x"))
11 .unwrap()
12 .write_all(include_bytes!("memory.x"))
13 .unwrap();
14 println!("cargo:rustc-link-search={}", out.display());
15
16 // By default, Cargo will re-run a build script whenever
17 // any file in the project changes. By specifying `memory.x`
18 // here, we ensure the build script is only re-run when
19 // `memory.x` is changed.
20 println!("cargo:rerun-if-changed=memory.x");
21
22 println!("cargo:rustc-link-arg-bins=--nmagic");
23 println!("cargo:rustc-link-arg-bins=-Tlink.x");
24 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
25 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
26 }
27}
diff --git a/examples/boot/bootloader/stm32wb-dfu/memory.x b/examples/boot/bootloader/stm32wb-dfu/memory.x
new file mode 100644
index 000000000..858062631
--- /dev/null
+++ b/examples/boot/bootloader/stm32wb-dfu/memory.x
@@ -0,0 +1,18 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 ACTIVE : ORIGIN = 0x08008000, LENGTH = 128K
7 DFU : ORIGIN = 0x08028000, LENGTH = 132K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
9}
10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH);
12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH);
13
14__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH);
15__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH);
16
17__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(FLASH);
18__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(FLASH);
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
new file mode 100644
index 000000000..a7ab813b6
--- /dev/null
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -0,0 +1,93 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use cortex_m_rt::{entry, exception};
7#[cfg(feature = "defmt")]
8use defmt_rtt as _;
9use embassy_boot_stm32::*;
10use embassy_stm32::flash::{Flash, BANK1_REGION, WRITE_SIZE};
11use embassy_stm32::rcc::WPAN_DEFAULT;
12use embassy_stm32::usb::Driver;
13use embassy_stm32::{bind_interrupts, peripherals, usb};
14use embassy_sync::blocking_mutex::Mutex;
15use embassy_usb::Builder;
16use embassy_usb_dfu::consts::DfuAttributes;
17use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate};
18
19bind_interrupts!(struct Irqs {
20 USB_LP => usb::InterruptHandler<peripherals::USB>;
21});
22
23#[entry]
24fn main() -> ! {
25 let mut config = embassy_stm32::Config::default();
26 config.rcc = WPAN_DEFAULT;
27 let p = embassy_stm32::init(config);
28
29 // Prevent a hard fault when accessing flash 'too early' after boot.
30 #[cfg(feature = "defmt")]
31 for _ in 0..10000000 {
32 cortex_m::asm::nop();
33 }
34
35 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
36 let flash = Mutex::new(RefCell::new(layout.bank1_region));
37
38 let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
39 let active_offset = config.active.offset();
40 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
41 if bl.state == State::DfuDetach {
42 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
43 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
44 config.manufacturer = Some("Embassy");
45 config.product = Some("USB-DFU Bootloader example");
46 config.serial_number = Some("1235678");
47
48 let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
49 let mut buffer = AlignedBuffer([0; WRITE_SIZE]);
50 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]);
51
52 let mut device_descriptor = [0; 256];
53 let mut config_descriptor = [0; 256];
54 let mut bos_descriptor = [0; 256];
55 let mut control_buf = [0; 4096];
56 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD);
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut device_descriptor,
61 &mut config_descriptor,
62 &mut bos_descriptor,
63 &mut [],
64 &mut control_buf,
65 );
66
67 usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state);
68
69 let mut dev = builder.build();
70 embassy_futures::block_on(dev.run());
71 }
72
73 unsafe { bl.load(BANK1_REGION.base + active_offset) }
74}
75
76#[no_mangle]
77#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
78unsafe extern "C" fn HardFault() {
79 cortex_m::peripheral::SCB::sys_reset();
80}
81
82#[exception]
83unsafe fn DefaultHandler(_: i16) -> ! {
84 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
85 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
86
87 panic!("DefaultHandler #{:?}", irqn);
88}
89
90#[panic_handler]
91fn panic(_info: &core::panic::PanicInfo) -> ! {
92 cortex_m::asm::udf();
93}
diff --git a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
index 888375693..41cc06417 100644
--- a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
+++ b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::future::poll_fn; 4use core::future::poll_fn;
6use core::task::Poll; 5use core::task::Poll;
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 65cd631f8..bc8a7f2d6 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -4,12 +4,6 @@ name = "embassy-nrf52840-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[features]
8default = ["nightly"]
9nightly = [
10 "static_cell/nightly",
11]
12
13[dependencies] 7[dependencies]
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
@@ -36,9 +30,9 @@ rand = { version = "0.8.4", default-features = false }
36embedded-storage = "0.3.1" 30embedded-storage = "0.3.1"
37usbd-hid = "0.6.0" 31usbd-hid = "0.6.0"
38serde = { version = "1.0.136", default-features = false } 32serde = { version = "1.0.136", default-features = false }
39embedded-hal = { version = "1.0.0-rc.2" } 33embedded-hal = { version = "1.0.0-rc.3" }
40embedded-hal-async = { version = "1.0.0-rc.2" } 34embedded-hal-async = { version = "1.0.0-rc.3" }
41embedded-hal-bus = { version = "0.1.0-rc.2", features = ["async"] } 35embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] }
42num-integer = { version = "0.1.45", default-features = false } 36num-integer = { version = "0.1.45", default-features = false }
43microfft = "0.5.0" 37microfft = "0.5.0"
44 38
diff --git a/examples/nrf52840/src/bin/blinky.rs b/examples/nrf52840/src/bin/blinky.rs
index d3d1a7122..58a3d2cd9 100644
--- a/examples/nrf52840/src/bin/blinky.rs
+++ b/examples/nrf52840/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use embassy_executor::Spawner; 4use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Level, Output, OutputDrive}; 5use embassy_nrf::gpio::{Level, Output, OutputDrive};
diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs
index d9c505786..6ac72bcaf 100644
--- a/examples/nrf52840/src/bin/buffered_uart.rs
+++ b/examples/nrf52840/src/bin/buffered_uart.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs
index d3c7b47d2..7fcea9dbd 100644
--- a/examples/nrf52840/src/bin/channel.rs
+++ b/examples/nrf52840/src/bin/channel.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::unwrap; 4use defmt::unwrap;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs
index 79d2c4048..3095a04ec 100644
--- a/examples/nrf52840/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::unwrap; 4use defmt::unwrap;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index d1b796fab..a8e64b38a 100644
--- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -14,7 +13,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spim};
14use embassy_time::Delay; 13use embassy_time::Delay;
15use embedded_hal_bus::spi::ExclusiveDevice; 14use embedded_hal_bus::spi::ExclusiveDevice;
16use embedded_io_async::Write; 15use embedded_io_async::Write;
17use static_cell::make_static; 16use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
20bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
@@ -70,11 +69,20 @@ async fn main(spawner: Spawner) {
70 let seed = u64::from_le_bytes(seed); 69 let seed = u64::from_le_bytes(seed);
71 70
72 // Init network stack 71 // Init network stack
73 let stack = &*make_static!(Stack::new( 72 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
73 static STACK: StaticCell<
74 Stack<
75 Enc28j60<
76 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>,
77 Output<'static, peripherals::P0_13>,
78 >,
79 >,
80 > = StaticCell::new();
81 let stack = STACK.init(Stack::new(
74 device, 82 device,
75 config, 83 config,
76 make_static!(StackResources::<2>::new()), 84 RESOURCES.init(StackResources::<2>::new()),
77 seed 85 seed,
78 )); 86 ));
79 87
80 unwrap!(spawner.spawn(net_task(stack))); 88 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/nrf52840/src/bin/executor_fairness_test.rs b/examples/nrf52840/src/bin/executor_fairness_test.rs
index f111b272e..df6e7af3f 100644
--- a/examples/nrf52840/src/bin/executor_fairness_test.rs
+++ b/examples/nrf52840/src/bin/executor_fairness_test.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::future::poll_fn; 4use core::future::poll_fn;
6use core::task::Poll; 5use core::task::Poll;
diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs
index 5bfd02465..e254d613d 100644
--- a/examples/nrf52840/src/bin/gpiote_channel.rs
+++ b/examples/nrf52840/src/bin/gpiote_channel.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/gpiote_port.rs b/examples/nrf52840/src/bin/gpiote_port.rs
index 0155d539e..c1afe2f20 100644
--- a/examples/nrf52840/src/bin/gpiote_port.rs
+++ b/examples/nrf52840/src/bin/gpiote_port.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs
index 391514d93..9eadeb4e4 100644
--- a/examples/nrf52840/src/bin/i2s_effect.rs
+++ b/examples/nrf52840/src/bin/i2s_effect.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::f32::consts::PI; 4use core::f32::consts::PI;
6 5
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs
index 4ed597c0d..799be351f 100644
--- a/examples/nrf52840/src/bin/i2s_monitor.rs
+++ b/examples/nrf52840/src/bin/i2s_monitor.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{debug, error, info}; 4use defmt::{debug, error, info};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs
index f2c1166b1..137d82840 100644
--- a/examples/nrf52840/src/bin/i2s_waveform.rs
+++ b/examples/nrf52840/src/bin/i2s_waveform.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::f32::consts::PI; 4use core::f32::consts::PI;
6 5
diff --git a/examples/nrf52840/src/bin/manually_create_executor.rs b/examples/nrf52840/src/bin/manually_create_executor.rs
index 80364d34a..7ca39348e 100644
--- a/examples/nrf52840/src/bin/manually_create_executor.rs
+++ b/examples/nrf52840/src/bin/manually_create_executor.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7 6
8use cortex_m_rt::entry; 7use cortex_m_rt::entry;
9use defmt::{info, unwrap}; 8use defmt::{info, unwrap};
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index 352f62bf2..b634d8569 100644
--- a/examples/nrf52840/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -55,7 +55,6 @@
55 55
56#![no_std] 56#![no_std]
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)]
59 58
60use cortex_m_rt::entry; 59use cortex_m_rt::entry;
61use defmt::{info, unwrap}; 60use defmt::{info, unwrap};
diff --git a/examples/nrf52840/src/bin/mutex.rs b/examples/nrf52840/src/bin/mutex.rs
index 11b47d991..5c22279b5 100644
--- a/examples/nrf52840/src/bin/mutex.rs
+++ b/examples/nrf52840/src/bin/mutex.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/nvmc.rs b/examples/nrf52840/src/bin/nvmc.rs
index 624829863..a79385b98 100644
--- a/examples/nrf52840/src/bin/nvmc.rs
+++ b/examples/nrf52840/src/bin/nvmc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs
index bff323974..52dadc805 100644
--- a/examples/nrf52840/src/bin/pdm.rs
+++ b/examples/nrf52840/src/bin/pdm.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs
index 7d8531475..e948203a5 100644
--- a/examples/nrf52840/src/bin/pdm_continuous.rs
+++ b/examples/nrf52840/src/bin/pdm_continuous.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::cmp::Ordering; 4use core::cmp::Ordering;
6 5
diff --git a/examples/nrf52840/src/bin/ppi.rs b/examples/nrf52840/src/bin/ppi.rs
index d74ce4064..129ad06e7 100644
--- a/examples/nrf52840/src/bin/ppi.rs
+++ b/examples/nrf52840/src/bin/ppi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::future::pending; 4use core::future::pending;
6 5
diff --git a/examples/nrf52840/src/bin/pubsub.rs b/examples/nrf52840/src/bin/pubsub.rs
index 17d902227..5ebea9220 100644
--- a/examples/nrf52840/src/bin/pubsub.rs
+++ b/examples/nrf52840/src/bin/pubsub.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::unwrap; 4use defmt::unwrap;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs
index 9750935c8..a5bb1347a 100644
--- a/examples/nrf52840/src/bin/pwm.rs
+++ b/examples/nrf52840/src/bin/pwm.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/pwm_double_sequence.rs b/examples/nrf52840/src/bin/pwm_double_sequence.rs
index 1bfe6e15a..386c483b8 100644
--- a/examples/nrf52840/src/bin/pwm_double_sequence.rs
+++ b/examples/nrf52840/src/bin/pwm_double_sequence.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/pwm_sequence.rs b/examples/nrf52840/src/bin/pwm_sequence.rs
index f282cf910..87eda265f 100644
--- a/examples/nrf52840/src/bin/pwm_sequence.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
index 6594fa348..60ea712b5 100644
--- a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::future::pending; 4use core::future::pending;
6 5
diff --git a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
index 8596e6545..751cf4425 100644
--- a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs
index 92ded1f88..d772d2f5d 100644
--- a/examples/nrf52840/src/bin/pwm_servo.rs
+++ b/examples/nrf52840/src/bin/pwm_servo.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/qdec.rs b/examples/nrf52840/src/bin/qdec.rs
index 59783d312..ea849be63 100644
--- a/examples/nrf52840/src/bin/qdec.rs
+++ b/examples/nrf52840/src/bin/qdec.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs
index 9e8a01f4e..4539dd0e3 100644
--- a/examples/nrf52840/src/bin/qspi.rs
+++ b/examples/nrf52840/src/bin/qspi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{assert_eq, info, unwrap}; 4use defmt::{assert_eq, info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 42b5454e0..516c9b481 100644
--- a/examples/nrf52840/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::mem; 4use core::mem;
6 5
diff --git a/examples/nrf52840/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs
index 855743f50..326054c9a 100644
--- a/examples/nrf52840/src/bin/rng.rs
+++ b/examples/nrf52840/src/bin/rng.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use embassy_executor::Spawner; 4use embassy_executor::Spawner;
6use embassy_nrf::rng::Rng; 5use embassy_nrf::rng::Rng;
diff --git a/examples/nrf52840/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs
index d651834f5..653b7d606 100644
--- a/examples/nrf52840/src/bin/saadc.rs
+++ b/examples/nrf52840/src/bin/saadc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
index a5f8a4dd7..f76fa3570 100644
--- a/examples/nrf52840/src/bin/saadc_continuous.rs
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs
index 8a58396a4..5bfefc2af 100644
--- a/examples/nrf52840/src/bin/self_spawn.rs
+++ b/examples/nrf52840/src/bin/self_spawn.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/self_spawn_current_executor.rs b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
index 65d50f8c3..ec9569a64 100644
--- a/examples/nrf52840/src/bin/self_spawn_current_executor.rs
+++ b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/spim.rs b/examples/nrf52840/src/bin/spim.rs
index 9d1843a8f..131187660 100644
--- a/examples/nrf52840/src/bin/spim.rs
+++ b/examples/nrf52840/src/bin/spim.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs
index 77b6e8b64..613cd37ab 100644
--- a/examples/nrf52840/src/bin/spis.rs
+++ b/examples/nrf52840/src/bin/spis.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/temp.rs b/examples/nrf52840/src/bin/temp.rs
index d94dea38d..1d28f8ecf 100644
--- a/examples/nrf52840/src/bin/temp.rs
+++ b/examples/nrf52840/src/bin/temp.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/timer.rs b/examples/nrf52840/src/bin/timer.rs
index 9b9bb3eb4..365695a20 100644
--- a/examples/nrf52840/src/bin/timer.rs
+++ b/examples/nrf52840/src/bin/timer.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs
index 959e3a4be..a9a0765e8 100644
--- a/examples/nrf52840/src/bin/twim.rs
+++ b/examples/nrf52840/src/bin/twim.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
index bf9f966ef..c743614b8 100644
--- a/examples/nrf52840/src/bin/twim_lowpower.rs
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
@@ -6,7 +6,6 @@
6 6
7#![no_std] 7#![no_std]
8#![no_main] 8#![no_main]
9#![feature(type_alias_impl_trait)]
10 9
11use core::mem; 10use core::mem;
12 11
diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs
index aa42b679e..88bd4cceb 100644
--- a/examples/nrf52840/src/bin/twis.rs
+++ b/examples/nrf52840/src/bin/twis.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs
index 50d5cab8c..accaccea1 100644
--- a/examples/nrf52840/src/bin/uart.rs
+++ b/examples/nrf52840/src/bin/uart.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs
index e1f42fa6c..fa93bcf21 100644
--- a/examples/nrf52840/src/bin/uart_idle.rs
+++ b/examples/nrf52840/src/bin/uart_idle.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index b748bfcd8..c7510a9a8 100644
--- a/examples/nrf52840/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index b7806f418..3469c6e5f 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::mem; 4use core::mem;
6 5
@@ -16,7 +15,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
16use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 15use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
17use embassy_usb::{Builder, Config, UsbDevice}; 16use embassy_usb::{Builder, Config, UsbDevice};
18use embedded_io_async::Write; 17use embedded_io_async::Write;
19use static_cell::make_static; 18use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
21 20
22bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
@@ -71,14 +70,19 @@ async fn main(spawner: Spawner) {
71 config.device_protocol = 0x01; 70 config.device_protocol = 0x01;
72 71
73 // Create embassy-usb DeviceBuilder using the driver and config. 72 // Create embassy-usb DeviceBuilder using the driver and config.
73 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
74 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
75 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
76 static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new();
77 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
74 let mut builder = Builder::new( 78 let mut builder = Builder::new(
75 driver, 79 driver,
76 config, 80 config,
77 &mut make_static!([0; 256])[..], 81 &mut DEVICE_DESC.init([0; 256])[..],
78 &mut make_static!([0; 256])[..], 82 &mut CONFIG_DESC.init([0; 256])[..],
79 &mut make_static!([0; 256])[..], 83 &mut BOS_DESC.init([0; 256])[..],
80 &mut make_static!([0; 128])[..], 84 &mut MSOS_DESC.init([0; 128])[..],
81 &mut make_static!([0; 128])[..], 85 &mut CONTROL_BUF.init([0; 128])[..],
82 ); 86 );
83 87
84 // Our MAC addr. 88 // Our MAC addr.
@@ -87,14 +91,16 @@ async fn main(spawner: Spawner) {
87 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 91 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
88 92
89 // Create classes on the builder. 93 // Create classes on the builder.
90 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); 94 static STATE: StaticCell<State> = StaticCell::new();
95 let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64);
91 96
92 // Build the builder. 97 // Build the builder.
93 let usb = builder.build(); 98 let usb = builder.build();
94 99
95 unwrap!(spawner.spawn(usb_task(usb))); 100 unwrap!(spawner.spawn(usb_task(usb)));
96 101
97 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 102 static NET_STATE: StaticCell<NetState<MTU, 4, 4>> = StaticCell::new();
103 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(NET_STATE.init(NetState::new()), our_mac_addr);
98 unwrap!(spawner.spawn(usb_ncm_task(runner))); 104 unwrap!(spawner.spawn(usb_ncm_task(runner)));
99 105
100 let config = embassy_net::Config::dhcpv4(Default::default()); 106 let config = embassy_net::Config::dhcpv4(Default::default());
@@ -111,12 +117,9 @@ async fn main(spawner: Spawner) {
111 let seed = u64::from_le_bytes(seed); 117 let seed = u64::from_le_bytes(seed);
112 118
113 // Init network stack 119 // Init network stack
114 let stack = &*make_static!(Stack::new( 120 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
115 device, 121 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
116 config, 122 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
117 make_static!(StackResources::<2>::new()),
118 seed
119 ));
120 123
121 unwrap!(spawner.spawn(net_task(stack))); 124 unwrap!(spawner.spawn(net_task(stack)));
122 125
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 7ccd2946a..45850b4a4 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::mem; 4use core::mem;
6use core::sync::atomic::{AtomicBool, Ordering}; 5use core::sync::atomic::{AtomicBool, Ordering};
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 96fcf8a66..04ad841b7 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::mem; 4use core::mem;
6 5
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index dc95cde84..aff539b1b 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::mem; 4use core::mem;
6 5
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index cd4392903..4e8118fb8 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::mem; 4use core::mem;
6 5
@@ -12,7 +11,7 @@ use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
14use embassy_usb::{Builder, Config, UsbDevice}; 13use embassy_usb::{Builder, Config, UsbDevice};
15use static_cell::make_static; 14use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
18bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
@@ -64,17 +63,23 @@ async fn main(spawner: Spawner) {
64 config.device_protocol = 0x01; 63 config.device_protocol = 0x01;
65 config.composite_with_iads = true; 64 config.composite_with_iads = true;
66 65
67 let state = make_static!(State::new()); 66 static STATE: StaticCell<State> = StaticCell::new();
67 let state = STATE.init(State::new());
68 68
69 // Create embassy-usb DeviceBuilder using the driver and config. 69 // Create embassy-usb DeviceBuilder using the driver and config.
70 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
71 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
72 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
73 static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new();
74 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
70 let mut builder = Builder::new( 75 let mut builder = Builder::new(
71 driver, 76 driver,
72 config, 77 config,
73 &mut make_static!([0; 256])[..], 78 &mut DEVICE_DESC.init([0; 256])[..],
74 &mut make_static!([0; 256])[..], 79 &mut CONFIG_DESC.init([0; 256])[..],
75 &mut make_static!([0; 256])[..], 80 &mut BOS_DESC.init([0; 256])[..],
76 &mut make_static!([0; 128])[..], 81 &mut MSOS_DESC.init([0; 128])[..],
77 &mut make_static!([0; 128])[..], 82 &mut CONTROL_BUF.init([0; 128])[..],
78 ); 83 );
79 84
80 // Create classes on the builder. 85 // Create classes on the builder.
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
index 1d39d3841..060f9ba94 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::mem; 4use core::mem;
6 5
diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
index 058746518..ede88cc26 100644
--- a/examples/nrf52840/src/bin/wdt.rs
+++ b/examples/nrf52840/src/bin/wdt.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index a60822fd9..fc2086f75 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap, warn}; 4use defmt::{info, unwrap, warn};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -13,7 +12,7 @@ use embassy_nrf::{bind_interrupts, peripherals};
13use embassy_time::Delay; 12use embassy_time::Delay;
14use embedded_hal_bus::spi::ExclusiveDevice; 13use embedded_hal_bus::spi::ExclusiveDevice;
15use embedded_io_async::Write; 14use embedded_io_async::Write;
16use static_cell::make_static; 15use static_cell::StaticCell;
17use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; 16use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
18 17
19const WIFI_NETWORK: &str = "EmbassyTest"; 18const WIFI_NETWORK: &str = "EmbassyTest";
@@ -61,8 +60,9 @@ async fn main(spawner: Spawner) {
61 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); 60 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
62 let spi = ExclusiveDevice::new(spi, cs, Delay); 61 let spi = ExclusiveDevice::new(spi, cs, Delay);
63 62
63 static ESP_STATE: StaticCell<embassy_net_esp_hosted::State> = StaticCell::new();
64 let (device, mut control, runner) = embassy_net_esp_hosted::new( 64 let (device, mut control, runner) = embassy_net_esp_hosted::new(
65 make_static!(embassy_net_esp_hosted::State::new()), 65 ESP_STATE.init(embassy_net_esp_hosted::State::new()),
66 spi, 66 spi,
67 handshake, 67 handshake,
68 ready, 68 ready,
@@ -89,11 +89,13 @@ async fn main(spawner: Spawner) {
89 let seed = u64::from_le_bytes(seed); 89 let seed = u64::from_le_bytes(seed);
90 90
91 // Init network stack 91 // Init network stack
92 let stack = &*make_static!(Stack::new( 92 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
93 static STACK: StaticCell<Stack<hosted::NetDriver<'static>>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new(
93 device, 95 device,
94 config, 96 config,
95 make_static!(StackResources::<2>::new()), 97 RESOURCES.init(StackResources::<2>::new()),
96 seed 98 seed,
97 )); 99 ));
98 100
99 unwrap!(spawner.spawn(net_task(stack))); 101 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 17d3e30e4..fc0346f90 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } 12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] }
13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
@@ -17,7 +17,7 @@ embedded-io-async = { version = "0.6.1" }
17defmt = "0.3" 17defmt = "0.3"
18defmt-rtt = "0.4" 18defmt-rtt = "0.4"
19 19
20static_cell = { version = "2", features = ["nightly"]} 20static_cell = "2"
21cortex-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"] }
22cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
23panic-probe = { version = "0.3", features = ["print-defmt"] } 23panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/examples/nrf5340/src/bin/blinky.rs b/examples/nrf5340/src/bin/blinky.rs
index b784564a5..5c533c9b1 100644
--- a/examples/nrf5340/src/bin/blinky.rs
+++ b/examples/nrf5340/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use embassy_executor::Spawner; 4use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Level, Output, OutputDrive}; 5use embassy_nrf::gpio::{Level, Output, OutputDrive};
diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs
index ceab1194a..c0a55142f 100644
--- a/examples/nrf5340/src/bin/gpiote_channel.rs
+++ b/examples/nrf5340/src/bin/gpiote_channel.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/nrf5340/src/bin/uart.rs b/examples/nrf5340/src/bin/uart.rs
index d68539702..7b41d7463 100644
--- a/examples/nrf5340/src/bin/uart.rs
+++ b/examples/nrf5340/src/bin/uart.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 7f637758d..07de83203 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.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "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"] }
@@ -38,12 +38,12 @@ smart-leds = "0.3.0"
38heapless = "0.8" 38heapless = "0.8"
39usbd-hid = "0.6.1" 39usbd-hid = "0.6.1"
40 40
41embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 41embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
42embedded-hal-async = "1.0.0-rc.2" 42embedded-hal-async = "1.0.0-rc.3"
43embedded-hal-bus = { version = "0.1.0-rc.2", features = ["async"] } 43embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] }
44embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 44embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
45embedded-storage = { version = "0.3" } 45embedded-storage = { version = "0.3" }
46static_cell = { version = "2", features = ["nightly"]} 46static_cell = "2"
47portable-atomic = { version = "1.5", features = ["critical-section"] } 47portable-atomic = { version = "1.5", features = ["critical-section"] }
48log = "0.4" 48log = "0.4"
49pio-proc = "0.2" 49pio-proc = "0.2"
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
index a579be139..1bb7c2249 100644
--- a/examples/rp/src/bin/adc.rs
+++ b/examples/rp/src/bin/adc.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7 6
8use defmt::*; 7use defmt::*;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/blinky.rs b/examples/rp/src/bin/blinky.rs
index 66c8773fa..60fc45a70 100644
--- a/examples/rp/src/bin/blinky.rs
+++ b/examples/rp/src/bin/blinky.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs
index d7aa89410..e9054fd48 100644
--- a/examples/rp/src/bin/button.rs
+++ b/examples/rp/src/bin/button.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_rp::gpio::{Input, Level, Output, Pull}; 9use embassy_rp::gpio::{Input, Level, Output, Pull};
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 16
18 // Use PIN_28, Pin34 on J0 for RP Pico, as a input. 17 // Use PIN_28, Pin34 on J0 for RP Pico, as a input.
19 // You need to add your own button. 18 // You need to add your own button.
20 let button = Input::new(p.PIN_28, Pull::Up); 19 let mut button = Input::new(p.PIN_28, Pull::Up);
21 20
22 loop { 21 loop {
23 if button.is_high() { 22 if button.is_high() {
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index c0fde62ab..a16ea0007 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
@@ -20,7 +19,7 @@ use embassy_time::{Delay, Duration};
20use embedded_hal_bus::spi::ExclusiveDevice; 19use embedded_hal_bus::spi::ExclusiveDevice;
21use embedded_io_async::Write; 20use embedded_io_async::Write;
22use rand::RngCore; 21use rand::RngCore;
23use static_cell::make_static; 22use static_cell::StaticCell;
24use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
25 24
26#[embassy_executor::task] 25#[embassy_executor::task]
@@ -55,7 +54,8 @@ async fn main(spawner: Spawner) {
55 let w5500_reset = Output::new(p.PIN_20, Level::High); 54 let w5500_reset = Output::new(p.PIN_20, Level::High);
56 55
57 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
58 let state = make_static!(State::<8, 8>::new()); 57 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
58 let state = STATE.init(State::<8, 8>::new());
59 let (device, runner) = embassy_net_wiznet::new( 59 let (device, runner) = embassy_net_wiznet::new(
60 mac_addr, 60 mac_addr,
61 state, 61 state,
@@ -70,11 +70,13 @@ async fn main(spawner: Spawner) {
70 let seed = rng.next_u64(); 70 let seed = rng.next_u64();
71 71
72 // Init network stack 72 // Init network stack
73 let stack = &*make_static!(Stack::new( 73 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
74 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
75 let stack = &*STACK.init(Stack::new(
74 device, 76 device,
75 embassy_net::Config::dhcpv4(Default::default()), 77 embassy_net::Config::dhcpv4(Default::default()),
76 make_static!(StackResources::<3>::new()), 78 RESOURCES.init(StackResources::<3>::new()),
77 seed 79 seed,
78 )); 80 ));
79 81
80 // Launch network task 82 // Launch network task
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index b19362fc1..975b3d385 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use core::str::FromStr; 8use core::str::FromStr;
10 9
@@ -22,7 +21,7 @@ use embassy_time::{Delay, Duration, Timer};
22use embedded_hal_bus::spi::ExclusiveDevice; 21use embedded_hal_bus::spi::ExclusiveDevice;
23use embedded_io_async::Write; 22use embedded_io_async::Write;
24use rand::RngCore; 23use rand::RngCore;
25use static_cell::make_static; 24use static_cell::StaticCell;
26use {defmt_rtt as _, panic_probe as _}; 25use {defmt_rtt as _, panic_probe as _};
27 26
28#[embassy_executor::task] 27#[embassy_executor::task]
@@ -58,7 +57,8 @@ async fn main(spawner: Spawner) {
58 let w5500_reset = Output::new(p.PIN_20, Level::High); 57 let w5500_reset = Output::new(p.PIN_20, Level::High);
59 58
60 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 59 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
61 let state = make_static!(State::<8, 8>::new()); 60 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
61 let state = STATE.init(State::<8, 8>::new());
62 let (device, runner) = embassy_net_wiznet::new( 62 let (device, runner) = embassy_net_wiznet::new(
63 mac_addr, 63 mac_addr,
64 state, 64 state,
@@ -73,11 +73,13 @@ async fn main(spawner: Spawner) {
73 let seed = rng.next_u64(); 73 let seed = rng.next_u64();
74 74
75 // Init network stack 75 // Init network stack
76 let stack = &*make_static!(Stack::new( 76 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
77 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
78 let stack = &*STACK.init(Stack::new(
77 device, 79 device,
78 embassy_net::Config::dhcpv4(Default::default()), 80 embassy_net::Config::dhcpv4(Default::default()),
79 make_static!(StackResources::<2>::new()), 81 RESOURCES.init(StackResources::<2>::new()),
80 seed 82 seed,
81 )); 83 ));
82 84
83 // Launch network task 85 // Launch network task
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index c62caed7a..489af2c76 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -5,7 +5,6 @@
5 5
6#![no_std] 6#![no_std]
7#![no_main] 7#![no_main]
8#![feature(type_alias_impl_trait)]
9 8
10use defmt::*; 9use defmt::*;
11use embassy_executor::Spawner; 10use embassy_executor::Spawner;
@@ -21,7 +20,7 @@ use embassy_time::{Delay, Duration};
21use embedded_hal_bus::spi::ExclusiveDevice; 20use embedded_hal_bus::spi::ExclusiveDevice;
22use embedded_io_async::Write; 21use embedded_io_async::Write;
23use rand::RngCore; 22use rand::RngCore;
24use static_cell::make_static; 23use static_cell::StaticCell;
25use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
26 25
27#[embassy_executor::task] 26#[embassy_executor::task]
@@ -57,7 +56,8 @@ async fn main(spawner: Spawner) {
57 let w5500_reset = Output::new(p.PIN_20, Level::High); 56 let w5500_reset = Output::new(p.PIN_20, Level::High);
58 57
59 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 58 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
60 let state = make_static!(State::<8, 8>::new()); 59 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
60 let state = STATE.init(State::<8, 8>::new());
61 let (device, runner) = embassy_net_wiznet::new( 61 let (device, runner) = embassy_net_wiznet::new(
62 mac_addr, 62 mac_addr,
63 state, 63 state,
@@ -72,11 +72,13 @@ async fn main(spawner: Spawner) {
72 let seed = rng.next_u64(); 72 let seed = rng.next_u64();
73 73
74 // Init network stack 74 // Init network stack
75 let stack = &*make_static!(Stack::new( 75 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
76 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
77 let stack = &*STACK.init(Stack::new(
76 device, 78 device,
77 embassy_net::Config::dhcpv4(Default::default()), 79 embassy_net::Config::dhcpv4(Default::default()),
78 make_static!(StackResources::<2>::new()), 80 RESOURCES.init(StackResources::<2>::new()),
79 seed 81 seed,
80 )); 82 ));
81 83
82 // Launch network task 84 // Launch network task
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index 76dabce1c..41bd7d077 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
@@ -20,7 +19,7 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
20use embassy_time::Delay; 19use embassy_time::Delay;
21use embedded_hal_bus::spi::ExclusiveDevice; 20use embedded_hal_bus::spi::ExclusiveDevice;
22use rand::RngCore; 21use rand::RngCore;
23use static_cell::make_static; 22use static_cell::StaticCell;
24use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
25 24
26#[embassy_executor::task] 25#[embassy_executor::task]
@@ -55,7 +54,8 @@ async fn main(spawner: Spawner) {
55 let w5500_reset = Output::new(p.PIN_20, Level::High); 54 let w5500_reset = Output::new(p.PIN_20, Level::High);
56 55
57 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
58 let state = make_static!(State::<8, 8>::new()); 57 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
58 let state = STATE.init(State::<8, 8>::new());
59 let (device, runner) = embassy_net_wiznet::new( 59 let (device, runner) = embassy_net_wiznet::new(
60 mac_addr, 60 mac_addr,
61 state, 61 state,
@@ -70,11 +70,13 @@ async fn main(spawner: Spawner) {
70 let seed = rng.next_u64(); 70 let seed = rng.next_u64();
71 71
72 // Init network stack 72 // Init network stack
73 let stack = &*make_static!(Stack::new( 73 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
74 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
75 let stack = &*STACK.init(Stack::new(
74 device, 76 device,
75 embassy_net::Config::dhcpv4(Default::default()), 77 embassy_net::Config::dhcpv4(Default::default()),
76 make_static!(StackResources::<2>::new()), 78 RESOURCES.init(StackResources::<2>::new()),
77 seed 79 seed,
78 )); 80 ));
79 81
80 // Launch network task 82 // Launch network task
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
index 129a8497f..eb3e6a2b9 100644
--- a/examples/rp/src/bin/flash.rs
+++ b/examples/rp/src/bin/flash.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/gpio_async.rs b/examples/rp/src/bin/gpio_async.rs
index 98209fe41..b79fb2a15 100644
--- a/examples/rp/src/bin/gpio_async.rs
+++ b/examples/rp/src/bin/gpio_async.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs
index 896cc15ee..011359253 100644
--- a/examples/rp/src/bin/gpout.rs
+++ b/examples/rp/src/bin/gpout.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs
index 7b53aae72..e31cc894c 100644
--- a/examples/rp/src/bin/i2c_async.rs
+++ b/examples/rp/src/bin/i2c_async.rs
@@ -5,7 +5,6 @@
5 5
6#![no_std] 6#![no_std]
7#![no_main] 7#![no_main]
8#![feature(type_alias_impl_trait)]
9 8
10use defmt::*; 9use defmt::*;
11use embassy_executor::Spawner; 10use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/i2c_blocking.rs b/examples/rp/src/bin/i2c_blocking.rs
index 9ddb48d69..c9c8a2760 100644
--- a/examples/rp/src/bin/i2c_blocking.rs
+++ b/examples/rp/src/bin/i2c_blocking.rs
@@ -5,7 +5,6 @@
5 5
6#![no_std] 6#![no_std]
7#![no_main] 7#![no_main]
8#![feature(type_alias_impl_trait)]
9 8
10use defmt::*; 9use defmt::*;
11use embassy_executor::Spawner; 10use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs
index 151b083a4..479f9a16a 100644
--- a/examples/rp/src/bin/i2c_slave.rs
+++ b/examples/rp/src/bin/i2c_slave.rs
@@ -1,7 +1,6 @@
1//! This example shows how to use the 2040 as an i2c slave. 1//! This example shows how to use the 2040 as an i2c slave.
2#![no_std] 2#![no_std]
3#![no_main] 3#![no_main]
4#![feature(type_alias_impl_trait)]
5 4
6use defmt::*; 5use defmt::*;
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
index 43eaf8b0a..a1678d99a 100644
--- a/examples/rp/src/bin/multicore.rs
+++ b/examples/rp/src/bin/multicore.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Executor; 9use embassy_executor::Executor;
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs
index 28f621437..26b80c11d 100644
--- a/examples/rp/src/bin/multiprio.rs
+++ b/examples/rp/src/bin/multiprio.rs
@@ -55,7 +55,6 @@
55 55
56#![no_std] 56#![no_std]
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)]
59 58
60use cortex_m_rt::entry; 59use cortex_m_rt::entry;
61use defmt::{info, unwrap}; 60use defmt::{info, unwrap};
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
index a6d6144be..ee248591b 100644
--- a/examples/rp/src/bin/pio_async.rs
+++ b/examples/rp/src/bin/pio_async.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6use defmt::info; 5use defmt::info;
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts; 7use embassy_rp::bind_interrupts;
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
index 86e5017ac..02700269c 100644
--- a/examples/rp/src/bin/pio_dma.rs
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6use defmt::info; 5use defmt::info;
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
8use embassy_futures::join::join; 7use embassy_futures::join::join;
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
index 5e5a6f9a3..3fab7b5f2 100644
--- a/examples/rp/src/bin/pio_hd44780.rs
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7 6
8use core::fmt::Write; 7use core::fmt::Write;
9 8
diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs
index 6d9d59df6..58bdadbc0 100644
--- a/examples/rp/src/bin/pio_rotary_encoder.rs
+++ b/examples/rp/src/bin/pio_rotary_encoder.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6 5
7use defmt::info; 6use defmt::info;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs
index 02fb20699..ab9ecf623 100644
--- a/examples/rp/src/bin/pio_stepper.rs
+++ b/examples/rp/src/bin/pio_stepper.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7use core::mem::{self, MaybeUninit}; 6use core::mem::{self, MaybeUninit};
8 7
9use defmt::info; 8use defmt::info;
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs
index c0ea23607..a07f1c180 100644
--- a/examples/rp/src/bin/pio_uart.rs
+++ b/examples/rp/src/bin/pio_uart.rs
@@ -8,7 +8,6 @@
8 8
9#![no_std] 9#![no_std]
10#![no_main] 10#![no_main]
11#![feature(type_alias_impl_trait)]
12#![allow(async_fn_in_trait)] 11#![allow(async_fn_in_trait)]
13 12
14use defmt::{info, panic, trace}; 13use defmt::{info, panic, trace};
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
index 7b3259538..9a97cb8a7 100644
--- a/examples/rp/src/bin/pio_ws2812.rs
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7 6
8use defmt::*; 7use defmt::*;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs
index a99e88003..4fb62546d 100644
--- a/examples/rp/src/bin/pwm.rs
+++ b/examples/rp/src/bin/pwm.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/pwm_input.rs b/examples/rp/src/bin/pwm_input.rs
index 0fc2e40c3..e7bcbfbd4 100644
--- a/examples/rp/src/bin/pwm_input.rs
+++ b/examples/rp/src/bin/pwm_input.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/rosc.rs b/examples/rp/src/bin/rosc.rs
index f841043b6..942b72319 100644
--- a/examples/rp/src/bin/rosc.rs
+++ b/examples/rp/src/bin/rosc.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/rtc.rs b/examples/rp/src/bin/rtc.rs
index 667876db5..e9a5e43a8 100644
--- a/examples/rp/src/bin/rtc.rs
+++ b/examples/rp/src/bin/rtc.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs
index 602348f7a..4cc4f5210 100644
--- a/examples/rp/src/bin/spi.rs
+++ b/examples/rp/src/bin/spi.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/spi_async.rs b/examples/rp/src/bin/spi_async.rs
index f5a2d334e..266584efc 100644
--- a/examples/rp/src/bin/spi_async.rs
+++ b/examples/rp/src/bin/spi_async.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7 6
8use defmt::*; 7use defmt::*;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
index 26c258e1c..e937b9d0a 100644
--- a/examples/rp/src/bin/spi_display.rs
+++ b/examples/rp/src/bin/spi_display.rs
@@ -5,7 +5,6 @@
5 5
6#![no_std] 6#![no_std]
7#![no_main] 7#![no_main]
8#![feature(type_alias_impl_trait)]
9 8
10use core::cell::RefCell; 9use core::cell::RefCell;
11 10
diff --git a/examples/rp/src/bin/uart.rs b/examples/rp/src/bin/uart.rs
index 451c3c396..6a2816cd0 100644
--- a/examples/rp/src/bin/uart.rs
+++ b/examples/rp/src/bin/uart.rs
@@ -6,7 +6,6 @@
6 6
7#![no_std] 7#![no_std]
8#![no_main] 8#![no_main]
9#![feature(type_alias_impl_trait)]
10 9
11use embassy_executor::Spawner; 10use embassy_executor::Spawner;
12use embassy_rp::uart; 11use embassy_rp::uart;
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index 14e8810a4..fac61aa04 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -6,7 +6,6 @@
6 6
7#![no_std] 7#![no_std]
8#![no_main] 8#![no_main]
9#![feature(type_alias_impl_trait)]
10 9
11use defmt::*; 10use defmt::*;
12use embassy_executor::Spawner; 11use embassy_executor::Spawner;
@@ -15,7 +14,7 @@ use embassy_rp::peripherals::UART0;
15use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; 14use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
16use embassy_time::Timer; 15use embassy_time::Timer;
17use embedded_io_async::{Read, Write}; 16use embedded_io_async::{Read, Write};
18use static_cell::make_static; 17use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
20 19
21bind_interrupts!(struct Irqs { 20bind_interrupts!(struct Irqs {
@@ -27,8 +26,10 @@ async fn main(spawner: Spawner) {
27 let p = embassy_rp::init(Default::default()); 26 let p = embassy_rp::init(Default::default());
28 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0); 27 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
29 28
30 let tx_buf = &mut make_static!([0u8; 16])[..]; 29 static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
31 let rx_buf = &mut make_static!([0u8; 16])[..]; 30 let tx_buf = &mut TX_BUF.init([0; 16])[..];
31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
32 let rx_buf = &mut RX_BUF.init([0; 16])[..];
32 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); 33 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
33 let (rx, mut tx) = uart.split(); 34 let (rx, mut tx) = uart.split();
34 35
diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs
index 42c8b432e..a45f40756 100644
--- a/examples/rp/src/bin/uart_unidir.rs
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -7,7 +7,6 @@
7 7
8#![no_std] 8#![no_std]
9#![no_main] 9#![no_main]
10#![feature(type_alias_impl_trait)]
11 10
12use defmt::*; 11use defmt::*;
13use embassy_executor::Spawner; 12use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index cc63029fb..01f0d5967 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
@@ -17,7 +16,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
17use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 16use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
18use embassy_usb::{Builder, Config, UsbDevice}; 17use embassy_usb::{Builder, Config, UsbDevice};
19use embedded_io_async::Write; 18use embedded_io_async::Write;
20use static_cell::make_static; 19use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
22 21
23bind_interrupts!(struct Irqs { 22bind_interrupts!(struct Irqs {
@@ -65,14 +64,18 @@ async fn main(spawner: Spawner) {
65 config.device_protocol = 0x01; 64 config.device_protocol = 0x01;
66 65
67 // Create embassy-usb DeviceBuilder using the driver and config. 66 // Create embassy-usb DeviceBuilder using the driver and config.
67 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
68 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
69 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
70 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
68 let mut builder = Builder::new( 71 let mut builder = Builder::new(
69 driver, 72 driver,
70 config, 73 config,
71 &mut make_static!([0; 256])[..], 74 &mut DEVICE_DESC.init([0; 256])[..],
72 &mut make_static!([0; 256])[..], 75 &mut CONFIG_DESC.init([0; 256])[..],
73 &mut make_static!([0; 256])[..], 76 &mut BOS_DESC.init([0; 256])[..],
74 &mut [], // no msos descriptors 77 &mut [], // no msos descriptors
75 &mut make_static!([0; 128])[..], 78 &mut CONTROL_BUF.init([0; 128])[..],
76 ); 79 );
77 80
78 // Our MAC addr. 81 // Our MAC addr.
@@ -81,14 +84,16 @@ async fn main(spawner: Spawner) {
81 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 84 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
82 85
83 // Create classes on the builder. 86 // Create classes on the builder.
84 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); 87 static STATE: StaticCell<State> = StaticCell::new();
88 let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64);
85 89
86 // Build the builder. 90 // Build the builder.
87 let usb = builder.build(); 91 let usb = builder.build();
88 92
89 unwrap!(spawner.spawn(usb_task(usb))); 93 unwrap!(spawner.spawn(usb_task(usb)));
90 94
91 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 95 static NET_STATE: StaticCell<NetState<MTU, 4, 4>> = StaticCell::new();
96 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(NET_STATE.init(NetState::new()), our_mac_addr);
92 unwrap!(spawner.spawn(usb_ncm_task(runner))); 97 unwrap!(spawner.spawn(usb_ncm_task(runner)));
93 98
94 let config = embassy_net::Config::dhcpv4(Default::default()); 99 let config = embassy_net::Config::dhcpv4(Default::default());
@@ -102,11 +107,13 @@ async fn main(spawner: Spawner) {
102 let seed = 1234; // guaranteed random, chosen by a fair dice roll 107 let seed = 1234; // guaranteed random, chosen by a fair dice roll
103 108
104 // Init network stack 109 // Init network stack
105 let stack = &*make_static!(Stack::new( 110 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
111 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
112 let stack = &*STACK.init(Stack::new(
106 device, 113 device,
107 config, 114 config,
108 make_static!(StackResources::<2>::new()), 115 RESOURCES.init(StackResources::<2>::new()),
109 seed 116 seed,
110 )); 117 ));
111 118
112 unwrap!(spawner.spawn(net_task(stack))); 119 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
index 569c9b12b..b5ac16245 100644
--- a/examples/rp/src/bin/usb_hid_keyboard.rs
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, Ordering};
6 5
diff --git a/examples/rp/src/bin/usb_logger.rs b/examples/rp/src/bin/usb_logger.rs
index 791f15e56..af401ed63 100644
--- a/examples/rp/src/bin/usb_logger.rs
+++ b/examples/rp/src/bin/usb_logger.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 9use embassy_rp::bind_interrupts;
diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs
index d5cdae319..95306a35c 100644
--- a/examples/rp/src/bin/usb_midi.rs
+++ b/examples/rp/src/bin/usb_midi.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::{info, panic}; 8use defmt::{info, panic};
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs
index f59262e5c..a6c8a5b2e 100644
--- a/examples/rp/src/bin/usb_raw.rs
+++ b/examples/rp/src/bin/usb_raw.rs
@@ -48,7 +48,6 @@
48 48
49#![no_std] 49#![no_std]
50#![no_main] 50#![no_main]
51#![feature(type_alias_impl_trait)]
52 51
53use defmt::info; 52use defmt::info;
54use embassy_executor::Spawner; 53use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs
index 288be5a4e..0dc8e9f72 100644
--- a/examples/rp/src/bin/usb_raw_bulk.rs
+++ b/examples/rp/src/bin/usb_raw_bulk.rs
@@ -26,7 +26,6 @@
26 26
27#![no_std] 27#![no_std]
28#![no_main] 28#![no_main]
29#![feature(type_alias_impl_trait)]
30 29
31use defmt::info; 30use defmt::info;
32use embassy_executor::Spawner; 31use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index 30347d920..ab24a994c 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::{info, panic}; 8use defmt::{info, panic};
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/watchdog.rs b/examples/rp/src/bin/watchdog.rs
index b6af518af..b9d4ef22f 100644
--- a/examples/rp/src/bin/watchdog.rs
+++ b/examples/rp/src/bin/watchdog.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use defmt::info; 8use defmt::info;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index ad1fa6462..1bd75607e 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![allow(async_fn_in_trait)] 6#![allow(async_fn_in_trait)]
8 7
9use core::str::from_utf8; 8use core::str::from_utf8;
@@ -19,7 +18,7 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
19use embassy_rp::pio::{InterruptHandler, Pio}; 18use embassy_rp::pio::{InterruptHandler, Pio};
20use embassy_time::Duration; 19use embassy_time::Duration;
21use embedded_io_async::Write; 20use embedded_io_async::Write;
22use static_cell::make_static; 21use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
24 23
25bind_interrupts!(struct Irqs { 24bind_interrupts!(struct Irqs {
@@ -59,7 +58,8 @@ async fn main(spawner: Spawner) {
59 let mut pio = Pio::new(p.PIO0, Irqs); 58 let mut pio = Pio::new(p.PIO0, Irqs);
60 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 59 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
61 60
62 let state = make_static!(cyw43::State::new()); 61 static STATE: StaticCell<cyw43::State> = StaticCell::new();
62 let state = STATE.init(cyw43::State::new());
63 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 63 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
64 unwrap!(spawner.spawn(wifi_task(runner))); 64 unwrap!(spawner.spawn(wifi_task(runner)));
65 65
@@ -79,11 +79,13 @@ async fn main(spawner: Spawner) {
79 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 79 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
80 80
81 // Init network stack 81 // Init network stack
82 let stack = &*make_static!(Stack::new( 82 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
83 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
84 let stack = &*STACK.init(Stack::new(
83 net_device, 85 net_device,
84 config, 86 config,
85 make_static!(StackResources::<2>::new()), 87 RESOURCES.init(StackResources::<2>::new()),
86 seed 88 seed,
87 )); 89 ));
88 90
89 unwrap!(spawner.spawn(net_task(stack))); 91 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
index 14ace74e9..1ed74993c 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -4,7 +4,6 @@
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
7#![feature(type_alias_impl_trait)]
8 7
9use cyw43_pio::PioSpi; 8use cyw43_pio::PioSpi;
10use defmt::*; 9use defmt::*;
@@ -14,7 +13,7 @@ use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 13use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::{InterruptHandler, Pio}; 14use embassy_rp::pio::{InterruptHandler, Pio};
16use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
17use static_cell::make_static; 16use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
20bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
@@ -46,7 +45,8 @@ async fn main(spawner: Spawner) {
46 let mut pio = Pio::new(p.PIO0, Irqs); 45 let mut pio = Pio::new(p.PIO0, Irqs);
47 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 46 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
48 47
49 let state = make_static!(cyw43::State::new()); 48 static STATE: StaticCell<cyw43::State> = StaticCell::new();
49 let state = STATE.init(cyw43::State::new());
50 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 50 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
51 unwrap!(spawner.spawn(wifi_task(runner))); 51 unwrap!(spawner.spawn(wifi_task(runner)));
52 52
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index 7adf52b88..45bb5b76c 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![allow(async_fn_in_trait)] 6#![allow(async_fn_in_trait)]
8 7
9use core::str; 8use core::str;
@@ -16,7 +15,7 @@ use embassy_rp::bind_interrupts;
16use embassy_rp::gpio::{Level, Output}; 15use embassy_rp::gpio::{Level, Output};
17use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 16use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
18use embassy_rp::pio::{InterruptHandler, Pio}; 17use embassy_rp::pio::{InterruptHandler, Pio};
19use static_cell::make_static; 18use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
21 20
22bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
@@ -56,7 +55,8 @@ async fn main(spawner: Spawner) {
56 let mut pio = Pio::new(p.PIO0, Irqs); 55 let mut pio = Pio::new(p.PIO0, Irqs);
57 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 56 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
58 57
59 let state = make_static!(cyw43::State::new()); 58 static STATE: StaticCell<cyw43::State> = StaticCell::new();
59 let state = STATE.init(cyw43::State::new());
60 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 60 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
61 unwrap!(spawner.spawn(wifi_task(runner))); 61 unwrap!(spawner.spawn(wifi_task(runner)));
62 62
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index ec6b4ee74..c346f1ded 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -3,7 +3,6 @@
3 3
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![allow(async_fn_in_trait)] 6#![allow(async_fn_in_trait)]
8 7
9use core::str::from_utf8; 8use core::str::from_utf8;
@@ -19,7 +18,7 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
19use embassy_rp::pio::{InterruptHandler, Pio}; 18use embassy_rp::pio::{InterruptHandler, Pio};
20use embassy_time::{Duration, Timer}; 19use embassy_time::{Duration, Timer};
21use embedded_io_async::Write; 20use embedded_io_async::Write;
22use static_cell::make_static; 21use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
24 23
25bind_interrupts!(struct Irqs { 24bind_interrupts!(struct Irqs {
@@ -62,7 +61,8 @@ async fn main(spawner: Spawner) {
62 let mut pio = Pio::new(p.PIO0, Irqs); 61 let mut pio = Pio::new(p.PIO0, Irqs);
63 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 62 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
64 63
65 let state = make_static!(cyw43::State::new()); 64 static STATE: StaticCell<cyw43::State> = StaticCell::new();
65 let state = STATE.init(cyw43::State::new());
66 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 66 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
67 unwrap!(spawner.spawn(wifi_task(runner))); 67 unwrap!(spawner.spawn(wifi_task(runner)));
68 68
@@ -82,11 +82,13 @@ async fn main(spawner: Spawner) {
82 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 82 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
83 83
84 // Init network stack 84 // Init network stack
85 let stack = &*make_static!(Stack::new( 85 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
86 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
87 let stack = &*STACK.init(Stack::new(
86 net_device, 88 net_device,
87 config, 89 config,
88 make_static!(StackResources::<2>::new()), 90 RESOURCES.init(StackResources::<2>::new()),
89 seed 91 seed,
90 )); 92 ));
91 93
92 unwrap!(spawner.spawn(net_task(stack))); 94 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index ccc0a4afc..a4f306865 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "std", ] } 10embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "std", ] }
11embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } 11embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } 12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
@@ -23,7 +23,7 @@ nix = "0.26.2"
23clap = { version = "3.0.0-beta.5", features = ["derive"] } 23clap = { version = "3.0.0-beta.5", features = ["derive"] }
24rand_core = { version = "0.6.3", features = ["std"] } 24rand_core = { version = "0.6.3", features = ["std"] }
25heapless = { version = "0.8", default-features = false } 25heapless = { version = "0.8", default-features = false }
26static_cell = { version = "2", features = ["nightly"]} 26static_cell = "2"
27 27
28[profile.release] 28[profile.release]
29debug = 2 29debug = 2
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 8d8345057..dad93d0a1 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -1,5 +1,3 @@
1#![feature(type_alias_impl_trait)]
2
3use std::default::Default; 1use std::default::Default;
4 2
5use clap::Parser; 3use clap::Parser;
@@ -12,7 +10,7 @@ use embedded_io_async::Write;
12use heapless::Vec; 10use heapless::Vec;
13use log::*; 11use log::*;
14use rand_core::{OsRng, RngCore}; 12use rand_core::{OsRng, RngCore};
15use static_cell::{make_static, StaticCell}; 13use static_cell::StaticCell;
16 14
17#[derive(Parser)] 15#[derive(Parser)]
18#[clap(version = "1.0")] 16#[clap(version = "1.0")]
@@ -54,11 +52,13 @@ async fn main_task(spawner: Spawner) {
54 let seed = u64::from_le_bytes(seed); 52 let seed = u64::from_le_bytes(seed);
55 53
56 // Init network stack 54 // Init network stack
57 let stack = &*make_static!(Stack::new( 55 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
56 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
57 let stack = &*STACK.init(Stack::new(
58 device, 58 device,
59 config, 59 config,
60 make_static!(StackResources::<3>::new()), 60 RESOURCES.init(StackResources::<3>::new()),
61 seed 61 seed,
62 )); 62 ));
63 63
64 // Launch network task 64 // Launch network task
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index 6c19874d5..fca1e076e 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -1,5 +1,3 @@
1#![feature(type_alias_impl_trait)]
2
3use std::default::Default; 1use std::default::Default;
4 2
5use clap::Parser; 3use clap::Parser;
@@ -10,7 +8,7 @@ use embassy_net_tuntap::TunTapDevice;
10use heapless::Vec; 8use heapless::Vec;
11use log::*; 9use log::*;
12use rand_core::{OsRng, RngCore}; 10use rand_core::{OsRng, RngCore};
13use static_cell::{make_static, StaticCell}; 11use static_cell::StaticCell;
14 12
15#[derive(Parser)] 13#[derive(Parser)]
16#[clap(version = "1.0")] 14#[clap(version = "1.0")]
@@ -53,11 +51,13 @@ async fn main_task(spawner: Spawner) {
53 let seed = u64::from_le_bytes(seed); 51 let seed = u64::from_le_bytes(seed);
54 52
55 // Init network stack 53 // Init network stack
56 let stack: &Stack<_> = &*make_static!(Stack::new( 54 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
55 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
56 let stack: &Stack<_> = &*STACK.init(Stack::new(
57 device, 57 device,
58 config, 58 config,
59 make_static!(StackResources::<3>::new()), 59 RESOURCES.init(StackResources::<3>::new()),
60 seed 60 seed,
61 )); 61 ));
62 62
63 // Launch network task 63 // Launch network task
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs
index cee04e558..9ec0ea91f 100644
--- a/examples/std/src/bin/net_ppp.rs
+++ b/examples/std/src/bin/net_ppp.rs
@@ -7,7 +7,6 @@
7//! ping 192.168.7.10 7//! ping 192.168.7.10
8//! nc 192.168.7.10 1234 8//! nc 192.168.7.10 1234
9 9
10#![feature(type_alias_impl_trait)]
11#![allow(async_fn_in_trait)] 10#![allow(async_fn_in_trait)]
12 11
13#[path = "../serial_port.rs"] 12#[path = "../serial_port.rs"]
@@ -25,7 +24,7 @@ use heapless::Vec;
25use log::*; 24use log::*;
26use nix::sys::termios; 25use nix::sys::termios;
27use rand_core::{OsRng, RngCore}; 26use rand_core::{OsRng, RngCore};
28use static_cell::{make_static, StaticCell}; 27use static_cell::StaticCell;
29 28
30use crate::serial_port::SerialPort; 29use crate::serial_port::SerialPort;
31 30
@@ -88,7 +87,8 @@ async fn main_task(spawner: Spawner) {
88 let port = SerialPort::new(opts.device.as_str(), baudrate).unwrap(); 87 let port = SerialPort::new(opts.device.as_str(), baudrate).unwrap();
89 88
90 // Init network device 89 // Init network device
91 let state = make_static!(embassy_net_ppp::State::<4, 4>::new()); 90 static STATE: StaticCell<embassy_net_ppp::State<4, 4>> = StaticCell::new();
91 let state = STATE.init(embassy_net_ppp::State::<4, 4>::new());
92 let (device, runner) = embassy_net_ppp::new(state); 92 let (device, runner) = embassy_net_ppp::new(state);
93 93
94 // Generate random seed 94 // Generate random seed
@@ -97,11 +97,13 @@ async fn main_task(spawner: Spawner) {
97 let seed = u64::from_le_bytes(seed); 97 let seed = u64::from_le_bytes(seed);
98 98
99 // Init network stack 99 // Init network stack
100 let stack = &*make_static!(Stack::new( 100 static STACK: StaticCell<Stack<embassy_net_ppp::Device<'static>>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new(
101 device, 103 device,
102 Config::default(), // don't configure IP yet 104 Config::default(), // don't configure IP yet
103 make_static!(StackResources::<3>::new()), 105 RESOURCES.init(StackResources::<3>::new()),
104 seed 106 seed,
105 )); 107 ));
106 108
107 // Launch network task 109 // Launch network task
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index 98dcc9925..bee91990d 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -1,5 +1,3 @@
1#![feature(type_alias_impl_trait)]
2
3use clap::Parser; 1use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 2use embassy_executor::{Executor, Spawner};
5use embassy_net::udp::{PacketMetadata, UdpSocket}; 3use embassy_net::udp::{PacketMetadata, UdpSocket};
@@ -8,7 +6,7 @@ use embassy_net_tuntap::TunTapDevice;
8use heapless::Vec; 6use heapless::Vec;
9use log::*; 7use log::*;
10use rand_core::{OsRng, RngCore}; 8use rand_core::{OsRng, RngCore};
11use static_cell::{make_static, StaticCell}; 9use static_cell::StaticCell;
12 10
13#[derive(Parser)] 11#[derive(Parser)]
14#[clap(version = "1.0")] 12#[clap(version = "1.0")]
@@ -50,11 +48,13 @@ async fn main_task(spawner: Spawner) {
50 let seed = u64::from_le_bytes(seed); 48 let seed = u64::from_le_bytes(seed);
51 49
52 // Init network stack 50 // Init network stack
53 let stack = &*make_static!(Stack::new( 51 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
53 let stack = &*STACK.init(Stack::new(
54 device, 54 device,
55 config, 55 config,
56 make_static!(StackResources::<3>::new()), 56 RESOURCES.init(StackResources::<3>::new()),
57 seed 57 seed,
58 )); 58 ));
59 59
60 // Launch network task 60 // Launch network task
diff --git a/examples/std/src/bin/serial.rs b/examples/std/src/bin/serial.rs
index 0b289c74d..435089aad 100644
--- a/examples/std/src/bin/serial.rs
+++ b/examples/std/src/bin/serial.rs
@@ -1,5 +1,3 @@
1#![feature(type_alias_impl_trait)]
2
3#[path = "../serial_port.rs"] 1#[path = "../serial_port.rs"]
4mod serial_port; 2mod serial_port;
5 3
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs
index 79fa375cd..00ccd83a7 100644
--- a/examples/std/src/bin/tcp_accept.rs
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -1,5 +1,3 @@
1#![feature(type_alias_impl_trait)]
2
3use core::fmt::Write as _; 1use core::fmt::Write as _;
4use std::default::Default; 2use std::default::Default;
5 3
@@ -13,7 +11,7 @@ use embedded_io_async::Write as _;
13use heapless::Vec; 11use heapless::Vec;
14use log::*; 12use log::*;
15use rand_core::{OsRng, RngCore}; 13use rand_core::{OsRng, RngCore};
16use static_cell::{make_static, StaticCell}; 14use static_cell::StaticCell;
17 15
18#[derive(Parser)] 16#[derive(Parser)]
19#[clap(version = "1.0")] 17#[clap(version = "1.0")]
@@ -65,11 +63,13 @@ async fn main_task(spawner: Spawner) {
65 let seed = u64::from_le_bytes(seed); 63 let seed = u64::from_le_bytes(seed);
66 64
67 // Init network stack 65 // Init network stack
68 let stack = &*make_static!(Stack::new( 66 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
67 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
68 let stack = &*STACK.init(Stack::new(
69 device, 69 device,
70 config, 70 config,
71 make_static!(StackResources::<3>::new()), 71 RESOURCES.init(StackResources::<3>::new()),
72 seed 72 seed,
73 )); 73 ));
74 74
75 // Launch network task 75 // Launch network task
diff --git a/examples/std/src/bin/tick.rs b/examples/std/src/bin/tick.rs
index a3f99067e..f23cf3549 100644
--- a/examples/std/src/bin/tick.rs
+++ b/examples/std/src/bin/tick.rs
@@ -1,5 +1,3 @@
1#![feature(type_alias_impl_trait)]
2
3use embassy_executor::Spawner; 1use embassy_executor::Spawner;
4use embassy_time::Timer; 2use embassy_time::Timer;
5use log::*; 3use log::*;
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index 2d831ba5d..0fd3939c6 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32c031c6 to your chip name, if necessary. 8# Change stm32c031c6 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32c0/src/bin/blinky.rs b/examples/stm32c0/src/bin/blinky.rs
index cbeb0dee1..90e479aae 100644
--- a/examples/stm32c0/src/bin/blinky.rs
+++ b/examples/stm32c0/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32c0/src/bin/button.rs b/examples/stm32c0/src/bin/button.rs
index 72a3f5cbf..265200132 100644
--- a/examples/stm32c0/src/bin/button.rs
+++ b/examples/stm32c0/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
@@ -13,7 +12,7 @@ fn main() -> ! {
13 12
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 14
16 let button = Input::new(p.PC13, Pull::Up); 15 let mut button = Input::new(p.PC13, Pull::Up);
17 16
18 loop { 17 loop {
19 if button.is_high() { 18 if button.is_high() {
diff --git a/examples/stm32c0/src/bin/button_exti.rs b/examples/stm32c0/src/bin/button_exti.rs
index ef32d4c4a..1e970fdd6 100644
--- a/examples/stm32c0/src/bin/button_exti.rs
+++ b/examples/stm32c0/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 2b066d731..9fdc4798a 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -15,9 +15,9 @@ defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
16panic-probe = "0.3" 16panic-probe = "0.3"
17embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 17embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
18embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 18embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
19embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 19embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
20static_cell = { version = "2", features = ["nightly"]} 20static_cell = "2"
21portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 21portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
22 22
23[profile.release] 23[profile.release]
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
index 96f234402..8fef062b3 100644
--- a/examples/stm32f0/src/bin/adc.rs
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f0/src/bin/blinky.rs b/examples/stm32f0/src/bin/blinky.rs
index 899394546..2572be1bc 100644
--- a/examples/stm32f0/src/bin/blinky.rs
+++ b/examples/stm32f0/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs
index 306df1752..360d153c3 100644
--- a/examples/stm32f0/src/bin/button_controlled_blink.rs
+++ b/examples/stm32f0/src/bin/button_controlled_blink.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6 5
7use core::sync::atomic::{AtomicU32, Ordering}; 6use core::sync::atomic::{AtomicU32, Ordering};
8 7
diff --git a/examples/stm32f0/src/bin/button_exti.rs b/examples/stm32f0/src/bin/button_exti.rs
index 40c0d5848..ce17c1a48 100644
--- a/examples/stm32f0/src/bin/button_exti.rs
+++ b/examples/stm32f0/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f0/src/bin/hello.rs b/examples/stm32f0/src/bin/hello.rs
index 0f98d9865..ccd6a0a39 100644
--- a/examples/stm32f0/src/bin/hello.rs
+++ b/examples/stm32f0/src/bin/hello.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs
index 870c7c45b..e49951726 100644
--- a/examples/stm32f0/src/bin/multiprio.rs
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -55,7 +55,6 @@
55 55
56#![no_std] 56#![no_std]
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)]
59 58
60use cortex_m_rt::entry; 59use cortex_m_rt::entry;
61use defmt::*; 60use defmt::*;
diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs
index b51dee8ee..b974bff91 100644
--- a/examples/stm32f0/src/bin/wdg.rs
+++ b/examples/stm32f0/src/bin/wdg.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index f04d41317..c933a4368 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f103c8 to your chip name, if necessary. 8# Change stm32f103c8 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index 1edac3d83..1440460a9 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f1/src/bin/blinky.rs b/examples/stm32f1/src/bin/blinky.rs
index 3425b0536..cc43f85f4 100644
--- a/examples/stm32f1/src/bin/blinky.rs
+++ b/examples/stm32f1/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs
new file mode 100644
index 000000000..c1c4f8359
--- /dev/null
+++ b/examples/stm32f1/src/bin/can.rs
@@ -0,0 +1,66 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::can::bxcan::filter::Mask32;
7use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId};
8use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
9use embassy_stm32::peripherals::CAN;
10use embassy_stm32::{bind_interrupts, Config};
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 USB_LP_CAN1_RX0 => Rx0InterruptHandler<CAN>;
15 CAN1_RX1 => Rx1InterruptHandler<CAN>;
16 CAN1_SCE => SceInterruptHandler<CAN>;
17 USB_HP_CAN1_TX => TxInterruptHandler<CAN>;
18});
19
20// This example is configured to work with real CAN transceivers on B8/B9.
21// See other examples for loopback.
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 let p = embassy_stm32::init(Config::default());
26
27 // Set alternate pin mapping to B8/B9
28 embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2));
29
30 let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs);
31
32 can.as_mut()
33 .modify_filters()
34 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
35
36 can.as_mut()
37 .modify_config()
38 .set_loopback(false)
39 .set_silent(false)
40 .leave_disabled();
41
42 can.set_bitrate(250_000);
43
44 can.enable().await;
45
46 let mut i: u8 = 0;
47 loop {
48 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
49 can.write(&tx_frame).await;
50
51 match can.read().await {
52 Ok(env) => match env.frame.id() {
53 Id::Extended(id) => {
54 defmt::println!("Extended Frame id={:x}", id.as_raw());
55 }
56 Id::Standard(id) => {
57 defmt::println!("Standard Frame id={:x}", id.as_raw());
58 }
59 },
60 Err(err) => {
61 defmt::println!("Error {}", err);
62 }
63 }
64 i += 1;
65 }
66}
diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs
index e63bcaae0..7b761ecc1 100644
--- a/examples/stm32f1/src/bin/hello.rs
+++ b/examples/stm32f1/src/bin/hello.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index 31519555f..e28381893 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index 66cc1e15b..eaaadeec5 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f207zg to your chip name, if necessary. 8# Change stm32f207zg to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32f2/src/bin/blinky.rs b/examples/stm32f2/src/bin/blinky.rs
index f6d7a0005..d9833ba8b 100644
--- a/examples/stm32f2/src/bin/blinky.rs
+++ b/examples/stm32f2/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs
index aae7637dc..e32f283d1 100644
--- a/examples/stm32f2/src/bin/pll.rs
+++ b/examples/stm32f2/src/bin/pll.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::convert::TryFrom; 4use core::convert::TryFrom;
6 5
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index ed1367858..d5ab0b25a 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f303ze to your chip name, if necessary. 8# Change stm32f303ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -24,7 +24,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
24heapless = { version = "0.8", default-features = false } 24heapless = { version = "0.8", default-features = false }
25nb = "1.0.0" 25nb = "1.0.0"
26embedded-storage = "0.3.1" 26embedded-storage = "0.3.1"
27static_cell = { version = "2", features = ["nightly"]} 27static_cell = "2"
28 28
29[profile.release] 29[profile.release]
30debug = 2 30debug = 2
diff --git a/examples/stm32f3/src/bin/blinky.rs b/examples/stm32f3/src/bin/blinky.rs
index e71031b30..0ea10522d 100644
--- a/examples/stm32f3/src/bin/blinky.rs
+++ b/examples/stm32f3/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f3/src/bin/button.rs b/examples/stm32f3/src/bin/button.rs
index b55bf3901..2cd356787 100644
--- a/examples/stm32f3/src/bin/button.rs
+++ b/examples/stm32f3/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
@@ -13,7 +12,7 @@ fn main() -> ! {
13 12
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 14
16 let button = Input::new(p.PA0, Pull::Down); 15 let mut button = Input::new(p.PA0, Pull::Down);
17 let mut led1 = Output::new(p.PE9, Level::High, Speed::Low); 16 let mut led1 = Output::new(p.PE9, Level::High, Speed::Low);
18 let mut led2 = Output::new(p.PE15, Level::High, Speed::Low); 17 let mut led2 = Output::new(p.PE15, Level::High, Speed::Low);
19 18
diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs
index 9df6d680d..2f7da4ef5 100644
--- a/examples/stm32f3/src/bin/button_events.rs
+++ b/examples/stm32f3/src/bin/button_events.rs
@@ -8,7 +8,6 @@
8 8
9#![no_std] 9#![no_std]
10#![no_main] 10#![no_main]
11#![feature(type_alias_impl_trait)]
12 11
13use defmt::*; 12use defmt::*;
14use embassy_executor::Spawner; 13use embassy_executor::Spawner;
diff --git a/examples/stm32f3/src/bin/button_exti.rs b/examples/stm32f3/src/bin/button_exti.rs
index 1266778c1..86ff68492 100644
--- a/examples/stm32f3/src/bin/button_exti.rs
+++ b/examples/stm32f3/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs
index 236fb36c1..28125697d 100644
--- a/examples/stm32f3/src/bin/flash.rs
+++ b/examples/stm32f3/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f3/src/bin/hello.rs b/examples/stm32f3/src/bin/hello.rs
index b3285f3c1..fd54da53d 100644
--- a/examples/stm32f3/src/bin/hello.rs
+++ b/examples/stm32f3/src/bin/hello.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 74f3bb1c5..328447210 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -55,7 +55,6 @@
55 55
56#![no_std] 56#![no_std]
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)]
59 58
60use cortex_m_rt::entry; 59use cortex_m_rt::entry;
61use defmt::*; 60use defmt::*;
diff --git a/examples/stm32f3/src/bin/spi_dma.rs b/examples/stm32f3/src/bin/spi_dma.rs
index a27c1d547..54498d53d 100644
--- a/examples/stm32f3/src/bin/spi_dma.rs
+++ b/examples/stm32f3/src/bin/spi_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6use core::str::from_utf8; 5use core::str::from_utf8;
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs
index ce8c212ae..5234e53b9 100644
--- a/examples/stm32f3/src/bin/usart_dma.rs
+++ b/examples/stm32f3/src/bin/usart_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6 5
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index d5d068d62..cf9ecedfa 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml
index 320cf7d7b..b29a08e7c 100644
--- a/examples/stm32f334/Cargo.toml
+++ b/examples/stm32f334/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.2.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.2.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -23,4 +23,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24nb = "1.0.0" 24nb = "1.0.0"
25embedded-storage = "0.3.1" 25embedded-storage = "0.3.1"
26static_cell = { version = "2", features = ["nightly"]} 26static_cell = "2"
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs
index f259135d2..063ee9dac 100644
--- a/examples/stm32f334/src/bin/adc.rs
+++ b/examples/stm32f334/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f334/src/bin/button.rs b/examples/stm32f334/src/bin/button.rs
index 501fb080c..256f9a44a 100644
--- a/examples/stm32f334/src/bin/button.rs
+++ b/examples/stm32f334/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f334/src/bin/hello.rs b/examples/stm32f334/src/bin/hello.rs
index b3285f3c1..fd54da53d 100644
--- a/examples/stm32f334/src/bin/hello.rs
+++ b/examples/stm32f334/src/bin/hello.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs
index 10e7b3543..850a0e335 100644
--- a/examples/stm32f334/src/bin/opamp.rs
+++ b/examples/stm32f334/src/bin/opamp.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index 8040c3f18..c149cad92 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 6ea0018cd..a74e0f674 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32f429zi to your chip name, if necessary. 8# Change stm32f429zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] }
14embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 14embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
@@ -27,7 +27,7 @@ heapless = { version = "0.8", default-features = false }
27nb = "1.0.0" 27nb = "1.0.0"
28embedded-storage = "0.3.1" 28embedded-storage = "0.3.1"
29micromath = "2.0.0" 29micromath = "2.0.0"
30static_cell = { version = "2", features = ["nightly"]} 30static_cell = "2"
31chrono = { version = "^0.4", default-features = false} 31chrono = { version = "^0.4", default-features = false}
32 32
33[profile.release] 33[profile.release]
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index f19328727..699c29c05 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs; 4use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs;
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32f4/src/bin/blinky.rs b/examples/stm32f4/src/bin/blinky.rs
index 4bfc5a50d..31cce8225 100644
--- a/examples/stm32f4/src/bin/blinky.rs
+++ b/examples/stm32f4/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/button.rs b/examples/stm32f4/src/bin/button.rs
index b13e64531..ad30a56a2 100644
--- a/examples/stm32f4/src/bin/button.rs
+++ b/examples/stm32f4/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
@@ -13,7 +12,7 @@ fn main() -> ! {
13 12
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 14
16 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = Input::new(p.PC13, Pull::Down);
17 let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); 16 let mut led1 = Output::new(p.PB0, Level::High, Speed::Low);
18 let _led2 = Output::new(p.PB7, Level::High, Speed::Low); 17 let _led2 = Output::new(p.PB7, Level::High, Speed::Low);
19 let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); 18 let mut led3 = Output::new(p.PB14, Level::High, Speed::Low);
diff --git a/examples/stm32f4/src/bin/button_exti.rs b/examples/stm32f4/src/bin/button_exti.rs
index dfe587d41..67751187d 100644
--- a/examples/stm32f4/src/bin/button_exti.rs
+++ b/examples/stm32f4/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index 20ce4edce..d074b4265 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index 8f14d6078..9c7754c4f 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 088d83c06..7f5c8fdb1 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -14,7 +13,7 @@ use embassy_stm32::time::Hertz;
14use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; 13use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::Timer; 14use embassy_time::Timer;
16use embedded_io_async::Write; 15use embedded_io_async::Write;
17use static_cell::make_static; 16use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
20bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
@@ -63,8 +62,9 @@ async fn main(spawner: Spawner) -> ! {
63 62
64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 63 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
65 64
65 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
66 let device = Ethernet::new( 66 let device = Ethernet::new(
67 make_static!(PacketQueue::<16, 16>::new()), 67 PACKETS.init(PacketQueue::<16, 16>::new()),
68 p.ETH, 68 p.ETH,
69 Irqs, 69 Irqs,
70 p.PA1, 70 p.PA1,
@@ -88,11 +88,13 @@ async fn main(spawner: Spawner) -> ! {
88 //}); 88 //});
89 89
90 // Init network stack 90 // Init network stack
91 let stack = &*make_static!(Stack::new( 91 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
92 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
93 let stack = &*STACK.init(Stack::new(
92 device, 94 device,
93 config, 95 config,
94 make_static!(StackResources::<2>::new()), 96 RESOURCES.init(StackResources::<2>::new()),
95 seed 97 seed,
96 )); 98 ));
97 99
98 // Launch network task 100 // Launch network task
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
index 93c54e943..1e8cabab4 100644
--- a/examples/stm32f4/src/bin/flash.rs
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -31,7 +30,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
31 30
32 info!("Reading..."); 31 info!("Reading...");
33 let mut buf = [0u8; 32]; 32 let mut buf = [0u8; 32];
34 unwrap!(f.read(offset, &mut buf)); 33 unwrap!(f.blocking_read(offset, &mut buf));
35 info!("Read: {=[u8]:x}", buf); 34 info!("Read: {=[u8]:x}", buf);
36 35
37 info!("Erasing..."); 36 info!("Erasing...");
@@ -39,7 +38,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
39 38
40 info!("Reading..."); 39 info!("Reading...");
41 let mut buf = [0u8; 32]; 40 let mut buf = [0u8; 32];
42 unwrap!(f.read(offset, &mut buf)); 41 unwrap!(f.blocking_read(offset, &mut buf));
43 info!("Read after erase: {=[u8]:x}", buf); 42 info!("Read after erase: {=[u8]:x}", buf);
44 43
45 info!("Writing..."); 44 info!("Writing...");
@@ -53,7 +52,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
53 52
54 info!("Reading..."); 53 info!("Reading...");
55 let mut buf = [0u8; 32]; 54 let mut buf = [0u8; 32];
56 unwrap!(f.read(offset, &mut buf)); 55 unwrap!(f.blocking_read(offset, &mut buf));
57 info!("Read: {=[u8]:x}", buf); 56 info!("Read: {=[u8]:x}", buf);
58 assert_eq!( 57 assert_eq!(
59 &buf[..], 58 &buf[..],
diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs
index f0a65a725..493a536f3 100644
--- a/examples/stm32f4/src/bin/flash_async.rs
+++ b/examples/stm32f4/src/bin/flash_async.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -48,7 +47,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
48 47
49 info!("Reading..."); 48 info!("Reading...");
50 let mut buf = [0u8; 32]; 49 let mut buf = [0u8; 32];
51 unwrap!(f.read(offset, &mut buf)); 50 unwrap!(f.blocking_read(offset, &mut buf));
52 info!("Read: {=[u8]:x}", buf); 51 info!("Read: {=[u8]:x}", buf);
53 52
54 info!("Erasing..."); 53 info!("Erasing...");
@@ -56,7 +55,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
56 55
57 info!("Reading..."); 56 info!("Reading...");
58 let mut buf = [0u8; 32]; 57 let mut buf = [0u8; 32];
59 unwrap!(f.read(offset, &mut buf)); 58 unwrap!(f.blocking_read(offset, &mut buf));
60 info!("Read after erase: {=[u8]:x}", buf); 59 info!("Read after erase: {=[u8]:x}", buf);
61 60
62 info!("Writing..."); 61 info!("Writing...");
@@ -73,7 +72,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
73 72
74 info!("Reading..."); 73 info!("Reading...");
75 let mut buf = [0u8; 32]; 74 let mut buf = [0u8; 32];
76 unwrap!(f.read(offset, &mut buf)); 75 unwrap!(f.blocking_read(offset, &mut buf));
77 info!("Read: {=[u8]:x}", buf); 76 info!("Read: {=[u8]:x}", buf);
78 assert_eq!( 77 assert_eq!(
79 &buf[..], 78 &buf[..],
diff --git a/examples/stm32f4/src/bin/hello.rs b/examples/stm32f4/src/bin/hello.rs
index a2a287110..3c295612c 100644
--- a/examples/stm32f4/src/bin/hello.rs
+++ b/examples/stm32f4/src/bin/hello.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
index 4f4adde28..4b5da774d 100644
--- a/examples/stm32f4/src/bin/i2c.rs
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/i2c_async.rs b/examples/stm32f4/src/bin/i2c_async.rs
index 9f59e4d41..90d11d4b4 100644
--- a/examples/stm32f4/src/bin/i2c_async.rs
+++ b/examples/stm32f4/src/bin/i2c_async.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5// Example originally designed for stm32f411ceu6 reading an A1454 hall effect sensor on I2C1 4// Example originally designed for stm32f411ceu6 reading an A1454 hall effect sensor on I2C1
6// DMA peripherals changed to compile for stm32f429zi, for the CI. 5// DMA peripherals changed to compile for stm32f429zi, for the CI.
diff --git a/examples/stm32f4/src/bin/i2c_comparison.rs b/examples/stm32f4/src/bin/i2c_comparison.rs
index 6d23c0ed8..30cfbdf57 100644
--- a/examples/stm32f4/src/bin/i2c_comparison.rs
+++ b/examples/stm32f4/src/bin/i2c_comparison.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5// Example originally designed for stm32f411ceu6 with three A1454 hall effect sensors, connected to I2C1, 2 and 3 4// Example originally designed for stm32f411ceu6 with three A1454 hall effect sensors, connected to I2C1, 2 and 3
6// on the pins referenced in the peripheral definitions. 5// on the pins referenced in the peripheral definitions.
diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs
index e8d7b5f77..97a04b2aa 100644
--- a/examples/stm32f4/src/bin/i2s_dma.rs
+++ b/examples/stm32f4/src/bin/i2s_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6 5
diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs
index 3315e7652..eb7bb6261 100644
--- a/examples/stm32f4/src/bin/mco.rs
+++ b/examples/stm32f4/src/bin/mco.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 74f3bb1c5..328447210 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -55,7 +55,6 @@
55 55
56#![no_std] 56#![no_std]
57#![no_main] 57#![no_main]
58#![feature(type_alias_impl_trait)]
59 58
60use cortex_m_rt::entry; 59use cortex_m_rt::entry;
61use defmt::*; 60use defmt::*;
diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs
index 8e41d0e78..8844a9f0e 100644
--- a/examples/stm32f4/src/bin/pwm.rs
+++ b/examples/stm32f4/src/bin/pwm.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs
index d925f26d9..161f43c48 100644
--- a/examples/stm32f4/src/bin/pwm_complementary.rs
+++ b/examples/stm32f4/src/bin/pwm_complementary.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs
index 44b4303c0..abab07b6b 100644
--- a/examples/stm32f4/src/bin/rtc.rs
+++ b/examples/stm32f4/src/bin/rtc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use chrono::{NaiveDate, NaiveDateTime}; 4use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index 91747b2d5..66e4e527c 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs
index 0919e9874..dc9141c62 100644
--- a/examples/stm32f4/src/bin/spi.rs
+++ b/examples/stm32f4/src/bin/spi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32f4/src/bin/spi_dma.rs b/examples/stm32f4/src/bin/spi_dma.rs
index f291f7dba..7249c831a 100644
--- a/examples/stm32f4/src/bin/spi_dma.rs
+++ b/examples/stm32f4/src/bin/spi_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6use core::str::from_utf8; 5use core::str::from_utf8;
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 45e94715f..40d9d70f1 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs
index 71abc2893..c99807f11 100644
--- a/examples/stm32f4/src/bin/usart_buffered.rs
+++ b/examples/stm32f4/src/bin/usart_buffered.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index dca25a78c..dd6de599c 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6 5
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 6bf5b1cba..a196259a8 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -14,7 +13,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState
14use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
15use embassy_usb::{Builder, UsbDevice}; 14use embassy_usb::{Builder, UsbDevice};
16use embedded_io_async::Write; 15use embedded_io_async::Write;
17use static_cell::make_static; 16use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
20type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>; 19type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>;
@@ -68,7 +67,8 @@ async fn main(spawner: Spawner) {
68 let p = embassy_stm32::init(config); 67 let p = embassy_stm32::init(config);
69 68
70 // Create the driver, from the HAL. 69 // Create the driver, from the HAL.
71 let ep_out_buffer = &mut make_static!([0; 256])[..]; 70 static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new();
71 let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..];
72 let mut config = embassy_stm32::usb_otg::Config::default(); 72 let mut config = embassy_stm32::usb_otg::Config::default();
73 config.vbus_detection = true; 73 config.vbus_detection = true;
74 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); 74 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
@@ -88,14 +88,18 @@ async fn main(spawner: Spawner) {
88 config.device_protocol = 0x01; 88 config.device_protocol = 0x01;
89 89
90 // Create embassy-usb DeviceBuilder using the driver and config. 90 // Create embassy-usb DeviceBuilder using the driver and config.
91 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
92 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
93 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
94 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
91 let mut builder = Builder::new( 95 let mut builder = Builder::new(
92 driver, 96 driver,
93 config, 97 config,
94 &mut make_static!([0; 256])[..], 98 &mut DEVICE_DESC.init([0; 256])[..],
95 &mut make_static!([0; 256])[..], 99 &mut CONFIG_DESC.init([0; 256])[..],
96 &mut make_static!([0; 256])[..], 100 &mut BOS_DESC.init([0; 256])[..],
97 &mut [], // no msos descriptors 101 &mut [], // no msos descriptors
98 &mut make_static!([0; 128])[..], 102 &mut CONTROL_BUF.init([0; 128])[..],
99 ); 103 );
100 104
101 // Our MAC addr. 105 // Our MAC addr.
@@ -104,14 +108,16 @@ async fn main(spawner: Spawner) {
104 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 108 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
105 109
106 // Create classes on the builder. 110 // Create classes on the builder.
107 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); 111 static STATE: StaticCell<State> = StaticCell::new();
112 let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64);
108 113
109 // Build the builder. 114 // Build the builder.
110 let usb = builder.build(); 115 let usb = builder.build();
111 116
112 unwrap!(spawner.spawn(usb_task(usb))); 117 unwrap!(spawner.spawn(usb_task(usb)));
113 118
114 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 119 static NET_STATE: StaticCell<NetState<MTU, 4, 4>> = StaticCell::new();
120 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(NET_STATE.init(NetState::new()), our_mac_addr);
115 unwrap!(spawner.spawn(usb_ncm_task(runner))); 121 unwrap!(spawner.spawn(usb_ncm_task(runner)));
116 122
117 let config = embassy_net::Config::dhcpv4(Default::default()); 123 let config = embassy_net::Config::dhcpv4(Default::default());
@@ -128,11 +134,13 @@ async fn main(spawner: Spawner) {
128 let seed = u64::from_le_bytes(seed); 134 let seed = u64::from_le_bytes(seed);
129 135
130 // Init network stack 136 // Init network stack
131 let stack = &*make_static!(Stack::new( 137 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
138 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
139 let stack = &*STACK.init(Stack::new(
132 device, 140 device,
133 config, 141 config,
134 make_static!(StackResources::<2>::new()), 142 RESOURCES.init(StackResources::<2>::new()),
135 seed 143 seed,
136 )); 144 ));
137 145
138 unwrap!(spawner.spawn(net_task(stack))); 146 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs
index 719b22bb9..afff55187 100644
--- a/examples/stm32f4/src/bin/usb_raw.rs
+++ b/examples/stm32f4/src/bin/usb_raw.rs
@@ -48,7 +48,6 @@
48 48
49#![no_std] 49#![no_std]
50#![no_main] 50#![no_main]
51#![feature(type_alias_impl_trait)]
52 51
53use defmt::*; 52use defmt::*;
54use embassy_executor::Spawner; 53use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index e2ccc9142..58d994a61 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs
index 0443b61c5..ea27ebce0 100644
--- a/examples/stm32f4/src/bin/wdt.rs
+++ b/examples/stm32f4/src/bin/wdt.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
new file mode 100644
index 000000000..4458b643f
--- /dev/null
+++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
@@ -0,0 +1,150 @@
1// Configure TIM3 in PWM mode, and start DMA Transfer(s) to send color data into ws2812.
2// We assume the DIN pin of ws2812 connect to GPIO PB4, and ws2812 is properly powered.
3//
4// The idea is that the data rate of ws2812 is 800 kHz, and it use different duty ratio to represent bit 0 and bit 1.
5// Thus we can set TIM overflow at 800 kHz, and let TIM Update Event trigger a DMA transfer, then let DMA change CCR value,
6// such that pwm duty ratio meet the bit representation of ws2812.
7//
8// You may want to modify TIM CCR with Cortex core directly,
9// but according to my test, Cortex core will need to run far more than 100 MHz to catch up with TIM.
10// Thus we need to use a DMA.
11//
12// This demo is a combination of HAL, PAC, and manually invoke `dma::Transfer`.
13// If you need a simpler way to control ws2812, you may want to take a look at `ws2812_spi.rs` file, which make use of SPI.
14//
15// Warning:
16// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
17
18#![no_std]
19#![no_main]
20
21use embassy_executor::Spawner;
22use embassy_stm32::gpio::OutputType;
23use embassy_stm32::pac;
24use embassy_stm32::time::khz;
25use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
26use embassy_stm32::timer::{Channel, CountingMode};
27use embassy_time::{Duration, Ticker, Timer};
28use {defmt_rtt as _, panic_probe as _};
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let mut device_config = embassy_stm32::Config::default();
33
34 // set SYSCLK/HCLK/PCLK2 to 20 MHz, thus each tick is 0.05 us,
35 // and ws2812 timings are integer multiples of 0.05 us
36 {
37 use embassy_stm32::rcc::*;
38 use embassy_stm32::time::*;
39 device_config.enable_debug_during_sleep = true;
40 device_config.rcc.hse = Some(Hse {
41 freq: mhz(12),
42 mode: HseMode::Oscillator,
43 });
44 device_config.rcc.pll_src = PllSource::HSE;
45 device_config.rcc.pll = Some(Pll {
46 prediv: PllPreDiv::DIV6,
47 mul: PllMul::MUL80,
48 divp: Some(PllPDiv::DIV8),
49 divq: None,
50 divr: None,
51 });
52 device_config.rcc.sys = Sysclk::PLL1_P;
53 }
54
55 let mut dp = embassy_stm32::init(device_config);
56
57 let mut ws2812_pwm = SimplePwm::new(
58 dp.TIM3,
59 Some(PwmPin::new_ch1(dp.PB4, OutputType::PushPull)),
60 None,
61 None,
62 None,
63 khz(800), // data rate of ws2812
64 CountingMode::EdgeAlignedUp,
65 );
66
67 // construct ws2812 non-return-to-zero (NRZ) code bit by bit
68 // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low
69
70 let max_duty = ws2812_pwm.get_max_duty();
71 let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing
72 let n1 = 2 * n0; // ws2812 Bit 1 high level timing
73
74 let turn_off = [
75 n0, n0, n0, n0, n0, n0, n0, n0, // Green
76 n0, n0, n0, n0, n0, n0, n0, n0, // Red
77 n0, n0, n0, n0, n0, n0, n0, n0, // Blue
78 0, // keep PWM output low after a transfer
79 ];
80
81 let dim_white = [
82 n0, n0, n0, n0, n0, n0, n1, n0, // Green
83 n0, n0, n0, n0, n0, n0, n1, n0, // Red
84 n0, n0, n0, n0, n0, n0, n1, n0, // Blue
85 0, // keep PWM output low after a transfer
86 ];
87
88 let color_list = &[&turn_off, &dim_white];
89
90 let pwm_channel = Channel::Ch1;
91
92 // PAC level hacking, enable output compare preload
93 // keep output waveform integrity
94 pac::TIM3
95 .ccmr_output(pwm_channel.index())
96 .modify(|v| v.set_ocpe(0, true));
97
98 // make sure PWM output keep low on first start
99 ws2812_pwm.set_duty(pwm_channel, 0);
100
101 {
102 use embassy_stm32::dma::{Burst, FifoThreshold, Transfer, TransferOptions};
103
104 // configure FIFO and MBURST of DMA, to minimize DMA occupation on AHB/APB
105 let mut dma_transfer_option = TransferOptions::default();
106 dma_transfer_option.fifo_threshold = Some(FifoThreshold::Full);
107 dma_transfer_option.mburst = Burst::Incr8;
108
109 // flip color at 2 Hz
110 let mut ticker = Ticker::every(Duration::from_millis(500));
111
112 loop {
113 for &color in color_list {
114 // start PWM output
115 ws2812_pwm.enable(pwm_channel);
116
117 // PAC level hacking, enable timer-update-event trigger DMA
118 pac::TIM3.dier().modify(|v| v.set_ude(true));
119
120 unsafe {
121 Transfer::new_write(
122 // with &mut, we can easily reuse same DMA channel multiple times
123 &mut dp.DMA1_CH2,
124 5,
125 color,
126 pac::TIM3.ccr(pwm_channel.index()).as_ptr() as *mut _,
127 dma_transfer_option,
128 )
129 .await;
130
131 // Turn off timer-update-event trigger DMA as soon as possible.
132 // Then clean the FIFO Error Flag if set.
133 pac::TIM3.dier().modify(|v| v.set_ude(false));
134 if pac::DMA1.isr(0).read().feif(2) {
135 pac::DMA1.ifcr(0).write(|v| v.set_feif(2, true));
136 }
137
138 // ws2812 need at least 50 us low level input to confirm the input data and change it's state
139 Timer::after_micros(50).await;
140 }
141
142 // stop PWM output for saving some energy
143 ws2812_pwm.disable(pwm_channel);
144
145 // wait until ticker tick
146 ticker.next().await;
147 }
148 }
149 }
150}
diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs
new file mode 100644
index 000000000..a280a3b77
--- /dev/null
+++ b/examples/stm32f4/src/bin/ws2812_spi.rs
@@ -0,0 +1,95 @@
1// Mimic PWM with SPI, to control ws2812
2// We assume the DIN pin of ws2812 connect to GPIO PB5, and ws2812 is properly powered.
3//
4// The idea is that the data rate of ws2812 is 800 kHz, and it use different duty ratio to represent bit 0 and bit 1.
5// Thus we can adjust SPI to send each *round* of data at 800 kHz, and in each *round*, we can adjust each *bit* to mimic 2 different PWM waveform.
6// such that the output waveform meet the bit representation of ws2812.
7//
8// If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA.
9//
10// Warning:
11// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
12
13#![no_std]
14#![no_main]
15
16use embassy_stm32::time::khz;
17use embassy_stm32::{dma, spi};
18use embassy_time::{Duration, Ticker, Timer};
19use {defmt_rtt as _, panic_probe as _};
20
21// we use 16 bit data frame format of SPI, to let timing as accurate as possible.
22// thanks to loose tolerance of ws2812 timing, you can also use 8 bit data frame format, thus you will need to adjust the bit representation.
23const N0: u16 = 0b1111100000000000u16; // ws2812 Bit 0 high level timing
24const N1: u16 = 0b1111111111000000u16; // ws2812 Bit 1 high level timing
25
26// ws2812 only need 24 bits for each LED,
27// but we add one bit more to keep SPI output low at the end
28
29static TURN_OFF: [u16; 25] = [
30 N0, N0, N0, N0, N0, N0, N0, N0, // Green
31 N0, N0, N0, N0, N0, N0, N0, N0, // Red
32 N0, N0, N0, N0, N0, N0, N0, N0, // Blue
33 0, // keep SPI output low after last bit
34];
35
36static DIM_WHITE: [u16; 25] = [
37 N0, N0, N0, N0, N0, N0, N1, N0, // Green
38 N0, N0, N0, N0, N0, N0, N1, N0, // Red
39 N0, N0, N0, N0, N0, N0, N1, N0, // Blue
40 0, // keep SPI output low after last bit
41];
42
43static COLOR_LIST: &[&[u16]] = &[&TURN_OFF, &DIM_WHITE];
44
45#[embassy_executor::main]
46async fn main(_spawner: embassy_executor::Spawner) {
47 let mut device_config = embassy_stm32::Config::default();
48
49 // Since we use 16 bit SPI, and we need each round 800 kHz,
50 // thus SPI output speed should be 800 kHz * 16 = 12.8 MHz, and APB clock should be 2 * 12.8 MHz = 25.6 MHz.
51 //
52 // As for my setup, with 12 MHz HSE, I got 25.5 MHz SYSCLK, which is slightly slower, but it's ok for ws2812.
53 {
54 use embassy_stm32::rcc::{Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllSource, Sysclk};
55 use embassy_stm32::time::mhz;
56 device_config.enable_debug_during_sleep = true;
57 device_config.rcc.hse = Some(Hse {
58 freq: mhz(12),
59 mode: HseMode::Oscillator,
60 });
61 device_config.rcc.pll_src = PllSource::HSE;
62 device_config.rcc.pll = Some(Pll {
63 prediv: PllPreDiv::DIV6,
64 mul: PllMul::MUL102,
65 divp: Some(PllPDiv::DIV8),
66 divq: None,
67 divr: None,
68 });
69 device_config.rcc.sys = Sysclk::PLL1_P;
70 }
71
72 let dp = embassy_stm32::init(device_config);
73
74 // Set SPI output speed.
75 // It's ok to blindly set frequency to 12800 kHz, the hal crate will take care of the SPI CR1 BR field.
76 // And in my case, the real bit rate will be 25.5 MHz / 2 = 12_750 kHz
77 let mut spi_config = spi::Config::default();
78 spi_config.frequency = khz(12_800);
79
80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered
81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config);
82
83 // flip color at 2 Hz
84 let mut ticker = Ticker::every(Duration::from_millis(500));
85
86 loop {
87 for &color in COLOR_LIST {
88 ws2812_spi.write(color).await.unwrap();
89 // ws2812 need at least 50 us low level input to confirm the input data and change it's state
90 Timer::after_micros(50).await;
91 // wait until ticker tick
92 ticker.next().await;
93 }
94 }
95}
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 4cca0d93c..b76a848a8 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f767zi to your chip name, if necessary. 8# Change stm32f767zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embedded-io-async = { version = "0.6.1" } 14embedded-io-async = { version = "0.6.1" }
@@ -27,7 +27,7 @@ nb = "1.0.0"
27rand_core = "0.6.3" 27rand_core = "0.6.3"
28critical-section = "1.1" 28critical-section = "1.1"
29embedded-storage = "0.3.1" 29embedded-storage = "0.3.1"
30static_cell = { version = "2", features = ["nightly"]} 30static_cell = "2"
31 31
32[profile.release] 32[profile.release]
33debug = 2 33debug = 2
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index 48c59eaf0..f8d7b691f 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f7/src/bin/blinky.rs b/examples/stm32f7/src/bin/blinky.rs
index 4bfc5a50d..31cce8225 100644
--- a/examples/stm32f7/src/bin/blinky.rs
+++ b/examples/stm32f7/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f7/src/bin/button.rs b/examples/stm32f7/src/bin/button.rs
index b13e64531..ad30a56a2 100644
--- a/examples/stm32f7/src/bin/button.rs
+++ b/examples/stm32f7/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
@@ -13,7 +12,7 @@ fn main() -> ! {
13 12
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 14
16 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = Input::new(p.PC13, Pull::Down);
17 let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); 16 let mut led1 = Output::new(p.PB0, Level::High, Speed::Low);
18 let _led2 = Output::new(p.PB7, Level::High, Speed::Low); 17 let _led2 = Output::new(p.PB7, Level::High, Speed::Low);
19 let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); 18 let mut led3 = Output::new(p.PB14, Level::High, Speed::Low);
diff --git a/examples/stm32f7/src/bin/button_exti.rs b/examples/stm32f7/src/bin/button_exti.rs
index dfe587d41..67751187d 100644
--- a/examples/stm32f7/src/bin/button_exti.rs
+++ b/examples/stm32f7/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
index 78b21ceaa..bcfdb67a8 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -12,6 +11,7 @@ use embassy_stm32::can::{
12}; 11};
13use embassy_stm32::gpio::{Input, Pull}; 12use embassy_stm32::gpio::{Input, Pull};
14use embassy_stm32::peripherals::CAN3; 13use embassy_stm32::peripherals::CAN3;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
@@ -43,7 +43,8 @@ async fn main(spawner: Spawner) {
43 let rx_pin = Input::new(&mut p.PA15, Pull::Up); 43 let rx_pin = Input::new(&mut p.PA15, Pull::Up);
44 core::mem::forget(rx_pin); 44 core::mem::forget(rx_pin);
45 45
46 let can: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); 46 static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new();
47 let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
47 can.as_mut() 48 can.as_mut()
48 .modify_filters() 49 .modify_filters()
49 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 50 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
@@ -56,7 +57,8 @@ async fn main(spawner: Spawner) {
56 57
57 let (tx, mut rx) = can.split(); 58 let (tx, mut rx) = can.split();
58 59
59 let tx: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx); 60 static CAN_TX: StaticCell<CanTx<'static, 'static, CAN3>> = StaticCell::new();
61 let tx = CAN_TX.init(tx);
60 spawner.spawn(send_can_message(tx)).unwrap(); 62 spawner.spawn(send_can_message(tx)).unwrap();
61 63
62 loop { 64 loop {
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index dd0069447..5bff48197 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -15,7 +14,7 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
15use embassy_time::Timer; 14use embassy_time::Timer;
16use embedded_io_async::Write; 15use embedded_io_async::Write;
17use rand_core::RngCore; 16use rand_core::RngCore;
18use static_cell::make_static; 17use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
20 19
21bind_interrupts!(struct Irqs { 20bind_interrupts!(struct Irqs {
@@ -64,8 +63,9 @@ async fn main(spawner: Spawner) -> ! {
64 63
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66 65
66 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
67 let device = Ethernet::new( 67 let device = Ethernet::new(
68 make_static!(PacketQueue::<16, 16>::new()), 68 PACKETS.init(PacketQueue::<16, 16>::new()),
69 p.ETH, 69 p.ETH,
70 Irqs, 70 Irqs,
71 p.PA1, 71 p.PA1,
@@ -89,11 +89,13 @@ async fn main(spawner: Spawner) -> ! {
89 //}); 89 //});
90 90
91 // Init network stack 91 // Init network stack
92 let stack = &*make_static!(Stack::new( 92 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
93 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new(
93 device, 95 device,
94 config, 96 config,
95 make_static!(StackResources::<2>::new()), 97 RESOURCES.init(StackResources::<2>::new()),
96 seed 98 seed,
97 )); 99 ));
98 100
99 // Launch network task 101 // Launch network task
diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs
index 06a94f1c8..885570478 100644
--- a/examples/stm32f7/src/bin/flash.rs
+++ b/examples/stm32f7/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f7/src/bin/hello.rs b/examples/stm32f7/src/bin/hello.rs
index a2a287110..3c295612c 100644
--- a/examples/stm32f7/src/bin/hello.rs
+++ b/examples/stm32f7/src/bin/hello.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::info; 4use defmt::info;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs
index 990de0ab1..6d36ef518 100644
--- a/examples/stm32f7/src/bin/sdmmc.rs
+++ b/examples/stm32f7/src/bin/sdmmc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs
index ba064081e..fb604b34f 100644
--- a/examples/stm32f7/src/bin/usart_dma.rs
+++ b/examples/stm32f7/src/bin/usart_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6 5
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 4991edbf0..97daf6bd1 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index b1e749440..0abc0a638 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32g071rb to your chip name, if necessary. 8# Change stm32g071rb to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32g0/src/bin/blinky.rs b/examples/stm32g0/src/bin/blinky.rs
index 4bfc5a50d..31cce8225 100644
--- a/examples/stm32g0/src/bin/blinky.rs
+++ b/examples/stm32g0/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g0/src/bin/button.rs b/examples/stm32g0/src/bin/button.rs
index 72a3f5cbf..265200132 100644
--- a/examples/stm32g0/src/bin/button.rs
+++ b/examples/stm32g0/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
@@ -13,7 +12,7 @@ fn main() -> ! {
13 12
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 14
16 let button = Input::new(p.PC13, Pull::Up); 15 let mut button = Input::new(p.PC13, Pull::Up);
17 16
18 loop { 17 loop {
19 if button.is_high() { 18 if button.is_high() {
diff --git a/examples/stm32g0/src/bin/button_exti.rs b/examples/stm32g0/src/bin/button_exti.rs
index ef32d4c4a..1e970fdd6 100644
--- a/examples/stm32g0/src/bin/button_exti.rs
+++ b/examples/stm32g0/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g0/src/bin/flash.rs b/examples/stm32g0/src/bin/flash.rs
index ed9f2e843..acef87b92 100644
--- a/examples/stm32g0/src/bin/flash.rs
+++ b/examples/stm32g0/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
index 214462d0e..c5ea51721 100644
--- a/examples/stm32g0/src/bin/spi_neopixel.rs
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index c56a63623..987f23b3a 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32g491re to your chip name, if necessary. 8# Change stm32g491re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 63b20c0d4..35324d931 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g4/src/bin/blinky.rs b/examples/stm32g4/src/bin/blinky.rs
index cbeb0dee1..90e479aae 100644
--- a/examples/stm32g4/src/bin/blinky.rs
+++ b/examples/stm32g4/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g4/src/bin/button.rs b/examples/stm32g4/src/bin/button.rs
index 15abd86d9..6f3db0819 100644
--- a/examples/stm32g4/src/bin/button.rs
+++ b/examples/stm32g4/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
@@ -13,7 +12,7 @@ fn main() -> ! {
13 12
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 14
16 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = Input::new(p.PC13, Pull::Down);
17 16
18 loop { 17 loop {
19 if button.is_high() { 18 if button.is_high() {
diff --git a/examples/stm32g4/src/bin/button_exti.rs b/examples/stm32g4/src/bin/button_exti.rs
index dfe587d41..67751187d 100644
--- a/examples/stm32g4/src/bin/button_exti.rs
+++ b/examples/stm32g4/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 09ef59d44..46ebe0b0d 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs
index a84394005..d4809a481 100644
--- a/examples/stm32g4/src/bin/pwm.rs
+++ b/examples/stm32g4/src/bin/pwm.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 565b25d60..c26fa76b7 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index 0ed0ce3c0..8815b8e47 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32h563zi to your chip name, if necessary. 8# Change stm32h563zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } 13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -19,8 +19,8 @@ defmt-rtt = "0.4"
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
23embedded-hal-async = { version = "=1.0.0-rc.2" } 23embedded-hal-async = { version = "=1.0.0-rc.3" }
24embedded-io-async = { version = "0.6.1" } 24embedded-io-async = { version = "0.6.1" }
25embedded-nal-async = { version = "0.7.1" } 25embedded-nal-async = { version = "0.7.1" }
26panic-probe = { version = "0.3", features = ["print-defmt"] } 26panic-probe = { version = "0.3", features = ["print-defmt"] }
@@ -31,7 +31,7 @@ critical-section = "1.1"
31micromath = "2.0.0" 31micromath = "2.0.0"
32stm32-fmc = "0.3.0" 32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.1" 33embedded-storage = "0.3.1"
34static_cell = { version = "2", features = ["nightly"]} 34static_cell = "2"
35 35
36# cargo build/run 36# cargo build/run
37[profile.dev] 37[profile.dev]
diff --git a/examples/stm32h5/src/bin/blinky.rs b/examples/stm32h5/src/bin/blinky.rs
index 1394f03fa..f37e8b1d8 100644
--- a/examples/stm32h5/src/bin/blinky.rs
+++ b/examples/stm32h5/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs
index dfe587d41..67751187d 100644
--- a/examples/stm32h5/src/bin/button_exti.rs
+++ b/examples/stm32h5/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index b2758cba0..2370656e6 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -18,7 +17,7 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
18use embassy_time::Timer; 17use embassy_time::Timer;
19use embedded_io_async::Write; 18use embedded_io_async::Write;
20use rand_core::RngCore; 19use rand_core::RngCore;
21use static_cell::make_static; 20use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
23 22
24bind_interrupts!(struct Irqs { 23bind_interrupts!(struct Irqs {
@@ -67,8 +66,9 @@ async fn main(spawner: Spawner) -> ! {
67 66
68 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 67 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
69 68
69 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
70 let device = Ethernet::new( 70 let device = Ethernet::new(
71 make_static!(PacketQueue::<4, 4>::new()), 71 PACKETS.init(PacketQueue::<4, 4>::new()),
72 p.ETH, 72 p.ETH,
73 Irqs, 73 Irqs,
74 p.PA1, 74 p.PA1,
@@ -92,11 +92,13 @@ async fn main(spawner: Spawner) -> ! {
92 //}); 92 //});
93 93
94 // Init network stack 94 // Init network stack
95 let stack = &*make_static!(Stack::new( 95 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
97 let stack = &*STACK.init(Stack::new(
96 device, 98 device,
97 config, 99 config,
98 make_static!(StackResources::<2>::new()), 100 RESOURCES.init(StackResources::<2>::new()),
99 seed 101 seed,
100 )); 102 ));
101 103
102 // Launch network task 104 // Launch network task
diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs
index 31783a2bf..31e83cbb5 100644
--- a/examples/stm32h5/src/bin/i2c.rs
+++ b/examples/stm32h5/src/bin/i2c.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h5/src/bin/rng.rs b/examples/stm32h5/src/bin/rng.rs
index 7c8c50eca..9c0d704b5 100644
--- a/examples/stm32h5/src/bin/rng.rs
+++ b/examples/stm32h5/src/bin/rng.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
index db04d4e55..f9cbad6af 100644
--- a/examples/stm32h5/src/bin/usart.rs
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
index bafe50839..caae0dd18 100644
--- a/examples/stm32h5/src/bin/usart_dma.rs
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6 5
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
index d9037c014..92047de8d 100644
--- a/examples/stm32h5/src/bin/usart_split.rs
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 7d45818af..208493d8c 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index baa530cf6..31feeda45 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 13embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -19,8 +19,8 @@ defmt-rtt = "0.4"
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
23embedded-hal-async = { version = "=1.0.0-rc.2" } 23embedded-hal-async = { version = "=1.0.0-rc.3" }
24embedded-nal-async = { version = "0.7.1" } 24embedded-nal-async = { version = "0.7.1" }
25embedded-io-async = { version = "0.6.1" } 25embedded-io-async = { version = "0.6.1" }
26panic-probe = { version = "0.3", features = ["print-defmt"] } 26panic-probe = { version = "0.3", features = ["print-defmt"] }
@@ -31,7 +31,7 @@ critical-section = "1.1"
31micromath = "2.0.0" 31micromath = "2.0.0"
32stm32-fmc = "0.3.0" 32stm32-fmc = "0.3.0"
33embedded-storage = "0.3.1" 33embedded-storage = "0.3.1"
34static_cell = { version = "2", features = ["nightly"]} 34static_cell = "2"
35chrono = { version = "^0.4", default-features = false } 35chrono = { version = "^0.4", default-features = false }
36 36
37# cargo build/run 37# cargo build/run
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index e367827e9..fe6fe69a1 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/blinky.rs b/examples/stm32h7/src/bin/blinky.rs
index a9cab1ff4..1ee90a870 100644
--- a/examples/stm32h7/src/bin/blinky.rs
+++ b/examples/stm32h7/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/button_exti.rs b/examples/stm32h7/src/bin/button_exti.rs
index dfe587d41..67751187d 100644
--- a/examples/stm32h7/src/bin/button_exti.rs
+++ b/examples/stm32h7/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs
index 489fb03dd..e5a104baf 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use embassy_executor::Spawner; 4use embassy_executor::Spawner;
6use embassy_stm32::dcmi::{self, *}; 5use embassy_stm32::dcmi::{self, *};
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index f66268151..a9bf46de0 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index c19fdd623..8e5c41a43 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -1,11 +1,10 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm}; 7use embassy_stm32::pac::timer::vals::Mms;
9use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
@@ -79,7 +78,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
79 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 78 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
80 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 79 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
81 TIM6::regs().cr1().modify(|w| { 80 TIM6::regs().cr1().modify(|w| {
82 w.set_opm(Opm::DISABLED); 81 w.set_opm(false);
83 w.set_cen(true); 82 w.set_cen(true);
84 }); 83 });
85 84
@@ -116,7 +115,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
116 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 115 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
117 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 116 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
118 TIM7::regs().cr1().modify(|w| { 117 TIM7::regs().cr1().modify(|w| {
119 w.set_opm(Opm::DISABLED); 118 w.set_opm(false);
120 w.set_cen(true); 119 w.set_cen(true);
121 }); 120 });
122 121
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index dbddfc22f..cd9a27fcd 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -14,7 +13,7 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
14use embassy_time::Timer; 13use embassy_time::Timer;
15use embedded_io_async::Write; 14use embedded_io_async::Write;
16use rand_core::RngCore; 15use rand_core::RngCore;
17use static_cell::make_static; 16use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
20bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
@@ -64,8 +63,9 @@ async fn main(spawner: Spawner) -> ! {
64 63
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66 65
66 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
67 let device = Ethernet::new( 67 let device = Ethernet::new(
68 make_static!(PacketQueue::<16, 16>::new()), 68 PACKETS.init(PacketQueue::<4, 4>::new()),
69 p.ETH, 69 p.ETH,
70 Irqs, 70 Irqs,
71 p.PA1, 71 p.PA1,
@@ -89,11 +89,13 @@ async fn main(spawner: Spawner) -> ! {
89 //}); 89 //});
90 90
91 // Init network stack 91 // Init network stack
92 let stack = &*make_static!(Stack::new( 92 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
93 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new(
93 device, 95 device,
94 config, 96 config,
95 make_static!(StackResources::<3>::new()), 97 RESOURCES.init(StackResources::<3>::new()),
96 seed 98 seed,
97 )); 99 ));
98 100
99 // Launch network task 101 // Launch network task
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 17e1d9fb7..dcc6e36e2 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -15,7 +14,7 @@ use embassy_time::Timer;
15use embedded_io_async::Write; 14use embedded_io_async::Write;
16use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; 15use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect};
17use rand_core::RngCore; 16use rand_core::RngCore;
18use static_cell::make_static; 17use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
20 19
21bind_interrupts!(struct Irqs { 20bind_interrupts!(struct Irqs {
@@ -65,8 +64,9 @@ async fn main(spawner: Spawner) -> ! {
65 64
66 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
67 66
67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
68 let device = Ethernet::new( 68 let device = Ethernet::new(
69 make_static!(PacketQueue::<16, 16>::new()), 69 PACKETS.init(PacketQueue::<16, 16>::new()),
70 p.ETH, 70 p.ETH,
71 Irqs, 71 Irqs,
72 p.PA1, 72 p.PA1,
@@ -90,11 +90,13 @@ async fn main(spawner: Spawner) -> ! {
90 //}); 90 //});
91 91
92 // Init network stack 92 // Init network stack
93 let stack = &*make_static!(Stack::new( 93 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
95 let stack = &*STACK.init(Stack::new(
94 device, 96 device,
95 config, 97 config,
96 make_static!(StackResources::<3>::new()), 98 RESOURCES.init(StackResources::<3>::new()),
97 seed 99 seed,
98 )); 100 ));
99 101
100 // Launch network task 102 // Launch network task
diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs
index 89c0c8a66..4f9f6bb0a 100644
--- a/examples/stm32h7/src/bin/flash.rs
+++ b/examples/stm32h7/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs
index 54e2c3629..5e5e6ccc8 100644
--- a/examples/stm32h7/src/bin/fmc.rs
+++ b/examples/stm32h7/src/bin/fmc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs
index aea21ec6f..3bf39eb44 100644
--- a/examples/stm32h7/src/bin/i2c.rs
+++ b/examples/stm32h7/src/bin/i2c.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index e0be495d1..cc508c3cf 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -85,7 +84,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
85 84
86 let mut this = Self { inner: tim }; 85 let mut this = Self { inner: tim };
87 86
88 this.set_freq(freq); 87 this.set_frequency(freq);
89 this.inner.start(); 88 this.inner.start();
90 89
91 let r = T::regs_gp32(); 90 let r = T::regs_gp32();
@@ -102,14 +101,14 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
102 } 101 }
103 102
104 pub fn enable(&mut self, channel: Channel) { 103 pub fn enable(&mut self, channel: Channel) {
105 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); 104 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true));
106 } 105 }
107 106
108 pub fn disable(&mut self, channel: Channel) { 107 pub fn disable(&mut self, channel: Channel) {
109 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); 108 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false));
110 } 109 }
111 110
112 pub fn set_freq(&mut self, freq: Hertz) { 111 pub fn set_frequency(&mut self, freq: Hertz) {
113 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); 112 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq);
114 } 113 }
115 114
@@ -119,6 +118,6 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
119 118
120 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 119 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
121 defmt::assert!(duty < self.get_max_duty()); 120 defmt::assert!(duty < self.get_max_duty());
122 T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) 121 T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty))
123 } 122 }
124} 123}
diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs
index c023f4584..a6ee27625 100644
--- a/examples/stm32h7/src/bin/mco.rs
+++ b/examples/stm32h7/src/bin/mco.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs
index c55d780a0..1e48ba67b 100644
--- a/examples/stm32h7/src/bin/pwm.rs
+++ b/examples/stm32h7/src/bin/pwm.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs
index 1fb4cfec0..a9ef7200d 100644
--- a/examples/stm32h7/src/bin/rng.rs
+++ b/examples/stm32h7/src/bin/rng.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs
index 78cea9c89..c6b9cf57e 100644
--- a/examples/stm32h7/src/bin/rtc.rs
+++ b/examples/stm32h7/src/bin/rtc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use chrono::{NaiveDate, NaiveDateTime}; 4use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs
index be968ff77..abe2d4ba7 100644
--- a/examples/stm32h7/src/bin/sdmmc.rs
+++ b/examples/stm32h7/src/bin/sdmmc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs
index b5f583289..b73360f32 100644
--- a/examples/stm32h7/src/bin/signal.rs
+++ b/examples/stm32h7/src/bin/signal.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index a8db0ff77..aed27723a 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6use core::str::from_utf8; 5use core::str::from_utf8;
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 561052e48..54d4d7656 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6use core::str::from_utf8; 5use core::str::from_utf8;
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index db04d4e55..f9cbad6af 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index 249050fd1..ae1f3a2e9 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6 5
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index 61c9f1954..b98c40877 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index f80cf63ec..d81efb541 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs
index 76fd9dfc0..a4184aa96 100644
--- a/examples/stm32h7/src/bin/wdg.rs
+++ b/examples/stm32h7/src/bin/wdg.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 7c8264739..739aa6cb1 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -4,10 +4,6 @@ name = "embassy-stm32l0-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[features]
8default = ["nightly"]
9nightly = ["embassy-executor/nightly"]
10
11[dependencies] 7[dependencies]
12# Change stm32l072cz to your chip name, if necessary. 8# Change stm32l072cz to your chip name, if necessary.
13embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
diff --git a/examples/stm32l0/src/bin/blinky.rs b/examples/stm32l0/src/bin/blinky.rs
index ea40bfc48..caca5759f 100644
--- a/examples/stm32l0/src/bin/blinky.rs
+++ b/examples/stm32l0/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l0/src/bin/button.rs b/examples/stm32l0/src/bin/button.rs
index 9d194471e..165a714a5 100644
--- a/examples/stm32l0/src/bin/button.rs
+++ b/examples/stm32l0/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -12,7 +11,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 11 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 12 info!("Hello World!");
14 13
15 let button = Input::new(p.PB2, Pull::Up); 14 let mut button = Input::new(p.PB2, Pull::Up);
16 let mut led1 = Output::new(p.PA5, Level::High, Speed::Low); 15 let mut led1 = Output::new(p.PA5, Level::High, Speed::Low);
17 let mut led2 = Output::new(p.PB5, Level::High, Speed::Low); 16 let mut led2 = Output::new(p.PB5, Level::High, Speed::Low);
18 17
diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs
index ffede253e..f517fce04 100644
--- a/examples/stm32l0/src/bin/button_exti.rs
+++ b/examples/stm32l0/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs
index 86f6c70b9..1865748fd 100644
--- a/examples/stm32l0/src/bin/flash.rs
+++ b/examples/stm32l0/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs
index 583e3d127..f23a537b8 100644
--- a/examples/stm32l0/src/bin/spi.rs
+++ b/examples/stm32l0/src/bin/spi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs
index 62c9b5595..74889c838 100644
--- a/examples/stm32l0/src/bin/usart_dma.rs
+++ b/examples/stm32l0/src/bin/usart_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs
index 5107a1a0a..2c96a8bc2 100644
--- a/examples/stm32l0/src/bin/usart_irq.rs
+++ b/examples/stm32l0/src/bin/usart_irq.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 23dd0ef87..071d6a502 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.5.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12 12
diff --git a/examples/stm32l1/src/bin/blinky.rs b/examples/stm32l1/src/bin/blinky.rs
index 06f732eb7..da6777b2d 100644
--- a/examples/stm32l1/src/bin/blinky.rs
+++ b/examples/stm32l1/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs
index aeb535cca..e9ce4eae8 100644
--- a/examples/stm32l1/src/bin/flash.rs
+++ b/examples/stm32l1/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs
index 905b4d75c..8be686c5a 100644
--- a/examples/stm32l1/src/bin/spi.rs
+++ b/examples/stm32l1/src/bin/spi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index a936d27c3..8a5fb5749 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32l4s5vi to your chip name, if necessary. 8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
@@ -24,15 +24,15 @@ defmt-rtt = "0.4"
24cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 24cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
25cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
26embedded-hal = "0.2.6" 26embedded-hal = "0.2.6"
27embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 27embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
28embedded-hal-async = { version = "=1.0.0-rc.2" } 28embedded-hal-async = { version = "=1.0.0-rc.3" }
29embedded-hal-bus = { version = "=0.1.0-rc.2", features = ["async"] } 29embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] }
30panic-probe = { version = "0.3", features = ["print-defmt"] } 30panic-probe = { version = "0.3", features = ["print-defmt"] }
31futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 31futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
32heapless = { version = "0.8", default-features = false } 32heapless = { version = "0.8", default-features = false }
33chrono = { version = "^0.4", default-features = false } 33chrono = { version = "^0.4", default-features = false }
34rand = { version = "0.8.5", default-features = false } 34rand = { version = "0.8.5", default-features = false }
35static_cell = { version = "2", features = ["nightly"]} 35static_cell = "2"
36 36
37micromath = "2.0.0" 37micromath = "2.0.0"
38 38
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index a0ec5c33e..d01e9f1b3 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_stm32::adc::{Adc, Resolution}; 5use embassy_stm32::adc::{Adc, Resolution};
diff --git a/examples/stm32l4/src/bin/blinky.rs b/examples/stm32l4/src/bin/blinky.rs
index 6202fe2f7..b55dfd35e 100644
--- a/examples/stm32l4/src/bin/blinky.rs
+++ b/examples/stm32l4/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l4/src/bin/button.rs b/examples/stm32l4/src/bin/button.rs
index 73b1962e8..15288c61e 100644
--- a/examples/stm32l4/src/bin/button.rs
+++ b/examples/stm32l4/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_stm32::gpio::{Input, Pull}; 5use embassy_stm32::gpio::{Input, Pull};
@@ -12,7 +11,7 @@ fn main() -> ! {
12 11
13 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
14 13
15 let button = Input::new(p.PC13, Pull::Up); 14 let mut button = Input::new(p.PC13, Pull::Up);
16 15
17 loop { 16 loop {
18 if button.is_high() { 17 if button.is_high() {
diff --git a/examples/stm32l4/src/bin/button_exti.rs b/examples/stm32l4/src/bin/button_exti.rs
index ef32d4c4a..1e970fdd6 100644
--- a/examples/stm32l4/src/bin/button_exti.rs
+++ b/examples/stm32l4/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index d6a7ff624..fdbf1d374 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_stm32::dac::{DacCh1, Value}; 5use embassy_stm32::dac::{DacCh1, Value};
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index dc86dbf43..8e5098557 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -1,11 +1,10 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; 6use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm}; 7use embassy_stm32::pac::timer::vals::Mms;
9use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
@@ -50,7 +49,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
50 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 49 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
51 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 50 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
52 TIM6::regs().cr1().modify(|w| { 51 TIM6::regs().cr1().modify(|w| {
53 w.set_opm(Opm::DISABLED); 52 w.set_opm(false);
54 w.set_cen(true); 53 w.set_cen(true);
55 }); 54 });
56 55
@@ -87,7 +86,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
87 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 86 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
88 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 87 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
89 TIM7::regs().cr1().modify(|w| { 88 TIM7::regs().cr1().modify(|w| {
90 w.set_opm(Opm::DISABLED); 89 w.set_opm(false);
91 w.set_cen(true); 90 w.set_cen(true);
92 }); 91 });
93 92
diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs
index 07dc12e8c..f553deb82 100644
--- a/examples/stm32l4/src/bin/i2c.rs
+++ b/examples/stm32l4/src/bin/i2c.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs
index 60a4e2eb3..1b8652bcc 100644
--- a/examples/stm32l4/src/bin/i2c_blocking_async.rs
+++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/stm32l4/src/bin/i2c_dma.rs b/examples/stm32l4/src/bin/i2c_dma.rs
index 4c2c224a6..794972a33 100644
--- a/examples/stm32l4/src/bin/i2c_dma.rs
+++ b/examples/stm32l4/src/bin/i2c_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs
index 504879887..36c002952 100644
--- a/examples/stm32l4/src/bin/mco.rs
+++ b/examples/stm32l4/src/bin/mco.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs
index e5ad56fb9..638b3e9e4 100644
--- a/examples/stm32l4/src/bin/rng.rs
+++ b/examples/stm32l4/src/bin/rng.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
index d2a2aa1f2..526620bfb 100644
--- a/examples/stm32l4/src/bin/rtc.rs
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use chrono::{NaiveDate, NaiveDateTime}; 4use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 4826e0bed..9565ae168 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -1,10 +1,7 @@
1#![deny(clippy::pedantic)]
2#![allow(clippy::doc_markdown)]
3#![no_main] 1#![no_main]
4#![no_std] 2#![no_std]
5// Needed unitl https://github.com/rust-lang/rust/issues/63063 is stablised. 3#![deny(clippy::pedantic)]
6#![feature(type_alias_impl_trait)] 4#![allow(clippy::doc_markdown)]
7#![feature(associated_type_bounds)]
8#![allow(clippy::missing_errors_doc)] 5#![allow(clippy::missing_errors_doc)]
9 6
10// This example works on a ANALOG DEVICE EVAL-ADIN110EBZ board. 7// This example works on a ANALOG DEVICE EVAL-ADIN110EBZ board.
@@ -36,7 +33,7 @@ use hal::rng::{self, Rng};
36use hal::{bind_interrupts, exti, pac, peripherals}; 33use hal::{bind_interrupts, exti, pac, peripherals};
37use heapless::Vec; 34use heapless::Vec;
38use rand::RngCore; 35use rand::RngCore;
39use static_cell::make_static; 36use static_cell::StaticCell;
40use {embassy_stm32 as hal, panic_probe as _}; 37use {embassy_stm32 as hal, panic_probe as _};
41 38
42bind_interrupts!(struct Irqs { 39bind_interrupts!(struct Irqs {
@@ -114,8 +111,8 @@ async fn main(spawner: Spawner) {
114 let led_uc4_blue = Output::new(dp.PG15, Level::High, Speed::Low); 111 let led_uc4_blue = Output::new(dp.PG15, Level::High, Speed::Low);
115 112
116 // Read the uc_cfg switches 113 // Read the uc_cfg switches
117 let uc_cfg0 = Input::new(dp.PB2, Pull::None); 114 let mut uc_cfg0 = Input::new(dp.PB2, Pull::None);
118 let uc_cfg1 = Input::new(dp.PF11, Pull::None); 115 let mut uc_cfg1 = Input::new(dp.PF11, Pull::None);
119 let _uc_cfg2 = Input::new(dp.PG6, Pull::None); 116 let _uc_cfg2 = Input::new(dp.PG6, Pull::None);
120 let _uc_cfg3 = Input::new(dp.PG11, Pull::None); 117 let _uc_cfg3 = Input::new(dp.PG11, Pull::None);
121 118
@@ -133,8 +130,8 @@ async fn main(spawner: Spawner) {
133 130
134 // Setup IO and SPI for the SPE chip 131 // Setup IO and SPI for the SPE chip
135 let spe_reset_n = Output::new(dp.PC7, Level::Low, Speed::Low); 132 let spe_reset_n = Output::new(dp.PC7, Level::Low, Speed::Low);
136 let spe_cfg0 = Input::new(dp.PC8, Pull::None); 133 let mut spe_cfg0 = Input::new(dp.PC8, Pull::None);
137 let spe_cfg1 = Input::new(dp.PC9, Pull::None); 134 let mut spe_cfg1 = Input::new(dp.PC9, Pull::None);
138 let _spe_ts_capt = Output::new(dp.PC6, Level::Low, Speed::Low); 135 let _spe_ts_capt = Output::new(dp.PC6, Level::Low, Speed::Low);
139 136
140 let spe_int = Input::new(dp.PB11, Pull::None); 137 let spe_int = Input::new(dp.PB11, Pull::None);
@@ -180,7 +177,8 @@ async fn main(spawner: Spawner) {
180 } 177 }
181 }; 178 };
182 179
183 let state = make_static!(embassy_net_adin1110::State::<8, 8>::new()); 180 static STATE: StaticCell<embassy_net_adin1110::State<8, 8>> = StaticCell::new();
181 let state = STATE.init(embassy_net_adin1110::State::<8, 8>::new());
184 182
185 let (device, runner) = embassy_net_adin1110::new( 183 let (device, runner) = embassy_net_adin1110::new(
186 MAC, 184 MAC,
@@ -217,11 +215,13 @@ async fn main(spawner: Spawner) {
217 }; 215 };
218 216
219 // Init network stack 217 // Init network stack
220 let stack = &*make_static!(Stack::new( 218 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
219 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
220 let stack = &*STACK.init(Stack::new(
221 device, 221 device,
222 ip_cfg, 222 ip_cfg,
223 make_static!(StackResources::<2>::new()), 223 RESOURCES.init(StackResources::<2>::new()),
224 seed 224 seed,
225 )); 225 ));
226 226
227 // Launch network task 227 // Launch network task
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs
index 54cf68f7b..6653e4516 100644
--- a/examples/stm32l4/src/bin/spi.rs
+++ b/examples/stm32l4/src/bin/spi.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_stm32::dma::NoDma; 5use embassy_stm32::dma::NoDma;
diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs
index f1b80087c..a989a5a4a 100644
--- a/examples/stm32l4/src/bin/spi_blocking_async.rs
+++ b/examples/stm32l4/src/bin/spi_blocking_async.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
@@ -30,7 +29,7 @@ async fn main(_spawner: Spawner) {
30 let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh); 29 let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh);
31 let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh); 30 let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh);
32 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 31 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
33 let ready = Input::new(p.PE1, Pull::Up); 32 let mut ready = Input::new(p.PE1, Pull::Up);
34 33
35 cortex_m::asm::delay(100_000); 34 cortex_m::asm::delay(100_000);
36 reset.set_high(); 35 reset.set_high();
diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs
index ff9b5b43b..7922165df 100644
--- a/examples/stm32l4/src/bin/spi_dma.rs
+++ b/examples/stm32l4/src/bin/spi_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -25,7 +24,7 @@ async fn main(_spawner: Spawner) {
25 let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh); 24 let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh);
26 let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh); 25 let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh);
27 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 26 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
28 let ready = Input::new(p.PE1, Pull::Up); 27 let mut ready = Input::new(p.PE1, Pull::Up);
29 28
30 cortex_m::asm::delay(100_000); 29 cortex_m::asm::delay(100_000);
31 reset.set_high(); 30 reset.set_high();
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index f4da6b5ae..7bab23950 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_stm32::dma::NoDma; 5use embassy_stm32::dma::NoDma;
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index 2f3b2a0f0..031888f70 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::fmt::Write; 4use core::fmt::Write;
6 5
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 4baf5f05d..8cc9a7aed 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 2557ef42d..0d236ec90 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32l552ze to your chip name, if necessary. 8# Change stm32l552ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
@@ -26,7 +26,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
26heapless = { version = "0.8", default-features = false } 26heapless = { version = "0.8", default-features = false }
27rand_core = { version = "0.6.3", default-features = false } 27rand_core = { version = "0.6.3", default-features = false }
28embedded-io-async = { version = "0.6.1" } 28embedded-io-async = { version = "0.6.1" }
29static_cell = { version = "2", features = ["nightly"]} 29static_cell = "2"
30 30
31[profile.release] 31[profile.release]
32debug = 2 32debug = 2
diff --git a/examples/stm32l5/src/bin/button_exti.rs b/examples/stm32l5/src/bin/button_exti.rs
index e80ad2b3a..91d0ccc2e 100644
--- a/examples/stm32l5/src/bin/button_exti.rs
+++ b/examples/stm32l5/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs
index 279f4f65d..50da6c946 100644
--- a/examples/stm32l5/src/bin/rng.rs
+++ b/examples/stm32l5/src/bin/rng.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 0b0a0e2db..88060b6b0 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -15,7 +14,7 @@ use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
15use embassy_usb::{Builder, UsbDevice}; 14use embassy_usb::{Builder, UsbDevice};
16use embedded_io_async::Write; 15use embedded_io_async::Write;
17use rand_core::RngCore; 16use rand_core::RngCore;
18use static_cell::make_static; 17use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
20 19
21type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>; 20type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>;
@@ -76,14 +75,18 @@ async fn main(spawner: Spawner) {
76 config.device_protocol = 0x01; 75 config.device_protocol = 0x01;
77 76
78 // Create embassy-usb DeviceBuilder using the driver and config. 77 // Create embassy-usb DeviceBuilder using the driver and config.
78 static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new();
79 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
80 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
81 static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new();
79 let mut builder = Builder::new( 82 let mut builder = Builder::new(
80 driver, 83 driver,
81 config, 84 config,
82 &mut make_static!([0; 256])[..], 85 &mut DEVICE_DESC.init([0; 256])[..],
83 &mut make_static!([0; 256])[..], 86 &mut CONFIG_DESC.init([0; 256])[..],
84 &mut make_static!([0; 256])[..], 87 &mut BOS_DESC.init([0; 256])[..],
85 &mut [], // no msos descriptors 88 &mut [], // no msos descriptors
86 &mut make_static!([0; 128])[..], 89 &mut CONTROL_BUF.init([0; 128])[..],
87 ); 90 );
88 91
89 // Our MAC addr. 92 // Our MAC addr.
@@ -92,14 +95,16 @@ async fn main(spawner: Spawner) {
92 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 95 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
93 96
94 // Create classes on the builder. 97 // Create classes on the builder.
95 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); 98 static STATE: StaticCell<State> = StaticCell::new();
99 let class = CdcNcmClass::new(&mut builder, STATE.init(State::new()), host_mac_addr, 64);
96 100
97 // Build the builder. 101 // Build the builder.
98 let usb = builder.build(); 102 let usb = builder.build();
99 103
100 unwrap!(spawner.spawn(usb_task(usb))); 104 unwrap!(spawner.spawn(usb_task(usb)));
101 105
102 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); 106 static NET_STATE: StaticCell<NetState<MTU, 4, 4>> = StaticCell::new();
107 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(NET_STATE.init(NetState::new()), our_mac_addr);
103 unwrap!(spawner.spawn(usb_ncm_task(runner))); 108 unwrap!(spawner.spawn(usb_ncm_task(runner)));
104 109
105 let config = embassy_net::Config::dhcpv4(Default::default()); 110 let config = embassy_net::Config::dhcpv4(Default::default());
@@ -114,11 +119,13 @@ async fn main(spawner: Spawner) {
114 let seed = rng.next_u64(); 119 let seed = rng.next_u64();
115 120
116 // Init network stack 121 // Init network stack
117 let stack = &*make_static!(Stack::new( 122 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
123 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
124 let stack = &*STACK.init(Stack::new(
118 device, 125 device,
119 config, 126 config,
120 make_static!(StackResources::<2>::new()), 127 RESOURCES.init(StackResources::<2>::new()),
121 seed 128 seed,
122 )); 129 ));
123 130
124 unwrap!(spawner.spawn(net_task(stack))); 131 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index 3614a8e0a..7c8a8ebfb 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index f2b894b68..75053ce4b 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 1afbd8db4..029b2cfe0 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32u585ai to your chip name, if necessary. 8# Change stm32u585ai to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14 14
diff --git a/examples/stm32u5/src/bin/blinky.rs b/examples/stm32u5/src/bin/blinky.rs
index 4b44cb12b..7fe88c183 100644
--- a/examples/stm32u5/src/bin/blinky.rs
+++ b/examples/stm32u5/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32u5/src/bin/boot.rs b/examples/stm32u5/src/bin/boot.rs
index e2112ce5c..23c7f8b22 100644
--- a/examples/stm32u5/src/bin/boot.rs
+++ b/examples/stm32u5/src/bin/boot.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use {defmt_rtt as _, embassy_stm32 as _, panic_probe as _}; 5use {defmt_rtt as _, embassy_stm32 as _, panic_probe as _};
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index 839d6472f..44d1df4f1 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{panic, *}; 4use defmt::{panic, *};
6use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index ada1f32e9..bce53c440 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 14embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
15 15
@@ -22,7 +22,7 @@ embedded-hal = "0.2.6"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24heapless = { version = "0.8", default-features = false } 24heapless = { version = "0.8", default-features = false }
25static_cell = { version = "2", features = ["nightly"]} 25static_cell = "2"
26 26
27[features] 27[features]
28default = ["ble", "mac"] 28default = ["ble", "mac"]
diff --git a/examples/stm32wb/src/bin/blinky.rs b/examples/stm32wb/src/bin/blinky.rs
index 1394f03fa..f37e8b1d8 100644
--- a/examples/stm32wb/src/bin/blinky.rs
+++ b/examples/stm32wb/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wb/src/bin/button_exti.rs b/examples/stm32wb/src/bin/button_exti.rs
index 3648db6ff..d34dde3e9 100644
--- a/examples/stm32wb/src/bin/button_exti.rs
+++ b/examples/stm32wb/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
index e58da8e35..cf9a5aa28 100644
--- a/examples/stm32wb/src/bin/eddystone_beacon.rs
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::time::Duration; 4use core::time::Duration;
6 5
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
index 80e835c1d..5ce620350 100644
--- a/examples/stm32wb/src/bin/gatt_server.rs
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use core::time::Duration; 4use core::time::Duration;
6 5
diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs
index 881dc488d..5cd660543 100644
--- a/examples/stm32wb/src/bin/mac_ffd.rs
+++ b/examples/stm32wb/src/bin/mac_ffd.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs
index f8c76b5a4..7a42bf577 100644
--- a/examples/stm32wb/src/bin/mac_ffd_net.rs
+++ b/examples/stm32wb/src/bin/mac_ffd_net.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
@@ -12,7 +11,7 @@ use embassy_stm32_wpan::mac::typedefs::{MacChannel, PanId, PibId};
12use embassy_stm32_wpan::mac::{self, Runner}; 11use embassy_stm32_wpan::mac::{self, Runner};
13use embassy_stm32_wpan::sub::mm; 12use embassy_stm32_wpan::sub::mm;
14use embassy_stm32_wpan::TlMbox; 13use embassy_stm32_wpan::TlMbox;
15use static_cell::make_static; 14use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
18bind_interrupts!(struct Irqs{ 17bind_interrupts!(struct Irqs{
@@ -154,15 +153,21 @@ async fn main(spawner: Spawner) {
154 .unwrap(); 153 .unwrap();
155 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); 154 defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap());
156 155
156 static TX1: StaticCell<[u8; 127]> = StaticCell::new();
157 static TX2: StaticCell<[u8; 127]> = StaticCell::new();
158 static TX3: StaticCell<[u8; 127]> = StaticCell::new();
159 static TX4: StaticCell<[u8; 127]> = StaticCell::new();
160 static TX5: StaticCell<[u8; 127]> = StaticCell::new();
157 let tx_queue = [ 161 let tx_queue = [
158 make_static!([0u8; 127]), 162 TX1.init([0u8; 127]),
159 make_static!([0u8; 127]), 163 TX2.init([0u8; 127]),
160 make_static!([0u8; 127]), 164 TX3.init([0u8; 127]),
161 make_static!([0u8; 127]), 165 TX4.init([0u8; 127]),
162 make_static!([0u8; 127]), 166 TX5.init([0u8; 127]),
163 ]; 167 ];
164 168
165 let runner = make_static!(Runner::new(mbox.mac_subsystem, tx_queue)); 169 static RUNNER: StaticCell<Runner> = StaticCell::new();
170 let runner = RUNNER.init(Runner::new(mbox.mac_subsystem, tx_queue));
166 171
167 spawner.spawn(run_mac(runner)).unwrap(); 172 spawner.spawn(run_mac(runner)).unwrap();
168 173
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs
index 000355de6..7949211fb 100644
--- a/examples/stm32wb/src/bin/mac_rfd.rs
+++ b/examples/stm32wb/src/bin/mac_rfd.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
index 9d0e0070c..cb92d462d 100644
--- a/examples/stm32wb/src/bin/tl_mbox.rs
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index 12c6aeebb..2599e1151 100644
--- a/examples/stm32wb/src/bin/tl_mbox_ble.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
index f32e07d96..5d868412a 100644
--- a/examples/stm32wb/src/bin/tl_mbox_mac.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml
index c97605937..84eb6c831 100644
--- a/examples/stm32wba/Cargo.toml
+++ b/examples/stm32wba/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } 8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 12embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
13 13
@@ -20,7 +20,7 @@ embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.8", default-features = false } 22heapless = { version = "0.8", default-features = false }
23static_cell = { version = "2", features = ["nightly"]} 23static_cell = "2"
24 24
25[profile.release] 25[profile.release]
26debug = 2 26debug = 2
diff --git a/examples/stm32wba/src/bin/blinky.rs b/examples/stm32wba/src/bin/blinky.rs
index 6b9635e66..0d803b257 100644
--- a/examples/stm32wba/src/bin/blinky.rs
+++ b/examples/stm32wba/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wba/src/bin/button_exti.rs b/examples/stm32wba/src/bin/button_exti.rs
index ef32d4c4a..1e970fdd6 100644
--- a/examples/stm32wba/src/bin/button_exti.rs
+++ b/examples/stm32wba/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 070d27cb6..62c34b792 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32wl55jc-cm4 to your chip name, if necessary. 8# Change stm32wl55jc-cm4 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
14 14
diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs
index 5bd5745f0..347bd093f 100644
--- a/examples/stm32wl/src/bin/blinky.rs
+++ b/examples/stm32wl/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs
index 982a7a112..3397e5ba6 100644
--- a/examples/stm32wl/src/bin/button.rs
+++ b/examples/stm32wl/src/bin/button.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use cortex_m_rt::entry; 4use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
@@ -13,7 +12,7 @@ fn main() -> ! {
13 12
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 14
16 let button = Input::new(p.PA0, Pull::Up); 15 let mut button = Input::new(p.PA0, Pull::Up);
17 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); 16 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low);
18 let mut led2 = Output::new(p.PB9, Level::High, Speed::Low); 17 let mut led2 = Output::new(p.PB9, Level::High, Speed::Low);
19 18
diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs
index 1f02db5cf..e6ad4b80b 100644
--- a/examples/stm32wl/src/bin/button_exti.rs
+++ b/examples/stm32wl/src/bin/button_exti.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index 5e52d49ec..0b7417c01 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index 2fd234966..3610392be 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index 4ffb0bb58..4738d5770 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use chrono::{NaiveDate, NaiveDateTime}; 4use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*; 5use defmt::*;
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
index 44e8f83a2..8e545834c 100644
--- a/examples/stm32wl/src/bin/uart_async.rs
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use defmt::*; 4use defmt::*;
6use embassy_executor::Spawner; 5use embassy_executor::Spawner;
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index c96a428b9..305ebd526 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -9,7 +9,7 @@ crate-type = ["cdylib"]
9 9
10[dependencies] 10[dependencies]
11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] }
12embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] } 12embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] }
13embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "wasm", ] } 13embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "wasm", ] }
14 14
15wasm-logger = "0.2.0" 15wasm-logger = "0.2.0"
diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs
index 1141096fb..71cf980dd 100644
--- a/examples/wasm/src/lib.rs
+++ b/examples/wasm/src/lib.rs
@@ -1,5 +1,3 @@
1#![feature(type_alias_impl_trait)]
2
3use embassy_executor::Spawner; 1use embassy_executor::Spawner;
4use embassy_time::Timer; 2use embassy_time::Timer;
5 3
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
new file mode 100644
index 000000000..b8a7db353
--- /dev/null
+++ b/rust-toolchain-nightly.toml
@@ -0,0 +1,12 @@
1[toolchain]
2channel = "nightly-2023-12-20"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [
5 "thumbv7em-none-eabi",
6 "thumbv7m-none-eabi",
7 "thumbv6m-none-eabi",
8 "thumbv7em-none-eabihf",
9 "thumbv8m.main-none-eabihf",
10 "riscv32imac-unknown-none-elf",
11 "wasm32-unknown-unknown",
12]
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 11f53ee4a..a6fe52ee2 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,8 +1,6 @@
1# Before upgrading check that everything is available on all tier1 targets here:
2# https://rust-lang.github.io/rustup-components-history
3[toolchain] 1[toolchain]
4channel = "nightly-2023-11-01" 2channel = "1.75"
5components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools" ]
6targets = [ 4targets = [
7 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
8 "thumbv7m-none-eabi", 6 "thumbv7m-none-eabi",
@@ -11,4 +9,4 @@ targets = [
11 "thumbv8m.main-none-eabihf", 9 "thumbv8m.main-none-eabihf",
12 "riscv32imac-unknown-none-elf", 10 "riscv32imac-unknown-none-elf",
13 "wasm32-unknown-unknown", 11 "wasm32-unknown-unknown",
14] \ No newline at end of file 12]
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 7b0d59ee2..ccdca0844 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -16,9 +16,9 @@ embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
16embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 16embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
18embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } 18embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] }
19embedded-hal-async = { version = "1.0.0-rc.2" } 19embedded-hal-async = { version = "1.0.0-rc.3" }
20embedded-hal-bus = { version = "0.1.0-rc.2", features = ["async"] } 20embedded-hal-bus = { version = "0.1.0-rc.3", features = ["async"] }
21static_cell = { version = "2", features = [ "nightly" ] } 21static_cell = "2"
22perf-client = { path = "../perf-client" } 22perf-client = { path = "../perf-client" }
23 23
24defmt = "0.3" 24defmt = "0.3"
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
index 60d30a2ff..7dc1941d7 100644
--- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
+++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"ak-gwe-r7"); 3teleprobe_meta::target!(b"ak-gwe-r7");
5teleprobe_meta::timeout!(120); 4teleprobe_meta::timeout!(120);
6 5
@@ -14,7 +13,7 @@ use embassy_nrf::spim::{self, Spim};
14use embassy_nrf::{bind_interrupts, peripherals}; 13use embassy_nrf::{bind_interrupts, peripherals};
15use embassy_time::Delay; 14use embassy_time::Delay;
16use embedded_hal_bus::spi::ExclusiveDevice; 15use embedded_hal_bus::spi::ExclusiveDevice;
17use static_cell::make_static; 16use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
20bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
@@ -68,11 +67,13 @@ async fn main(spawner: Spawner) {
68 let seed = u64::from_le_bytes(seed); 67 let seed = u64::from_le_bytes(seed);
69 68
70 // Init network stack 69 // Init network stack
71 let stack = &*make_static!(Stack::new( 70 static STACK: StaticCell<Stack<MyDriver>> = StaticCell::new();
71 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
72 let stack = &*STACK.init(Stack::new(
72 device, 73 device,
73 config, 74 config,
74 make_static!(StackResources::<2>::new()), 75 RESOURCES.init(StackResources::<2>::new()),
75 seed 76 seed,
76 )); 77 ));
77 78
78 unwrap!(spawner.spawn(net_task(stack))); 79 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
index 9eee39ccf..c96064f84 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"nrf52840-dk"); 3teleprobe_meta::target!(b"nrf52840-dk");
5teleprobe_meta::timeout!(120); 4teleprobe_meta::timeout!(120);
6 5
@@ -13,7 +12,7 @@ use embassy_nrf::spim::{self, Spim};
13use embassy_nrf::{bind_interrupts, peripherals}; 12use embassy_nrf::{bind_interrupts, peripherals};
14use embassy_time::Delay; 13use embassy_time::Delay;
15use embedded_hal_bus::spi::ExclusiveDevice; 14use embedded_hal_bus::spi::ExclusiveDevice;
16use static_cell::make_static; 15use static_cell::StaticCell;
17use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; 16use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
18 17
19bind_interrupts!(struct Irqs { 18bind_interrupts!(struct Irqs {
@@ -64,8 +63,9 @@ async fn main(spawner: Spawner) {
64 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); 63 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
65 let spi = ExclusiveDevice::new(spi, cs, Delay); 64 let spi = ExclusiveDevice::new(spi, cs, Delay);
66 65
66 static STATE: StaticCell<embassy_net_esp_hosted::State> = StaticCell::new();
67 let (device, mut control, runner) = embassy_net_esp_hosted::new( 67 let (device, mut control, runner) = embassy_net_esp_hosted::new(
68 make_static!(embassy_net_esp_hosted::State::new()), 68 STATE.init(embassy_net_esp_hosted::State::new()),
69 spi, 69 spi,
70 handshake, 70 handshake,
71 ready, 71 ready,
@@ -85,11 +85,13 @@ async fn main(spawner: Spawner) {
85 let seed = u64::from_le_bytes(seed); 85 let seed = u64::from_le_bytes(seed);
86 86
87 // Init network stack 87 // Init network stack
88 let stack = &*make_static!(Stack::new( 88 static STACK: StaticCell<Stack<MyDriver>> = StaticCell::new();
89 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
90 let stack = &*STACK.init(Stack::new(
89 device, 91 device,
90 Config::dhcpv4(Default::default()), 92 Config::dhcpv4(Default::default()),
91 make_static!(StackResources::<2>::new()), 93 RESOURCES.init(StackResources::<2>::new()),
92 seed 94 seed,
93 )); 95 ));
94 96
95 unwrap!(spawner.spawn(net_task(stack))); 97 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 44fb7bed6..c38aa8004 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -24,14 +24,14 @@ defmt-rtt = "0.4"
24cortex-m = { version = "0.7.6" } 24cortex-m = { version = "0.7.6" }
25cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
26embedded-hal = "0.2.6" 26embedded-hal = "0.2.6"
27embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 27embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
28embedded-hal-async = { version = "=1.0.0-rc.2" } 28embedded-hal-async = { version = "=1.0.0-rc.3" }
29embedded-hal-bus = { version = "=0.1.0-rc.2", features = ["async"] } 29embedded-hal-bus = { version = "=0.1.0-rc.3", features = ["async"] }
30panic-probe = { version = "0.3.0", features = ["print-defmt"] } 30panic-probe = { version = "0.3.0", features = ["print-defmt"] }
31futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 31futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
32embedded-io-async = { version = "0.6.1" } 32embedded-io-async = { version = "0.6.1" }
33embedded-storage = { version = "0.3" } 33embedded-storage = { version = "0.3" }
34static_cell = { version = "2", features = ["nightly"]} 34static_cell = "2"
35portable-atomic = { version = "1.5", features = ["critical-section"] } 35portable-atomic = { version = "1.5", features = ["critical-section"] }
36pio = "0.2" 36pio = "0.2"
37pio-proc = "0.2" 37pio-proc = "0.2"
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index de29c06dd..a1b2946e6 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"rpi-pico"); 3teleprobe_meta::target!(b"rpi-pico");
5 4
6use cyw43_pio::PioSpi; 5use cyw43_pio::PioSpi;
@@ -11,7 +10,7 @@ use embassy_rp::gpio::{Level, Output};
11use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 10use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
12use embassy_rp::pio::{InterruptHandler, Pio}; 11use embassy_rp::pio::{InterruptHandler, Pio};
13use embassy_rp::{bind_interrupts, rom_data}; 12use embassy_rp::{bind_interrupts, rom_data};
14use static_cell::make_static; 13use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
16 15
17bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
@@ -58,7 +57,8 @@ async fn main(spawner: Spawner) {
58 let mut pio = Pio::new(p.PIO0, Irqs); 57 let mut pio = Pio::new(p.PIO0, Irqs);
59 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); 58 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
60 59
61 let state = make_static!(cyw43::State::new()); 60 static STATE: StaticCell<cyw43::State> = StaticCell::new();
61 let state = STATE.init(cyw43::State::new());
62 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 62 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
63 unwrap!(spawner.spawn(wifi_task(runner))); 63 unwrap!(spawner.spawn(wifi_task(runner)));
64 64
@@ -71,11 +71,13 @@ async fn main(spawner: Spawner) {
71 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. 71 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
72 72
73 // Init network stack 73 // Init network stack
74 let stack = &*make_static!(Stack::new( 74 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
75 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
76 let stack = &*STACK.init(Stack::new(
75 net_device, 77 net_device,
76 Config::dhcpv4(Default::default()), 78 Config::dhcpv4(Default::default()),
77 make_static!(StackResources::<2>::new()), 79 RESOURCES.init(StackResources::<2>::new()),
78 seed 80 seed,
79 )); 81 ));
80 82
81 unwrap!(spawner.spawn(net_task(stack))); 83 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs
index a4d253b3c..8c9089d0e 100644
--- a/tests/rp/src/bin/ethernet_w5100s_perf.rs
+++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"w5100s-evb-pico"); 3teleprobe_meta::target!(b"w5100s-evb-pico");
5teleprobe_meta::timeout!(120); 4teleprobe_meta::timeout!(120);
6 5
@@ -16,7 +15,7 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
16use embassy_time::Delay; 15use embassy_time::Delay;
17use embedded_hal_bus::spi::ExclusiveDevice; 16use embedded_hal_bus::spi::ExclusiveDevice;
18use rand::RngCore; 17use rand::RngCore;
19use static_cell::make_static; 18use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
21 20
22#[embassy_executor::task] 21#[embassy_executor::task]
@@ -51,7 +50,8 @@ async fn main(spawner: Spawner) {
51 let w5500_reset = Output::new(p.PIN_20, Level::High); 50 let w5500_reset = Output::new(p.PIN_20, Level::High);
52 51
53 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 52 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
54 let state = make_static!(State::<8, 8>::new()); 53 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
54 let state = STATE.init(State::<8, 8>::new());
55 let (device, runner) = embassy_net_wiznet::new( 55 let (device, runner) = embassy_net_wiznet::new(
56 mac_addr, 56 mac_addr,
57 state, 57 state,
@@ -66,11 +66,13 @@ async fn main(spawner: Spawner) {
66 let seed = rng.next_u64(); 66 let seed = rng.next_u64();
67 67
68 // Init network stack 68 // Init network stack
69 let stack = &*make_static!(Stack::new( 69 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
70 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
71 let stack = &*STACK.init(Stack::new(
70 device, 72 device,
71 embassy_net::Config::dhcpv4(Default::default()), 73 embassy_net::Config::dhcpv4(Default::default()),
72 make_static!(StackResources::<2>::new()), 74 RESOURCES.init(StackResources::<2>::new()),
73 seed 75 seed,
74 )); 76 ));
75 77
76 // Launch network task 78 // Launch network task
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs
index e0c309887..a57d5d9e8 100644
--- a/tests/rp/src/bin/gpio.rs
+++ b/tests/rp/src/bin/gpio.rs
@@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) {
16 16
17 // Test initial output 17 // Test initial output
18 { 18 {
19 let b = Input::new(&mut b, Pull::None); 19 let mut b = Input::new(&mut b, Pull::None);
20 20
21 { 21 {
22 let a = Output::new(&mut a, Level::Low); 22 let mut a = Output::new(&mut a, Level::Low);
23 delay(); 23 delay();
24 assert!(b.is_low()); 24 assert!(b.is_low());
25 assert!(!b.is_high()); 25 assert!(!b.is_high());
@@ -64,7 +64,7 @@ async fn main(_spawner: Spawner) {
64 64
65 // Test input no pull 65 // Test input no pull
66 { 66 {
67 let b = Input::new(&mut b, Pull::None); 67 let mut b = Input::new(&mut b, Pull::None);
68 // no pull, the status is undefined 68 // no pull, the status is undefined
69 69
70 let mut a = Output::new(&mut a, Level::Low); 70 let mut a = Output::new(&mut a, Level::Low);
@@ -77,7 +77,7 @@ async fn main(_spawner: Spawner) {
77 77
78 // Test input pulldown 78 // Test input pulldown
79 { 79 {
80 let b = Input::new(&mut b, Pull::Down); 80 let mut b = Input::new(&mut b, Pull::Down);
81 delay(); 81 delay();
82 assert!(b.is_low()); 82 assert!(b.is_low());
83 83
@@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) {
91 91
92 // Test input pullup 92 // Test input pullup
93 { 93 {
94 let b = Input::new(&mut b, Pull::Up); 94 let mut b = Input::new(&mut b, Pull::Up);
95 delay(); 95 delay();
96 assert!(b.is_high()); 96 assert!(b.is_high());
97 97
diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs
index e71d9e610..3fc0bb2a0 100644
--- a/tests/rp/src/bin/pwm.rs
+++ b/tests/rp/src/bin/pwm.rs
@@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) {
45 45
46 // Test output from A 46 // Test output from A
47 { 47 {
48 let pin1 = Input::new(&mut p9, Pull::None); 48 let mut pin1 = Input::new(&mut p9, Pull::None);
49 let _pwm = Pwm::new_output_a(&mut p.PWM_CH3, &mut p6, cfg.clone()); 49 let _pwm = Pwm::new_output_a(&mut p.PWM_CH3, &mut p6, cfg.clone());
50 Timer::after_millis(1).await; 50 Timer::after_millis(1).await;
51 assert_eq!(pin1.is_low(), invert_a); 51 assert_eq!(pin1.is_low(), invert_a);
@@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) {
59 59
60 // Test output from B 60 // Test output from B
61 { 61 {
62 let pin2 = Input::new(&mut p11, Pull::None); 62 let mut pin2 = Input::new(&mut p11, Pull::None);
63 let _pwm = Pwm::new_output_b(&mut p.PWM_CH3, &mut p7, cfg.clone()); 63 let _pwm = Pwm::new_output_b(&mut p.PWM_CH3, &mut p7, cfg.clone());
64 Timer::after_millis(1).await; 64 Timer::after_millis(1).await;
65 assert_ne!(pin2.is_low(), invert_a); 65 assert_ne!(pin2.is_low(), invert_a);
@@ -73,8 +73,8 @@ async fn main(_spawner: Spawner) {
73 73
74 // Test output from A+B 74 // Test output from A+B
75 { 75 {
76 let pin1 = Input::new(&mut p9, Pull::None); 76 let mut pin1 = Input::new(&mut p9, Pull::None);
77 let pin2 = Input::new(&mut p11, Pull::None); 77 let mut pin2 = Input::new(&mut p11, Pull::None);
78 let _pwm = Pwm::new_output_ab(&mut p.PWM_CH3, &mut p6, &mut p7, cfg.clone()); 78 let _pwm = Pwm::new_output_ab(&mut p.PWM_CH3, &mut p6, &mut p7, cfg.clone());
79 Timer::after_millis(1).await; 79 Timer::after_millis(1).await;
80 assert_eq!(pin1.is_low(), invert_a); 80 assert_eq!(pin1.is_low(), invert_a);
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 4f53e84f0..c60b28a7a 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -63,13 +63,13 @@ defmt-rtt = "0.4"
63cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 63cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
64cortex-m-rt = "0.7.0" 64cortex-m-rt = "0.7.0"
65embedded-hal = "0.2.6" 65embedded-hal = "0.2.6"
66embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" } 66embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.3" }
67embedded-hal-async = { version = "=1.0.0-rc.2" } 67embedded-hal-async = { version = "=1.0.0-rc.3" }
68micromath = "2.0.0" 68micromath = "2.0.0"
69panic-probe = { version = "0.3.0", features = ["print-defmt"] } 69panic-probe = { version = "0.3.0", features = ["print-defmt"] }
70rand_core = { version = "0.6", default-features = false } 70rand_core = { version = "0.6", default-features = false }
71rand_chacha = { version = "0.3", default-features = false } 71rand_chacha = { version = "0.3", default-features = false }
72static_cell = { version = "2", features = ["nightly"] } 72static_cell = "2"
73portable-atomic = { version = "1.5", features = [] } 73portable-atomic = { version = "1.5", features = [] }
74 74
75chrono = { version = "^0.4", default-features = false, optional = true} 75chrono = { version = "^0.4", default-features = false, optional = true}
diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs
index 754354944..7c02f0354 100644
--- a/tests/stm32/src/bin/eth.rs
+++ b/tests/stm32/src/bin/eth.rs
@@ -1,7 +1,6 @@
1// required-features: eth 1// required-features: eth
2#![no_std] 2#![no_std]
3#![no_main] 3#![no_main]
4#![feature(type_alias_impl_trait)]
5 4
6#[path = "../common.rs"] 5#[path = "../common.rs"]
7mod common; 6mod common;
@@ -14,7 +13,7 @@ use embassy_stm32::peripherals::ETH;
14use embassy_stm32::rng::Rng; 13use embassy_stm32::rng::Rng;
15use embassy_stm32::{bind_interrupts, eth, peripherals, rng}; 14use embassy_stm32::{bind_interrupts, eth, peripherals, rng};
16use rand_core::RngCore; 15use rand_core::RngCore;
17use static_cell::make_static; 16use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
20teleprobe_meta::timeout!(120); 19teleprobe_meta::timeout!(120);
@@ -71,8 +70,9 @@ async fn main(spawner: Spawner) {
71 #[cfg(not(feature = "stm32f207zg"))] 70 #[cfg(not(feature = "stm32f207zg"))]
72 const PACKET_QUEUE_SIZE: usize = 4; 71 const PACKET_QUEUE_SIZE: usize = 4;
73 72
73 static PACKETS: StaticCell<PacketQueue<PACKET_QUEUE_SIZE, PACKET_QUEUE_SIZE>> = StaticCell::new();
74 let device = Ethernet::new( 74 let device = Ethernet::new(
75 make_static!(PacketQueue::<PACKET_QUEUE_SIZE, PACKET_QUEUE_SIZE>::new()), 75 PACKETS.init(PacketQueue::<PACKET_QUEUE_SIZE, PACKET_QUEUE_SIZE>::new()),
76 p.ETH, 76 p.ETH,
77 Irqs, 77 Irqs,
78 p.PA1, 78 p.PA1,
@@ -99,11 +99,13 @@ async fn main(spawner: Spawner) {
99 //}); 99 //});
100 100
101 // Init network stack 101 // Init network stack
102 let stack = &*make_static!(Stack::new( 102 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
103 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
104 let stack = &*STACK.init(Stack::new(
103 device, 105 device,
104 config, 106 config,
105 make_static!(StackResources::<2>::new()), 107 RESOURCES.init(StackResources::<2>::new()),
106 seed 108 seed,
107 )); 109 ));
108 110
109 // Launch network task 111 // Launch network task
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index c4e2fe161..9f1993024 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -20,10 +20,10 @@ async fn main(_spawner: Spawner) {
20 20
21 // Test initial output 21 // Test initial output
22 { 22 {
23 let b = Input::new(&mut b, Pull::None); 23 let mut b = Input::new(&mut b, Pull::None);
24 24
25 { 25 {
26 let a = Output::new(&mut a, Level::Low, Speed::Low); 26 let mut a = Output::new(&mut a, Level::Low, Speed::Low);
27 delay(); 27 delay();
28 assert!(b.is_low()); 28 assert!(b.is_low());
29 assert!(!b.is_high()); 29 assert!(!b.is_high());
@@ -68,7 +68,7 @@ async fn main(_spawner: Spawner) {
68 68
69 // Test input no pull 69 // Test input no pull
70 { 70 {
71 let b = Input::new(&mut b, Pull::None); 71 let mut b = Input::new(&mut b, Pull::None);
72 // no pull, the status is undefined 72 // no pull, the status is undefined
73 73
74 let mut a = Output::new(&mut a, Level::Low, Speed::Low); 74 let mut a = Output::new(&mut a, Level::Low, Speed::Low);
@@ -81,7 +81,7 @@ async fn main(_spawner: Spawner) {
81 81
82 // Test input pulldown 82 // Test input pulldown
83 { 83 {
84 let b = Input::new(&mut b, Pull::Down); 84 let mut b = Input::new(&mut b, Pull::Down);
85 delay(); 85 delay();
86 assert!(b.is_low()); 86 assert!(b.is_low());
87 87
@@ -95,7 +95,7 @@ async fn main(_spawner: Spawner) {
95 95
96 // Test input pullup 96 // Test input pullup
97 { 97 {
98 let b = Input::new(&mut b, Pull::Up); 98 let mut b = Input::new(&mut b, Pull::Up);
99 delay(); 99 delay();
100 assert!(b.is_high()); 100 assert!(b.is_high());
101 101
@@ -109,7 +109,7 @@ async fn main(_spawner: Spawner) {
109 109
110 // Test output open drain 110 // Test output open drain
111 { 111 {
112 let b = Input::new(&mut b, Pull::Down); 112 let mut b = Input::new(&mut b, Pull::Down);
113 // no pull, the status is undefined 113 // no pull, the status is undefined
114 114
115 let mut a = OutputOpenDrain::new(&mut a, Level::Low, Speed::Low, Pull::None); 115 let mut a = OutputOpenDrain::new(&mut a, Level::Low, Speed::Low, Pull::None);
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs
index b9810673a..000296d46 100644
--- a/tests/stm32/src/bin/stop.rs
+++ b/tests/stm32/src/bin/stop.rs
@@ -2,7 +2,6 @@
2 2
3#![no_std] 3#![no_std]
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"] 5#[path = "../common.rs"]
7mod common; 6mod common;
8 7
@@ -15,7 +14,7 @@ use embassy_stm32::rcc::LsConfig;
15use embassy_stm32::rtc::{Rtc, RtcConfig}; 14use embassy_stm32::rtc::{Rtc, RtcConfig};
16use embassy_stm32::Config; 15use embassy_stm32::Config;
17use embassy_time::Timer; 16use embassy_time::Timer;
18use static_cell::make_static; 17use static_cell::StaticCell;
19 18
20#[entry] 19#[entry]
21fn main() -> ! { 20fn main() -> ! {
@@ -64,7 +63,8 @@ async fn async_main(spawner: Spawner) {
64 63
65 rtc.set_datetime(now.into()).expect("datetime not set"); 64 rtc.set_datetime(now.into()).expect("datetime not set");
66 65
67 let rtc = make_static!(rtc); 66 static RTC: StaticCell<Rtc> = StaticCell::new();
67 let rtc = RTC.init(rtc);
68 68
69 stop_with_rtc(rtc); 69 stop_with_rtc(rtc);
70 70