aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarun Koppula <[email protected]>2024-03-07 15:20:29 -0500
committerGitHub <[email protected]>2024-03-07 15:20:29 -0500
commit54751b7a5093b7960e42cee1bc9a850f9c4b7a8f (patch)
treedf08df503f2b441c5b62306d50532403fe4c19c9
parent3b1d87050e2a30b598e92979b6f202b67664a29c (diff)
parentb2d236ee390081ec6aeef1a27da06098f9febbf9 (diff)
Merge branch 'main' into karun/main_octospi_implementation
-rw-r--r--.gitattributes4
-rwxr-xr-x.github/ci/doc.sh3
-rw-r--r--README.md2
-rwxr-xr-xci-nightly.sh3
-rwxr-xr-xci.sh74
-rw-r--r--cyw43-pio/src/lib.rs14
-rw-r--r--cyw43/Cargo.toml4
-rw-r--r--cyw43/src/control.rs89
-rw-r--r--cyw43/src/events.rs4
-rw-r--r--cyw43/src/runner.rs8
-rw-r--r--cyw43/src/structs.rs38
-rw-r--r--docs/modules/ROOT/examples/basic/src/main.rs3
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-async/src/main.rs4
-rw-r--r--docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs13
-rw-r--r--docs/modules/ROOT/pages/basic_application.adoc15
-rw-r--r--docs/modules/ROOT/pages/best_practices.adoc6
-rw-r--r--docs/modules/ROOT/pages/embassy_in_the_wild.adoc2
-rw-r--r--docs/modules/ROOT/pages/faq.adoc40
-rw-r--r--docs/modules/ROOT/pages/getting_started.adoc31
-rw-r--r--docs/modules/ROOT/pages/new_project.adoc25
-rw-r--r--docs/modules/ROOT/pages/project_structure.adoc9
-rw-r--r--embassy-boot-nrf/src/lib.rs17
-rw-r--r--embassy-boot-rp/src/lib.rs15
-rw-r--r--embassy-boot-stm32/src/lib.rs15
-rw-r--r--embassy-boot/src/boot_loader.rs53
-rw-r--r--embassy-boot/src/firmware_updater/asynch.rs171
-rw-r--r--embassy-boot/src/firmware_updater/blocking.rs187
-rw-r--r--embassy-boot/src/firmware_updater/mod.rs2
-rw-r--r--embassy-executor-macros/src/lib.rs7
-rw-r--r--embassy-executor-macros/src/macros/main.rs14
-rw-r--r--embassy-executor/Cargo.toml14
-rw-r--r--embassy-executor/src/arch/avr.rs72
-rw-r--r--embassy-executor/src/arch/riscv32.rs2
-rw-r--r--embassy-executor/src/lib.rs3
-rw-r--r--embassy-executor/src/raw/mod.rs12
-rw-r--r--embassy-hal-internal/src/atomic_ring_buffer.rs33
-rw-r--r--embassy-hal-internal/src/peripheral.rs11
-rw-r--r--embassy-net/Cargo.toml4
-rw-r--r--embassy-net/src/tcp.rs14
-rw-r--r--embassy-nrf/Cargo.toml9
-rw-r--r--embassy-nrf/README.md3
-rw-r--r--embassy-nrf/src/buffered_uarte.rs755
-rw-r--r--embassy-nrf/src/chips/nrf51.rs174
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs5
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs5
-rw-r--r--embassy-nrf/src/gpio.rs74
-rw-r--r--embassy-nrf/src/gpiote.rs111
-rw-r--r--embassy-nrf/src/lib.rs28
-rw-r--r--embassy-nrf/src/nvmc.rs2
-rw-r--r--embassy-nrf/src/pdm.rs57
-rw-r--r--embassy-nrf/src/ppi/mod.rs1
-rw-r--r--embassy-nrf/src/ppi/ppi.rs5
-rw-r--r--embassy-nrf/src/pwm.rs30
-rw-r--r--embassy-nrf/src/qdec.rs7
-rwxr-xr-xembassy-nrf/src/qspi.rs8
-rw-r--r--embassy-nrf/src/radio/ble.rs417
-rw-r--r--embassy-nrf/src/radio/ieee802154.rs546
-rw-r--r--embassy-nrf/src/radio/mod.rs110
-rw-r--r--embassy-nrf/src/rng.rs128
-rw-r--r--embassy-nrf/src/spim.rs148
-rw-r--r--embassy-nrf/src/spis.rs21
-rw-r--r--embassy-nrf/src/temp.rs2
-rw-r--r--embassy-nrf/src/time_driver.rs18
-rw-r--r--embassy-nrf/src/timer.rs20
-rw-r--r--embassy-nrf/src/twim.rs18
-rw-r--r--embassy-nrf/src/twis.rs2
-rw-r--r--embassy-nrf/src/uarte.rs238
-rw-r--r--embassy-nrf/src/util.rs15
-rw-r--r--embassy-rp/src/gpio.rs138
-rw-r--r--embassy-rp/src/i2c.rs84
-rw-r--r--embassy-rp/src/i2c_slave.rs272
-rw-r--r--embassy-rp/src/uart/mod.rs222
-rw-r--r--embassy-stm32-wpan/Cargo.toml2
-rw-r--r--embassy-stm32-wpan/build.rs17
-rw-r--r--embassy-stm32-wpan/tl_mbox_extended_wb1.x.in16
-rw-r--r--embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in16
-rw-r--r--embassy-stm32/Cargo.toml28
-rw-r--r--embassy-stm32/build.rs599
-rw-r--r--embassy-stm32/src/adc/f1.rs21
-rw-r--r--embassy-stm32/src/adc/f3.rs18
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs51
-rw-r--r--embassy-stm32/src/adc/mod.rs67
-rw-r--r--embassy-stm32/src/adc/resolution.rs72
-rw-r--r--embassy-stm32/src/adc/sample_time.rs148
-rw-r--r--embassy-stm32/src/adc/v1.rs25
-rw-r--r--embassy-stm32/src/adc/v2.rs8
-rw-r--r--embassy-stm32/src/adc/v3.rs125
-rw-r--r--embassy-stm32/src/adc/v4.rs2
-rw-r--r--embassy-stm32/src/can/bxcan.rs124
-rw-r--r--embassy-stm32/src/can/enums.rs30
-rw-r--r--embassy-stm32/src/can/fd/config.rs475
-rw-r--r--embassy-stm32/src/can/fd/filter.rs379
-rw-r--r--embassy-stm32/src/can/fd/message_ram/common.rs134
-rw-r--r--embassy-stm32/src/can/fd/message_ram/enums.rs233
-rw-r--r--embassy-stm32/src/can/fd/message_ram/extended_filter.rs136
-rw-r--r--embassy-stm32/src/can/fd/message_ram/generic.rs168
-rw-r--r--embassy-stm32/src/can/fd/message_ram/mod.rs170
-rw-r--r--embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs122
-rw-r--r--embassy-stm32/src/can/fd/message_ram/standard_filter.rs136
-rw-r--r--embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs433
-rw-r--r--embassy-stm32/src/can/fd/message_ram/txevent_element.rs138
-rw-r--r--embassy-stm32/src/can/fd/mod.rs6
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs788
-rw-r--r--embassy-stm32/src/can/fdcan.rs933
-rw-r--r--embassy-stm32/src/can/frame.rs398
-rw-r--r--embassy-stm32/src/can/util.rs117
-rw-r--r--embassy-stm32/src/cryp/mod.rs1356
-rw-r--r--embassy-stm32/src/dac/mod.rs23
-rw-r--r--embassy-stm32/src/dcmi.rs122
-rw-r--r--embassy-stm32/src/dma/bdma.rs733
-rw-r--r--embassy-stm32/src/dma/dma.rs1005
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs913
-rw-r--r--embassy-stm32/src/dma/dmamux.rs34
-rw-r--r--embassy-stm32/src/dma/gpdma.rs170
-rw-r--r--embassy-stm32/src/dma/mod.rs111
-rw-r--r--embassy-stm32/src/dma/ringbuffer.rs12
-rw-r--r--embassy-stm32/src/eth/mod.rs10
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs4
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs138
-rw-r--r--embassy-stm32/src/exti.rs45
-rw-r--r--embassy-stm32/src/flash/h50.rs124
-rw-r--r--embassy-stm32/src/flash/h7.rs8
-rw-r--r--embassy-stm32/src/flash/mod.rs4
-rw-r--r--embassy-stm32/src/flash/u5.rs105
-rw-r--r--embassy-stm32/src/fmc.rs8
-rw-r--r--embassy-stm32/src/gpio.rs143
-rw-r--r--embassy-stm32/src/hash/mod.rs592
-rw-r--r--embassy-stm32/src/hrtim/mod.rs4
-rw-r--r--embassy-stm32/src/hrtim/traits.rs16
-rw-r--r--embassy-stm32/src/i2s.rs25
-rw-r--r--embassy-stm32/src/ipcc.rs19
-rw-r--r--embassy-stm32/src/lib.rs9
-rw-r--r--embassy-stm32/src/opamp.rs2
-rw-r--r--embassy-stm32/src/rcc/bd.rs19
-rw-r--r--embassy-stm32/src/rcc/c0.rs231
-rw-r--r--embassy-stm32/src/rcc/f0.rs172
-rw-r--r--embassy-stm32/src/rcc/f013.rs456
-rw-r--r--embassy-stm32/src/rcc/f1.rs192
-rw-r--r--embassy-stm32/src/rcc/f247.rs (renamed from embassy-stm32/src/rcc/f.rs)68
-rw-r--r--embassy-stm32/src/rcc/f3.rs459
-rw-r--r--embassy-stm32/src/rcc/g0.rs537
-rw-r--r--embassy-stm32/src/rcc/g4.rs476
-rw-r--r--embassy-stm32/src/rcc/h.rs154
-rw-r--r--embassy-stm32/src/rcc/l.rs162
-rw-r--r--embassy-stm32/src/rcc/mco.rs24
-rw-r--r--embassy-stm32/src/rcc/mod.rs180
-rw-r--r--embassy-stm32/src/rcc/u5.rs643
-rw-r--r--embassy-stm32/src/rcc/wba.rs216
-rw-r--r--embassy-stm32/src/sai/mod.rs107
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs79
-rw-r--r--embassy-stm32/src/spi/mod.rs30
-rw-r--r--embassy-stm32/src/time_driver.rs110
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs20
-rw-r--r--embassy-stm32/src/timer/mod.rs715
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs105
-rw-r--r--embassy-stm32/src/usart/buffered.rs79
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs22
-rw-r--r--embassy-stm32/src/usb/usb.rs4
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs14
-rw-r--r--embassy-stm32/src/wdg/mod.rs6
-rw-r--r--embassy-sync/src/channel.rs22
-rw-r--r--embassy-sync/src/priority_channel.rs2
-rw-r--r--embassy-sync/src/ring_buffer.rs22
-rw-r--r--embassy-sync/src/zerocopy_channel.rs7
-rw-r--r--embassy-time/src/delay.rs1
-rw-r--r--embassy-time/src/lib.rs2
-rw-r--r--embassy-time/src/timer.rs15
-rw-r--r--embassy-usb-dfu/Cargo.toml14
-rw-r--r--embassy-usb-logger/src/lib.rs84
-rw-r--r--embassy-usb/Cargo.toml2
-rw-r--r--embassy-usb/README.md2
-rw-r--r--examples/boot/.cargo/config.toml4
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs2
-rw-r--r--examples/boot/application/rp/.cargo/config.toml4
-rw-r--r--examples/boot/application/rp/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f3/memory.x4
-rw-r--r--examples/boot/application/stm32f3/src/bin/a.rs7
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs7
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs7
-rw-r--r--examples/boot/application/stm32l0/memory.x4
-rw-r--r--examples/boot/application/stm32l0/src/bin/a.rs7
-rw-r--r--examples/boot/application/stm32l1/memory.x4
-rw-r--r--examples/boot/application/stm32l1/src/bin/a.rs7
-rw-r--r--examples/boot/application/stm32l4/memory.x4
-rw-r--r--examples/boot/application/stm32l4/src/bin/a.rs7
-rw-r--r--examples/boot/application/stm32wb-dfu/README.md24
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs2
-rw-r--r--examples/boot/application/stm32wl/memory.x4
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs7
-rw-r--r--examples/boot/bootloader/nrf/.cargo/config.toml6
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs2
-rw-r--r--examples/boot/bootloader/rp/src/main.rs2
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/Cargo.toml57
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/README.md44
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/build.rs27
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/memory.x18
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/src/main.rs53
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/README.md2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs4
-rw-r--r--examples/nrf51/.cargo/config.toml9
-rw-r--r--examples/nrf51/Cargo.toml20
-rw-r--r--examples/nrf51/build.rs35
-rw-r--r--examples/nrf51/memory.x5
-rw-r--r--examples/nrf51/src/bin/blinky.rs20
-rw-r--r--examples/nrf52840/Cargo.toml2
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs12
-rw-r--r--examples/nrf52840/src/bin/gpiote_port.rs12
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs4
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs12
-rw-r--r--examples/nrf5340/Cargo.toml2
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp/src/bin/blinky_two_tasks.rs2
-rw-r--r--examples/rp/src/bin/debounce.rs80
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs8
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs8
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs8
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs8
-rw-r--r--examples/rp/src/bin/i2c_slave.rs8
-rw-r--r--examples/rp/src/bin/multicore.rs3
-rw-r--r--examples/rp/src/bin/pio_i2s.rs125
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs7
-rw-r--r--examples/rp/src/bin/usb_hid_mouse.rs182
-rw-r--r--examples/rp/src/bin/usb_serial_with_logger.rs117
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs6
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs6
-rw-r--r--examples/rp/src/bin/wifi_scan.rs8
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs6
-rw-r--r--examples/std/README.md4
-rw-r--r--examples/stm32c0/src/bin/button_exti.rs5
-rw-r--r--examples/stm32f0/Cargo.toml2
-rw-r--r--examples/stm32f0/src/bin/adc.rs2
-rw-r--r--examples/stm32f0/src/bin/button_controlled_blink.rs5
-rw-r--r--examples/stm32f0/src/bin/button_exti.rs5
-rw-r--r--examples/stm32f1/src/bin/hello.rs4
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs20
-rw-r--r--examples/stm32f3/src/bin/button_events.rs28
-rw-r--r--examples/stm32f3/src/bin/button_exti.rs5
-rw-r--r--examples/stm32f3/src/bin/hello.rs5
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs21
-rw-r--r--examples/stm32f334/src/bin/adc.rs26
-rw-r--r--examples/stm32f334/src/bin/hello.rs5
-rw-r--r--examples/stm32f334/src/bin/opamp.rs26
-rw-r--r--examples/stm32f334/src/bin/pwm.rs26
-rw-r--r--examples/stm32f4/Cargo.toml1
-rw-r--r--examples/stm32f4/src/bin/button_exti.rs5
-rw-r--r--examples/stm32f4/src/bin/rtc.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs148
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs2
-rw-r--r--examples/stm32f7/.cargo/config.toml2
-rw-r--r--examples/stm32f7/Cargo.toml7
-rw-r--r--examples/stm32f7/src/bin/button_exti.rs5
-rw-r--r--examples/stm32f7/src/bin/cryp.rs74
-rw-r--r--examples/stm32f7/src/bin/eth.rs2
-rw-r--r--examples/stm32f7/src/bin/hash.rs78
-rw-r--r--examples/stm32g0/src/bin/button_exti.rs5
-rw-r--r--examples/stm32g0/src/bin/hf_timer.rs45
-rw-r--r--examples/stm32g0/src/bin/usb_serial.rs10
-rw-r--r--examples/stm32g4/Cargo.toml4
-rw-r--r--examples/stm32g4/src/bin/adc.rs31
-rw-r--r--examples/stm32g4/src/bin/button_exti.rs5
-rw-r--r--examples/stm32g4/src/bin/can.rs229
-rw-r--r--examples/stm32g4/src/bin/pll.rs28
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs43
-rw-r--r--examples/stm32h5/src/bin/button_exti.rs5
-rw-r--r--examples/stm32h5/src/bin/can.rs96
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs7
-rw-r--r--examples/stm32h7/src/bin/adc.rs4
-rw-r--r--examples/stm32h7/src/bin/button_exti.rs5
-rw-r--r--examples/stm32h7/src/bin/can.rs96
-rw-r--r--examples/stm32h7/src/bin/dac.rs2
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs16
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs1
-rw-r--r--examples/stm32h7/src/bin/eth_client_mii.rs142
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs4
-rw-r--r--examples/stm32h7/src/bin/rtc.rs4
-rw-r--r--examples/stm32l0/src/bin/adc.rs40
-rw-r--r--examples/stm32l0/src/bin/button_exti.rs5
-rw-r--r--examples/stm32l1/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32l4/src/bin/adc.rs16
-rw-r--r--examples/stm32l4/src/bin/button_exti.rs5
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs14
-rw-r--r--examples/stm32l4/src/bin/rng.rs4
-rw-r--r--examples/stm32l4/src/bin/rtc.rs6
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs15
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32l5/Cargo.toml2
-rw-r--r--examples/stm32l5/src/bin/button_exti.rs5
-rw-r--r--examples/stm32l5/src/bin/rng.rs4
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs2
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs2
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32u5/src/bin/flash.rs55
-rw-r--r--examples/stm32u5/src/bin/i2c.rs41
-rw-r--r--examples/stm32u5/src/bin/rng.rs25
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs27
-rw-r--r--examples/stm32wb/src/bin/button_exti.rs5
-rw-r--r--examples/stm32wba/src/bin/button_exti.rs5
-rw-r--r--examples/stm32wl/src/bin/button_exti.rs5
-rw-r--r--examples/stm32wl/src/bin/random.rs2
-rw-r--r--examples/stm32wl/src/bin/rtc.rs6
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs2
-rw-r--r--tests/nrf/src/bin/buffered_uart.rs78
-rw-r--r--tests/nrf51422/.cargo/config.toml9
-rw-r--r--tests/nrf51422/Cargo.toml23
-rw-r--r--tests/nrf51422/build.rs17
-rw-r--r--tests/nrf51422/memory.x5
-rw-r--r--tests/nrf51422/src/bin/gpio.rs28
-rw-r--r--tests/nrf51422/src/bin/gpiote.rs47
-rw-r--r--tests/nrf51422/src/bin/timer.rs24
-rw-r--r--tests/nrf52840/.cargo/config.toml (renamed from tests/nrf/.cargo/config.toml)0
-rw-r--r--tests/nrf52840/Cargo.toml (renamed from tests/nrf/Cargo.toml)0
-rw-r--r--tests/nrf52840/build.rs (renamed from tests/nrf/build.rs)0
-rw-r--r--tests/nrf52840/memory.x (renamed from tests/nrf/memory.x)0
-rw-r--r--tests/nrf52840/src/bin/buffered_uart.rs81
-rw-r--r--tests/nrf52840/src/bin/buffered_uart_full.rs (renamed from tests/nrf/src/bin/buffered_uart_full.rs)2
-rw-r--r--tests/nrf52840/src/bin/buffered_uart_halves.rs82
-rw-r--r--tests/nrf52840/src/bin/buffered_uart_spam.rs (renamed from tests/nrf/src/bin/buffered_uart_spam.rs)0
-rw-r--r--tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs (renamed from tests/nrf/src/bin/ethernet_enc28j60_perf.rs)5
-rw-r--r--tests/nrf52840/src/bin/timer.rs (renamed from tests/nrf/src/bin/timer.rs)1
-rw-r--r--tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs (renamed from tests/nrf/src/bin/wifi_esp_hosted_perf.rs)12
-rw-r--r--tests/rp/.cargo/config.toml2
-rw-r--r--tests/rp/Cargo.toml1
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs6
-rw-r--r--tests/rp/src/bin/ethernet_w5100s_perf.rs8
-rw-r--r--tests/rp/src/bin/i2c.rs96
-rw-r--r--tests/rp/src/bin/uart.rs6
-rw-r--r--tests/rp/src/bin/uart_buffered.rs6
-rw-r--r--tests/rp/src/bin/uart_dma.rs6
-rw-r--r--tests/stm32/.cargo/config.toml12
-rw-r--r--tests/stm32/Cargo.toml44
-rw-r--r--tests/stm32/build.rs3
-rw-r--r--tests/stm32/src/bin/cryp.rs69
-rw-r--r--tests/stm32/src/bin/fdcan.rs190
-rw-r--r--tests/stm32/src/bin/hash.rs101
-rw-r--r--tests/stm32/src/bin/usart_rx_ringbuffered.rs2
-rw-r--r--tests/stm32/src/common.rs184
-rwxr-xr-xtests/stm32/teleprobe.sh12
346 files changed, 18535 insertions, 7331 deletions
diff --git a/.gitattributes b/.gitattributes
index 4db9edae7..a51376f0d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -15,6 +15,8 @@
15*.x text 15*.x text
16*.yml text 16*.yml text
17 17
18.vscode/*.json linguist-language=JSON-with-Comments
19
18*.raw binary 20*.raw binary
19*.bin binary 21*.bin binary
20*.png binary 22*.png binary
@@ -38,4 +40,4 @@
38*.pdf binary 40*.pdf binary
39*.ez binary 41*.ez binary
40*.bz2 binary 42*.bz2 binary
41*.swp binary \ No newline at end of file 43*.swp binary
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 70833f934..7112d8aaa 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -1,7 +1,7 @@
1#!/bin/bash 1#!/bin/bash
2## on push branch=main 2## on push branch=main
3 3
4set -euo pipefail 4set -euxo pipefail
5 5
6export RUSTUP_HOME=/ci/cache/rustup 6export RUSTUP_HOME=/ci/cache/rustup
7export CARGO_HOME=/ci/cache/cargo 7export CARGO_HOME=/ci/cache/cargo
@@ -35,6 +35,7 @@ docserver-builder -i ./embassy-time-driver -o webroot/crates/embassy-time-driver
35docserver-builder -i ./embassy-time-queue-driver -o webroot/crates/embassy-time-queue-driver/git.zup 35docserver-builder -i ./embassy-time-queue-driver -o webroot/crates/embassy-time-queue-driver/git.zup
36 36
37docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup 37docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup
38docserver-builder -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup
38docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup 39docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup
39docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup 40docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
40 41
diff --git a/README.md b/README.md
index 24347a43f..b6f667f75 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
2 2
3Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. 3Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries.
4 4
5## <a href="https://embassy.dev/dev/index.html">Documentation</a> - <a href="https://docs.embassy.dev/">API reference</a> - <a href="https://embassy.dev/">Website</a> - <a href="https://matrix.to/#/#embassy-rs:matrix.org">Chat</a> 5## <a href="https://embassy.dev/book/dev/index.html">Documentation</a> - <a href="https://docs.embassy.dev/">API reference</a> - <a href="https://embassy.dev/">Website</a> - <a href="https://matrix.to/#/#embassy-rs:matrix.org">Chat</a>
6## Rust + async ❤️ embedded 6## Rust + async ❤️ embedded
7 7
8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. 8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system.
diff --git a/ci-nightly.sh b/ci-nightly.sh
index 1fc9692b5..46b19c5b7 100755
--- a/ci-nightly.sh
+++ b/ci-nightly.sh
@@ -28,3 +28,6 @@ cargo batch \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ 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 \ 29 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
30 30
31cargo 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
32cargo 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
33
diff --git a/ci.sh b/ci.sh
index a1d0c8c26..cd82af2f1 100755
--- a/ci.sh
+++ b/ci.sh
@@ -15,7 +15,8 @@ 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
18cargo batch \ 18# CI intentionally does not use -eabihf on thumbv7em to minimize dep compile time.
19cargo batch \
19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \ 20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \
20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ 21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ 22 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
@@ -23,6 +24,8 @@ cargo batch \
23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ 24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \ 25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \ 26 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \
27 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers,rtos-trace \
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 arch-cortex-m,executor-thread \
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 arch-cortex-m,executor-thread,integrated-timers \
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 arch-cortex-m,executor-interrupt \
@@ -47,6 +50,7 @@ cargo batch \
47 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \ 50 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \
48 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \ 51 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \
49 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ 52 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \
53 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,gpiote,time,time-driver-rtc1 \
50 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \ 54 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \
51 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \ 55 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \
52 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time,time-driver-rtc1 \ 56 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time,time-driver-rtc1 \
@@ -67,6 +71,9 @@ cargo batch \
67 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \ 71 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \
68 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \ 72 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \
69 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \ 73 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \
74 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
75 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
76 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
70 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \ 77 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \
71 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \ 78 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \
72 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \ 79 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \
@@ -81,6 +88,16 @@ cargo batch \
81 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ 88 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \
82 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ 89 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \
83 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ 90 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \
91 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \
92 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \
93 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \
94 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030r8,defmt,exti,time-driver-any,time \
95 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f031k6,defmt,exti,time-driver-any,time \
96 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030rc,defmt,exti,time-driver-any,time \
97 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f070f6,defmt,exti,time-driver-any,time \
98 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f078vb,defmt,exti,time-driver-any,time \
99 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f042g4,defmt,exti,time-driver-any,time \
100 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \
84 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \ 101 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \
85 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any \ 102 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any \
86 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any \ 103 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any \
@@ -107,6 +124,7 @@ cargo batch \
107 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ 124 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
108 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ 125 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \
109 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ 126 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \
127 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \
110 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ 128 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
111 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ 129 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \
112 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb15cc,defmt,exti,time-driver-any,time \ 130 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb15cc,defmt,exti,time-driver-any,time \
@@ -115,20 +133,21 @@ cargo batch \
115 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l051k8,defmt,exti,time-driver-any,time \ 133 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l051k8,defmt,exti,time-driver-any,time \
116 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073cz,defmt,exti,time-driver-any,low-power,time \ 134 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073cz,defmt,exti,time-driver-any,low-power,time \
117 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \ 135 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
118 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \ 136 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \
119 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f398ve,defmt,exti,time-driver-any,time \ 137 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f398ve,defmt,exti,time-driver-any,time \
120 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \ 138 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \
121 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \ 139 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \
122 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ 140 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
123 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ 141 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,low-power,time \
124 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \ 142 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \
125 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \ 143 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \
126 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,defmt,exti,time-driver-any,time \ 144 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,defmt,exti,time-driver-any,time \
127 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \ 145 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \
128 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \ 146 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \
129 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \ 147 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \
130 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32h503rb,defmt,exti,time-driver-any,time \ 148 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb,defmt,exti,time-driver-any,time \
131 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32h562ag,defmt,exti,time-driver-any,time \ 149 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h562ag,defmt,exti,time-driver-any,time \
150 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \
132 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ 151 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
133 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ 152 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
134 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ 153 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
@@ -148,28 +167,29 @@ cargo batch \
148 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ 167 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
149 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ 168 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
150 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ 169 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
170 --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \
151 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ 171 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
152 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ 172 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
153 --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ 173 --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
154 --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \ 174 --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
155 --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \ 175 --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f3 \
156 --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f334 \ 176 --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f334 \
157 --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ 177 --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \
158 --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \ 178 --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f7 \
159 --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ 179 --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
160 --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ 180 --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
161 --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ 181 --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \
162 --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \ 182 --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \
163 --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ 183 --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
164 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ 184 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
165 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ 185 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
166 --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ 186 --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \
167 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ 187 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
168 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ 188 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
169 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ 189 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \
170 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ 190 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
171 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ 191 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \
172 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ 192 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
173 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ 193 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
174 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \ 194 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
175 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \ 195 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
@@ -178,13 +198,14 @@ cargo batch \
178 --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \ 198 --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \
179 --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \ 199 --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \
180 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \ 200 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \
181 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \ 201 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32wl \
182 --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wb-dfu \ 202 --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \
183 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 203 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
184 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 204 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
185 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ 205 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
186 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 206 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
187 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf \ 207 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \
208 --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h747xi-cm7 \
188 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ 209 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
189 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ 210 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
190 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ 211 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
@@ -196,10 +217,10 @@ cargo batch \
196 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --out-dir out/tests/stm32h753zi \ 217 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --out-dir out/tests/stm32h753zi \
197 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --out-dir out/tests/stm32h7a3zi \ 218 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --out-dir out/tests/stm32h7a3zi \
198 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \ 219 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
199 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \ 220 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h563zi --out-dir out/tests/stm32h563zi \
200 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \ 221 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u585ai --out-dir out/tests/stm32u585ai \
201 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u5a5zj --out-dir out/tests/stm32u5a5zj \ 222 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5a5zj --out-dir out/tests/stm32u5a5zj \
202 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wba52cg --out-dir out/tests/stm32wba52cg \ 223 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba52cg --out-dir out/tests/stm32wba52cg \
203 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \ 224 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \
204 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \ 225 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \
205 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \ 226 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \
@@ -210,21 +231,18 @@ cargo batch \
210 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \ 231 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \
211 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \ 232 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \
212 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ 233 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \
234 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --out-dir out/tests/stm32f091rc \
235 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --out-dir out/tests/stm32h503rb \
213 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ 236 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
214 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ 237 --- build --release --manifest-path tests/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
238 --- build --release --manifest-path tests/nrf51422/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/nrf51-dk \
215 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ 239 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
216 $BUILD_EXTRA 240 $BUILD_EXTRA
217 241
218 242
219# failed, a wire must've come loose, will check asap.
220rm out/tests/rpi-pico/i2c
221
222rm out/tests/stm32wb55rg/wpan_mac 243rm out/tests/stm32wb55rg/wpan_mac
223rm out/tests/stm32wb55rg/wpan_ble 244rm out/tests/stm32wb55rg/wpan_ble
224 245
225# not in CI yet.
226rm -rf out/tests/stm32f446re
227
228# unstable, I think it's running out of RAM? 246# unstable, I think it's running out of RAM?
229rm out/tests/stm32f207zg/eth 247rm out/tests/stm32f207zg/eth
230 248
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
index 5efab10e4..8c217b995 100644
--- a/cyw43-pio/src/lib.rs
+++ b/cyw43-pio/src/lib.rs
@@ -7,25 +7,24 @@ use core::slice;
7 7
8use cyw43::SpiBusCyw43; 8use cyw43::SpiBusCyw43;
9use embassy_rp::dma::Channel; 9use embassy_rp::dma::Channel;
10use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate}; 10use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate};
11use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; 11use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine};
12use embassy_rp::{Peripheral, PeripheralRef}; 12use embassy_rp::{Peripheral, PeripheralRef};
13use fixed::FixedU32; 13use fixed::FixedU32;
14use pio_proc::pio_asm; 14use pio_proc::pio_asm;
15 15
16/// SPI comms driven by PIO. 16/// SPI comms driven by PIO.
17pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> { 17pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA> {
18 cs: Output<'d, CS>, 18 cs: Output<'d>,
19 sm: StateMachine<'d, PIO, SM>, 19 sm: StateMachine<'d, PIO, SM>,
20 irq: Irq<'d, PIO, 0>, 20 irq: Irq<'d, PIO, 0>,
21 dma: PeripheralRef<'d, DMA>, 21 dma: PeripheralRef<'d, DMA>,
22 wrap_target: u8, 22 wrap_target: u8,
23} 23}
24 24
25impl<'d, CS, PIO, const SM: usize, DMA> PioSpi<'d, CS, PIO, SM, DMA> 25impl<'d, PIO, const SM: usize, DMA> PioSpi<'d, PIO, SM, DMA>
26where 26where
27 DMA: Channel, 27 DMA: Channel,
28 CS: Pin,
29 PIO: Instance, 28 PIO: Instance,
30{ 29{
31 /// Create a new instance of PioSpi. 30 /// Create a new instance of PioSpi.
@@ -33,7 +32,7 @@ where
33 common: &mut Common<'d, PIO>, 32 common: &mut Common<'d, PIO>,
34 mut sm: StateMachine<'d, PIO, SM>, 33 mut sm: StateMachine<'d, PIO, SM>,
35 irq: Irq<'d, PIO, 0>, 34 irq: Irq<'d, PIO, 0>,
36 cs: Output<'d, CS>, 35 cs: Output<'d>,
37 dio: DIO, 36 dio: DIO,
38 clk: CLK, 37 clk: CLK,
39 dma: impl Peripheral<P = DMA> + 'd, 38 dma: impl Peripheral<P = DMA> + 'd,
@@ -206,9 +205,8 @@ where
206 } 205 }
207} 206}
208 207
209impl<'d, CS, PIO, const SM: usize, DMA> SpiBusCyw43 for PioSpi<'d, CS, PIO, SM, DMA> 208impl<'d, PIO, const SM: usize, DMA> SpiBusCyw43 for PioSpi<'d, PIO, SM, DMA>
210where 209where
211 CS: Pin,
212 PIO: Instance, 210 PIO: Instance,
213 DMA: Channel, 211 DMA: Channel,
214{ 212{
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index c857f7378..f279739e4 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -10,7 +10,7 @@ repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/cyw43" 10documentation = "https://docs.embassy.dev/cyw43"
11 11
12[features] 12[features]
13defmt = ["dep:defmt"] 13defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt"]
14log = ["dep:log"] 14log = ["dep:log"]
15 15
16# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. 16# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`.
@@ -32,6 +32,8 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
32embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 32embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
33num_enum = { version = "0.5.7", default-features = false } 33num_enum = { version = "0.5.7", default-features = false }
34 34
35heapless = "0.8.0"
36
35[package.metadata.embassy_docs] 37[package.metadata.embassy_docs]
36src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" 38src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
37src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" 39src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 311fcb08c..135b8c245 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -3,7 +3,7 @@ use core::iter::zip;
3 3
4use embassy_net_driver_channel as ch; 4use embassy_net_driver_channel as ch;
5use embassy_net_driver_channel::driver::{HardwareAddress, LinkState}; 5use embassy_net_driver_channel::driver::{HardwareAddress, LinkState};
6use embassy_time::Timer; 6use embassy_time::{Duration, Timer};
7 7
8use crate::consts::*; 8use crate::consts::*;
9use crate::events::{Event, EventSubscriber, Events}; 9use crate::events::{Event, EventSubscriber, Events};
@@ -35,6 +35,43 @@ pub struct Control<'a> {
35 ioctl_state: &'a IoctlState, 35 ioctl_state: &'a IoctlState,
36} 36}
37 37
38#[derive(Copy, Clone)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum ScanType {
41 Active,
42 Passive,
43}
44
45#[derive(Clone)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct ScanOptions {
48 pub ssid: Option<heapless::String<32>>,
49 /// If set to `None`, all APs will be returned. If set to `Some`, only APs
50 /// with the specified BSSID will be returned.
51 pub bssid: Option<[u8; 6]>,
52 /// Number of probes to send on each channel.
53 pub nprobes: Option<u16>,
54 /// Time to spend waiting on the home channel.
55 pub home_time: Option<Duration>,
56 /// Scan type: active or passive.
57 pub scan_type: ScanType,
58 /// Period of time to wait on each channel when passive scanning.
59 pub dwell_time: Option<Duration>,
60}
61
62impl Default for ScanOptions {
63 fn default() -> Self {
64 Self {
65 ssid: None,
66 bssid: None,
67 nprobes: None,
68 home_time: None,
69 scan_type: ScanType::Passive,
70 dwell_time: None,
71 }
72 }
73}
74
38impl<'a> Control<'a> { 75impl<'a> Control<'a> {
39 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { 76 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self {
40 Self { 77 Self {
@@ -471,22 +508,54 @@ impl<'a> Control<'a> {
471 /// # Note 508 /// # Note
472 /// Device events are currently implemented using a bounded queue. 509 /// Device events are currently implemented using a bounded queue.
473 /// To not miss any events, you should make sure to always await the stream. 510 /// To not miss any events, you should make sure to always await the stream.
474 pub async fn scan(&mut self) -> Scanner<'_> { 511 pub async fn scan(&mut self, scan_opts: ScanOptions) -> Scanner<'_> {
512 const SCANTYPE_ACTIVE: u8 = 0;
475 const SCANTYPE_PASSIVE: u8 = 1; 513 const SCANTYPE_PASSIVE: u8 = 1;
476 514
515 let dwell_time = match scan_opts.dwell_time {
516 None => !0,
517 Some(t) => {
518 let mut t = t.as_millis() as u32;
519 if t == !0 {
520 t = !0 - 1;
521 }
522 t
523 }
524 };
525
526 let mut active_time = !0;
527 let mut passive_time = !0;
528 let scan_type = match scan_opts.scan_type {
529 ScanType::Active => {
530 active_time = dwell_time;
531 SCANTYPE_ACTIVE
532 }
533 ScanType::Passive => {
534 passive_time = dwell_time;
535 SCANTYPE_PASSIVE
536 }
537 };
538
477 let scan_params = ScanParams { 539 let scan_params = ScanParams {
478 version: 1, 540 version: 1,
479 action: 1, 541 action: 1,
480 sync_id: 1, 542 sync_id: 1,
481 ssid_len: 0, 543 ssid_len: scan_opts.ssid.as_ref().map(|e| e.as_bytes().len() as u32).unwrap_or(0),
482 ssid: [0; 32], 544 ssid: scan_opts
483 bssid: [0xff; 6], 545 .ssid
546 .map(|e| {
547 let mut ssid = [0; 32];
548 ssid[..e.as_bytes().len()].copy_from_slice(e.as_bytes());
549 ssid
550 })
551 .unwrap_or([0; 32]),
552 bssid: scan_opts.bssid.unwrap_or([0xff; 6]),
484 bss_type: 2, 553 bss_type: 2,
485 scan_type: SCANTYPE_PASSIVE, 554 scan_type,
486 nprobes: !0, 555 nprobes: scan_opts.nprobes.unwrap_or(!0).into(),
487 active_time: !0, 556 active_time,
488 passive_time: !0, 557 passive_time,
489 home_time: !0, 558 home_time: scan_opts.home_time.map(|e| e.as_millis() as u32).unwrap_or(!0),
490 channel_num: 0, 559 channel_num: 0,
491 channel_list: [0; 1], 560 channel_list: [0; 1],
492 }; 561 };
diff --git a/cyw43/src/events.rs b/cyw43/src/events.rs
index a94c49a0c..44bfa98e9 100644
--- a/cyw43/src/events.rs
+++ b/cyw43/src/events.rs
@@ -311,13 +311,13 @@ pub struct Status {
311 pub status: u32, 311 pub status: u32,
312} 312}
313 313
314#[derive(Clone, Copy)] 314#[derive(Copy, Clone)]
315pub enum Payload { 315pub enum Payload {
316 None, 316 None,
317 BssInfo(BssInfo), 317 BssInfo(BssInfo),
318} 318}
319 319
320#[derive(Clone, Copy)] 320#[derive(Copy, Clone)]
321 321
322pub struct Message { 322pub struct Message {
323 pub header: Status, 323 pub header: Status,
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs
index b2a9e3e80..c72cf0def 100644
--- a/cyw43/src/runner.rs
+++ b/cyw43/src/runner.rs
@@ -242,13 +242,12 @@ where
242 cmd, 242 cmd,
243 iface, 243 iface,
244 }) => { 244 }) => {
245 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await; 245 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await;
246 self.check_status(&mut buf).await; 246 self.check_status(&mut buf).await;
247 } 247 }
248 Either3::Second(packet) => { 248 Either3::Second(packet) => {
249 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); 249 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
250 250
251 let mut buf = [0; 512];
252 let buf8 = slice8_mut(&mut buf); 251 let buf8 = slice8_mut(&mut buf);
253 252
254 // There MUST be 2 bytes of padding between the SDPCM and BDC headers. 253 // There MUST be 2 bytes of padding between the SDPCM and BDC headers.
@@ -480,9 +479,8 @@ where
480 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 479 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
481 } 480 }
482 481
483 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) { 482 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8], buf: &mut [u32; 512]) {
484 let mut buf = [0; 512]; 483 let buf8 = slice8_mut(buf);
485 let buf8 = slice8_mut(&mut buf);
486 484
487 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); 485 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
488 486
diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs
index 5ea62d95b..ae7ef6038 100644
--- a/cyw43/src/structs.rs
+++ b/cyw43/src/structs.rs
@@ -491,6 +491,44 @@ pub struct BssInfo {
491 pub ssid_len: u8, 491 pub ssid_len: u8,
492 /// SSID. 492 /// SSID.
493 pub ssid: [u8; 32], 493 pub ssid: [u8; 32],
494 reserved1: [u8; 1],
495 /// Number of rates in the rates field.
496 pub rateset_count: u32,
497 /// Rates in 500kpbs units.
498 pub rates: [u8; 16],
499 /// Channel specification.
500 pub chanspec: u16,
501 /// Announcement traffic indication message.
502 pub atim_window: u16,
503 /// Delivery traffic indication message.
504 pub dtim_period: u8,
505 reserved2: [u8; 1],
506 /// Receive signal strength (in dbM).
507 pub rssi: i16,
508 /// Received noise (in dbM).
509 pub phy_noise: i8,
510 /// 802.11n capability.
511 pub n_cap: u8,
512 reserved3: [u8; 2],
513 /// 802.11n BSS capabilities.
514 pub nbss_cap: u32,
515 /// 802.11n control channel number.
516 pub ctl_ch: u8,
517 reserved4: [u8; 3],
518 reserved32: [u32; 1],
519 /// Flags.
520 pub flags: u8,
521 /// VHT capability.
522 pub vht_cap: u8,
523 reserved5: [u8; 2],
524 /// 802.11n BSS required MCS.
525 pub basic_mcs: [u8; 16],
526 /// Information Elements (IE) offset.
527 pub ie_offset: u16,
528 /// Length of Information Elements (IE) in bytes.
529 pub ie_length: u32,
530 /// Average signal-to-noise (SNR) ratio during frame reception.
531 pub snr: i16,
494 // there will be more stuff here 532 // there will be more stuff here
495} 533}
496impl_bytes!(BssInfo); 534impl_bytes!(BssInfo);
diff --git a/docs/modules/ROOT/examples/basic/src/main.rs b/docs/modules/ROOT/examples/basic/src/main.rs
index 2a4ee5968..4412712c8 100644
--- a/docs/modules/ROOT/examples/basic/src/main.rs
+++ b/docs/modules/ROOT/examples/basic/src/main.rs
@@ -4,12 +4,11 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Level, Output, OutputDrive}; 6use embassy_nrf::gpio::{Level, Output, OutputDrive};
7use embassy_nrf::peripherals::P0_13;
8use embassy_time::{Duration, Timer}; 7use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; // global logger 8use {defmt_rtt as _, panic_probe as _}; // global logger
10 9
11#[embassy_executor::task] 10#[embassy_executor::task]
12async fn blinker(mut led: Output<'static, P0_13>, interval: Duration) { 11async fn blinker(mut led: Output<'static>, interval: Duration) {
13 loop { 12 loop {
14 led.set_high(); 13 led.set_high();
15 Timer::after(interval).await; 14 Timer::after(interval).await;
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 e6753be28..004602816 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
@@ -3,14 +3,14 @@
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_stm32::exti::ExtiInput; 5use embassy_stm32::exti::ExtiInput;
6use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
8 8
9#[embassy_executor::main] 9#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default()); 11 let p = embassy_stm32::init(Default::default());
12 let mut led = Output::new(p.PB14, Level::Low, Speed::VeryHigh); 12 let mut led = Output::new(p.PB14, Level::Low, Speed::VeryHigh);
13 let mut button = ExtiInput::new(Input::new(p.PC13, Pull::Up), p.EXTI13); 13 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
14 14
15 loop { 15 loop {
16 button.wait_for_any_edge().await; 16 button.wait_for_any_edge().await;
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
index aecba0755..743c9d99b 100644
--- a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
+++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs
@@ -6,13 +6,12 @@ use core::cell::RefCell;
6use cortex_m::interrupt::Mutex; 6use cortex_m::interrupt::Mutex;
7use cortex_m::peripheral::NVIC; 7use cortex_m::peripheral::NVIC;
8use cortex_m_rt::entry; 8use cortex_m_rt::entry;
9use embassy_stm32::gpio::{Input, Level, Output, Pin, Pull, Speed}; 9use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
10use embassy_stm32::peripherals::{PB14, PC13};
11use embassy_stm32::{interrupt, pac}; 10use embassy_stm32::{interrupt, pac};
12use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
13 12
14static BUTTON: Mutex<RefCell<Option<Input<'static, PC13>>>> = Mutex::new(RefCell::new(None)); 13static BUTTON: Mutex<RefCell<Option<Input<'static>>>> = Mutex::new(RefCell::new(None));
15static LED: Mutex<RefCell<Option<Output<'static, PB14>>>> = Mutex::new(RefCell::new(None)); 14static LED: Mutex<RefCell<Option<Output<'static>>>> = Mutex::new(RefCell::new(None));
16 15
17#[entry] 16#[entry]
18fn main() -> ! { 17fn main() -> ! {
@@ -62,14 +61,14 @@ fn EXTI15_10() {
62 61
63const PORT: u8 = 2; 62const PORT: u8 = 2;
64const PIN: usize = 13; 63const PIN: usize = 13;
65fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool { 64fn check_interrupt(_pin: &mut Input<'static>) -> bool {
66 let exti = pac::EXTI; 65 let exti = pac::EXTI;
67 let pin = PIN; 66 let pin = PIN;
68 let lines = exti.pr(0).read(); 67 let lines = exti.pr(0).read();
69 lines.line(pin) 68 lines.line(pin)
70} 69}
71 70
72fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { 71fn clear_interrupt(_pin: &mut Input<'static>) {
73 let exti = pac::EXTI; 72 let exti = pac::EXTI;
74 let pin = PIN; 73 let pin = PIN;
75 let mut lines = exti.pr(0).read(); 74 let mut lines = exti.pr(0).read();
@@ -77,7 +76,7 @@ fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
77 exti.pr(0).write_value(lines); 76 exti.pr(0).write_value(lines);
78} 77}
79 78
80fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { 79fn enable_interrupt(_pin: &mut Input<'static>) {
81 cortex_m::interrupt::free(|_| { 80 cortex_m::interrupt::free(|_| {
82 let rcc = pac::RCC; 81 let rcc = pac::RCC;
83 rcc.apb2enr().modify(|w| w.set_syscfgen(true)); 82 rcc.apb2enr().modify(|w| w.set_syscfgen(true));
diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
index 95792d5a0..d5aad806d 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -17,22 +17,13 @@ The first thing you’ll notice are two attributes at the top of the file. These
17include::example$basic/src/main.rs[lines="1..2"] 17include::example$basic/src/main.rs[lines="1..2"]
18---- 18----
19 19
20=== Rust Nightly
21
22The next declaration is a Rust Unstable feature, which means that Embassy requires Rust Nightly:
23
24[source,rust]
25----
26include::example$basic/src/main.rs[lines="3"]
27----
28
29=== Dealing with errors 20=== Dealing with errors
30 21
31Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal: 22Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal:
32 23
33[source,rust] 24[source,rust]
34---- 25----
35include::example$basic/src/main.rs[lines="10"] 26include::example$basic/src/main.rs[lines="8"]
36---- 27----
37 28
38=== Task declaration 29=== Task declaration
@@ -41,7 +32,7 @@ After a bit of import declaration, the tasks run by the application should be de
41 32
42[source,rust] 33[source,rust]
43---- 34----
44include::example$basic/src/main.rs[lines="12..20"] 35include::example$basic/src/main.rs[lines="10..18"]
45---- 36----
46 37
47An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking. 38An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
@@ -56,7 +47,7 @@ We then initialize the HAL with a default config, which gives us a `Peripherals`
56 47
57[source,rust] 48[source,rust]
58---- 49----
59include::example$basic/src/main.rs[lines="22..-1"] 50include::example$basic/src/main.rs[lines="20..-1"]
60---- 51----
61 52
62What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following: 53What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
diff --git a/docs/modules/ROOT/pages/best_practices.adoc b/docs/modules/ROOT/pages/best_practices.adoc
index 1e02f9ba9..bfcedec06 100644
--- a/docs/modules/ROOT/pages/best_practices.adoc
+++ b/docs/modules/ROOT/pages/best_practices.adoc
@@ -3,8 +3,10 @@
3Over time, a couple of best practices have emerged. The following list should serve as a guideline for developers writing embedded software in _Rust_, especially in the context of the _Embassy_ framework. 3Over time, a couple of best practices have emerged. The following list should serve as a guideline for developers writing embedded software in _Rust_, especially in the context of the _Embassy_ framework.
4 4
5== Passing Buffers by Reference 5== Passing Buffers by Reference
6It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't want to spend ressources on an allocator and end up placing buffers on the stack. 6It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`],
7This, however, can easily blow up your stack if you are not careful. 7to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't
8want to spend resources on an allocator and end up placing buffers on the stack. This, however, can easily blow up
9your stack if you are not careful.
8 10
9Consider the following example: 11Consider the following example:
10[,rust] 12[,rust]
diff --git a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc
index a1c31bfc7..85ad7f4a2 100644
--- a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc
+++ b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc
@@ -7,3 +7,5 @@ Here are known examples of real-world projects which make use of Embassy. Feel f
7* link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device 7* link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device
8** Targets the ESP32-S3 or ESP32-C6 MCU 8** Targets the ESP32-S3 or ESP32-C6 MCU
9* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL 9* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL
10** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system]
11*** Targets nRF52 and uses nrf-softdevice
diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc
index 147f119b0..6b5e6d009 100644
--- a/docs/modules/ROOT/pages/faq.adoc
+++ b/docs/modules/ROOT/pages/faq.adoc
@@ -29,11 +29,10 @@ If you see an error like this:
29 29
30You are likely missing some features of the `embassy-executor` crate. 30You are likely missing some features of the `embassy-executor` crate.
31 31
32For Cortex-M targets, consider making sure that ALL of the following features are active in your `Cargo.toml` for the `embassy-executor` crate: 32For Cortex-M targets, check whether ALL of the following features are enabled in your `Cargo.toml` for the `embassy-executor` crate:
33 33
34* `arch-cortex-m` 34* `arch-cortex-m`
35* `executor-thread` 35* `executor-thread`
36* `nightly`
37 36
38For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. 37For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate].
39 38
@@ -44,11 +43,12 @@ The first step to managing your binary size is to set up your link:https://doc.r
44[source,toml] 43[source,toml]
45---- 44----
46[profile.release] 45[profile.release]
47debug = false
48lto = true 46lto = true
49opt-level = "s" 47opt-level = "s"
50incremental = false 48incremental = false
51codegen-units = 1 49codegen-units = 1
50# note: debug = true is okay - debuginfo isn't flashed to the device!
51debug = true
52---- 52----
53 53
54All of these flags are elaborated on in the Rust Book page linked above. 54All of these flags are elaborated on in the Rust Book page linked above.
@@ -118,21 +118,31 @@ features = [
118] 118]
119---- 119----
120 120
121If you are in the early project setup phase and not using anything from the HAL, make sure the HAL is explicitly used to prevent the linker removing it as dead code by adding this line to your source:
122
123[source,rust]
124----
125use embassy_stm32 as _;
126----
127
121== Error: `Only one package in the dependency graph may specify the same links value.` 128== Error: `Only one package in the dependency graph may specify the same links value.`
122 129
123You have multiple versions of the same crate in your dependency tree. This means that some of your 130You have multiple versions of the same crate in your dependency tree. This means that some of your
124embassy crates are coming from crates.io, and some from git, each of them pulling in a different set 131embassy crates are coming from crates.io, and some from git, each of them pulling in a different set
125of dependencies. 132of dependencies.
126 133
127To resolve this issue, make sure to only use a single source for all your embassy crates! To do this, 134To resolve this issue, make sure to only use a single source for all your embassy crates!
128you should patch your dependencies to use git sources using `[patch.crates.io]` and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. 135To do this, you should patch your dependencies to use git sources using `[patch.crates.io]`
136and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`.
129 137
130Example: 138Example:
131 139
132[source,toml] 140[source,toml]
133---- 141----
134[patch.crates-io] 142[patch.crates-io]
135embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } 143embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" }
144embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" }
145# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" }
136---- 146----
137 147
138Note that the git revision should match any other embassy patches or git dependencies that you are using! 148Note that the git revision should match any other embassy patches or git dependencies that you are using!
@@ -180,3 +190,21 @@ Check out link:https://docs.embassy.dev/embassy-executor/git/cortex-m/index.html
180== Can I use manual ISRs alongside Embassy? 190== Can I use manual ISRs alongside Embassy?
181 191
182Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project]. 192Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project].
193
194== How can I measure resource usage (CPU, RAM, etc.)?
195
196=== For CPU Usage:
197
198There are a couple techniques that have been documented, generally you want to measure how long you are spending in the idle or low priority loop.
199
200We need to document specifically how to do this in embassy, but link:https://blog.japaric.io/cpu-monitor/[this older post] describes the general process.
201
202If you end up doing this, please update this section with more specific examples!
203
204=== For Static Memory Usage
205
206Tools like `cargo size` and `cargo nm` can tell you the size of any globals or other static usage. Specifically you will want to see the size of the `.data` and `.bss` sections, which together make up the total global/static memory usage.
207
208=== For Max Stack Usage
209
210Check out link:https://github.com/Dirbaio/cargo-call-stack/[`cargo-call-stack`] for statically calculating worst-case stack usage. There are some caveats and inaccuracies possible with this, but this is a good way to get the general idea. See link:https://github.com/dirbaio/cargo-call-stack#known-limitations[the README] for more details.
diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc
index ab819ac2a..73cb5530d 100644
--- a/docs/modules/ROOT/pages/getting_started.adoc
+++ b/docs/modules/ROOT/pages/getting_started.adoc
@@ -3,7 +3,7 @@
3So you want to try Embassy, great! To get started, there are a few tools you need to install: 3So you want to try Embassy, great! To get started, there are a few tools you need to install:
4 4
5* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code. 5* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
6* link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. 6* link:https://probe.rs/[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
7 7
8If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples. 8If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
9 9
@@ -82,19 +82,19 @@ If everything worked correctly, you should see a blinking LED on your board, and
82└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27 82└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27
83---- 83----
84 84
85NOTE: How does the `cargo run` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips. 85NOTE: How does the `+cargo run+` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips.
86 86
87=== It didn’t work! 87=== It didn’t work!
88 88
89If you hare having issues when running `cargo run --release`, please check the following: 89If you hare having issues when running `+cargo run --release+`, please check the following:
90 90
91* You are specifying the correct `--chip on the command line``, OR 91* You are specifying the correct `+--chip+` on the command line, OR
92* You have set `.cargo/config.toml`'s run line to the correct chip, AND 92* You have set `+.cargo/config.toml+`s run line to the correct chip, AND
93* You have changed `examples/Cargo.toml`'s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature) 93* You have changed `+examples/Cargo.toml+`’s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature)
94 94
95At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin. 95At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin.
96 96
97If you are trying to run an example with `cargo run --release` and you see the following output: 97If you are trying to run an example with `+cargo run --release+` and you see the following output:
98[source] 98[source]
99---- 99----
1000.000000 INFO Hello World! 1000.000000 INFO Hello World!
@@ -115,6 +115,22 @@ To get rid of the frame-index error add the following to your `Cargo.toml`:
115debug = 2 115debug = 2
116---- 116----
117 117
118If you’re getting an extremely long error message containing something like the following:
119
120[source]
121----
122error[E0463]: can't find crate for `std`
123 |
124 = note: the `thumbv6m-none-eabi` target may not support the standard library
125 = note: `std` is required by `stable_deref_trait` because it does not declare `#![no_std]`
126----
127
128Make sure that you didn’t accidentally run `+cargo add probe-rs+` (which adds it as a dependency) instead of link:https://probe.rs/docs/getting-started/installation/[correctly installing probe-rs].
129
130If you’re using a raspberry pi pico-w, make sure you’re running `+cargo run --bin wifi_blinky --release+` rather than the regular blinky. The pico-w’s on-board LED is connected to the WiFi chip, which needs to be initialized before the LED can be blinked.
131
132If you’re using an rp2040 debug probe (e.g. the pico probe) and are having issues after running `probe-rs info`, unplug and reconnect the probe, letting it power cycle. Running `probe-rs info` is link:https://github.com/probe-rs/probe-rs/issues/1849[known to put the pico probe into an unusable state].
133
118If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room]. 134If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room].
119 135
120== What's next? 136== What's next?
@@ -124,3 +140,4 @@ Congratulations, you have your first Embassy application running! Here are some
124* Read more about the xref:runtime.adoc[executor]. 140* Read more about the xref:runtime.adoc[executor].
125* Read more about the xref:hal.adoc[HAL]. 141* Read more about the xref:hal.adoc[HAL].
126* Start xref:basic_application.adoc[writing your application]. 142* Start xref:basic_application.adoc[writing your application].
143* Learn how to xref:new_project.adoc[start a new embassy project by adapting an example].
diff --git a/docs/modules/ROOT/pages/new_project.adoc b/docs/modules/ROOT/pages/new_project.adoc
index ce139ed8d..320966bb6 100644
--- a/docs/modules/ROOT/pages/new_project.adoc
+++ b/docs/modules/ROOT/pages/new_project.adoc
@@ -1,6 +1,17 @@
1= Starting a new Embassy project 1= Starting a new Embassy project
2 2
3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. The easiest way to do this is to adapt an example for a similar chip to the one you’re targeting. 3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project.
4
5There are some tools for generating Embassy projects: (WIP)
6
7==== CLI
8- link:https://github.com/adinack/cargo-embassy[cargo-embassy] (STM32 and NRF)
9
10==== cargo-generate
11- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP)
12- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP)
13
14But if you want to start from scratch:
4 15
5As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes. 16As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes.
6 17
@@ -166,13 +177,13 @@ should result in a blinking LED (if there’s one attached to the pin in `src/ma
166 Erasing sectors ✔ [00:00:00] [#########################################################] 18.00 KiB/18.00 KiB @ 54.09 KiB/s (eta 0s ) 177 Erasing sectors ✔ [00:00:00] [#########################################################] 18.00 KiB/18.00 KiB @ 54.09 KiB/s (eta 0s )
167 Programming pages ✔ [00:00:00] [#########################################################] 17.00 KiB/17.00 KiB @ 35.91 KiB/s (eta 0s ) Finished in 0.817s 178 Programming pages ✔ [00:00:00] [#########################################################] 17.00 KiB/17.00 KiB @ 35.91 KiB/s (eta 0s ) Finished in 0.817s
1680.000000 TRACE BDCR configured: 00008200 1790.000000 TRACE BDCR configured: 00008200
169└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117 180└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117
1700.000000 DEBUG rcc: Clocks { sys: Hertz(16000000), pclk1: Hertz(16000000), pclk1_tim: Hertz(16000000), pclk2: Hertz(16000000), pclk2_tim: Hertz(16000000), hclk1: Hertz(16000000), hclk2: Hertz(16000000), pll1_p: None, adc: None, adc34: None, rtc: Some(Hertz(32000)) } 1810.000000 DEBUG rcc: Clocks { sys: Hertz(16000000), pclk1: Hertz(16000000), pclk1_tim: Hertz(16000000), pclk2: Hertz(16000000), pclk2_tim: Hertz(16000000), hclk1: Hertz(16000000), hclk2: Hertz(16000000), pll1_p: None, adc: None, adc34: None, rtc: Some(Hertz(32000)) }
171└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130 182└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130
1720.000000 INFO Hello World! 1830.000000 INFO Hello World!
173└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14 184└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14
1740.000091 INFO high 1850.000091 INFO high
175└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19 186└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19
1760.300201 INFO low 1870.300201 INFO low
177└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23 188└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23
178---- \ No newline at end of file 189----
diff --git a/docs/modules/ROOT/pages/project_structure.adoc b/docs/modules/ROOT/pages/project_structure.adoc
index 61ffd05a6..2adfcc1df 100644
--- a/docs/modules/ROOT/pages/project_structure.adoc
+++ b/docs/modules/ROOT/pages/project_structure.adoc
@@ -38,13 +38,18 @@ DEFMT_LOG = "trace" # <- can change to info, warn, or error
38 38
39== build.rs 39== build.rs
40 40
41This is the build script for your project. It links defmt (what is defmt?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. 41This is the build script for your project. It links defmt (what is link:https://defmt.ferrous-systems.com[defmt]?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example].
42 42
43== Cargo.toml 43== Cargo.toml
44 44
45This is your manifest file, where you can configure all of the embassy components to use the features you need. 45This is your manifest file, where you can configure all of the embassy components to use the features you need.
46 46
47TODO: someone should exhaustively describe every feature for every component! 47==== Features
48===== Time
49- tick-hz-x: Configures the tick rate of `embassy-time`. Higher tick rate means higher precision, and higher CPU wakes.
50- defmt-timestamp-uptime: defmt log entries will display the uptime in seconds.
51
52...more to come
48 53
49== memory.x 54== memory.x
50 55
diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs
index 5b20a93c6..d53e78895 100644
--- a/embassy-boot-nrf/src/lib.rs
+++ b/embassy-boot-nrf/src/lib.rs
@@ -4,8 +4,8 @@
4mod fmt; 4mod fmt;
5 5
6pub use embassy_boot::{ 6pub use embassy_boot::{
7 AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareState, FirmwareUpdater, 7 AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState,
8 FirmwareUpdaterConfig, 8 FirmwareUpdater, FirmwareUpdaterConfig,
9}; 9};
10use embassy_nrf::nvmc::PAGE_SIZE; 10use embassy_nrf::nvmc::PAGE_SIZE;
11use embassy_nrf::peripherals::WDT; 11use embassy_nrf::peripherals::WDT;
@@ -16,14 +16,21 @@ use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
16pub struct BootLoader<const BUFFER_SIZE: usize = PAGE_SIZE>; 16pub struct BootLoader<const BUFFER_SIZE: usize = PAGE_SIZE>;
17 17
18impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> { 18impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> {
19 /// 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
20 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>( 20 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
21 config: BootLoaderConfig<ACTIVE, DFU, STATE>, 21 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
22 ) -> Self { 22 ) -> Self {
23 Self::try_prepare::<ACTIVE, DFU, STATE>(config).expect("Boot prepare error")
24 }
25
26 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware
27 pub fn try_prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
28 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
29 ) -> Result<Self, BootError> {
23 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); 30 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
24 let mut boot = embassy_boot::BootLoader::new(config); 31 let mut boot = embassy_boot::BootLoader::new(config);
25 boot.prepare_boot(&mut aligned_buf.0).expect("Boot prepare error"); 32 let _state = boot.prepare_boot(aligned_buf.as_mut())?;
26 Self 33 Ok(Self)
27 } 34 }
28 35
29 /// Boots the application without softdevice mechanisms. 36 /// Boots the application without softdevice mechanisms.
diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs
index 07a5b3f4d..d0a393bed 100644
--- a/embassy-boot-rp/src/lib.rs
+++ b/embassy-boot-rp/src/lib.rs
@@ -4,8 +4,8 @@
4mod fmt; 4mod fmt;
5 5
6pub use embassy_boot::{ 6pub use embassy_boot::{
7 AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareState, FirmwareUpdater, 7 AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState,
8 FirmwareUpdaterConfig, State, 8 FirmwareUpdater, FirmwareUpdaterConfig, State,
9}; 9};
10use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE}; 10use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE};
11use embassy_rp::peripherals::{FLASH, WATCHDOG}; 11use embassy_rp::peripherals::{FLASH, WATCHDOG};
@@ -21,10 +21,17 @@ impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> {
21 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>( 21 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
22 config: BootLoaderConfig<ACTIVE, DFU, STATE>, 22 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
23 ) -> Self { 23 ) -> Self {
24 Self::try_prepare::<ACTIVE, DFU, STATE>(config).expect("Boot prepare error")
25 }
26
27 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware
28 pub fn try_prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
29 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
30 ) -> Result<Self, BootError> {
24 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); 31 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
25 let mut boot = embassy_boot::BootLoader::new(config); 32 let mut boot = embassy_boot::BootLoader::new(config);
26 boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); 33 let _state = boot.prepare_boot(aligned_buf.as_mut())?;
27 Self 34 Ok(Self)
28 } 35 }
29 36
30 /// Boots the application. 37 /// Boots the application.
diff --git a/embassy-boot-stm32/src/lib.rs b/embassy-boot-stm32/src/lib.rs
index 4b4091ac9..708441835 100644
--- a/embassy-boot-stm32/src/lib.rs
+++ b/embassy-boot-stm32/src/lib.rs
@@ -4,8 +4,8 @@
4mod fmt; 4mod fmt;
5 5
6pub use embassy_boot::{ 6pub use embassy_boot::{
7 AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootLoaderConfig, FirmwareState, FirmwareUpdater, 7 AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState,
8 FirmwareUpdaterConfig, State, 8 FirmwareUpdater, FirmwareUpdaterConfig, State,
9}; 9};
10use embedded_storage::nor_flash::NorFlash; 10use embedded_storage::nor_flash::NorFlash;
11 11
@@ -20,10 +20,17 @@ impl BootLoader {
20 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>( 20 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>(
21 config: BootLoaderConfig<ACTIVE, DFU, STATE>, 21 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
22 ) -> Self { 22 ) -> Self {
23 Self::try_prepare::<ACTIVE, DFU, STATE, BUFFER_SIZE>(config).expect("Boot prepare error")
24 }
25
26 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware
27 pub fn try_prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>(
28 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
29 ) -> Result<Self, BootError> {
23 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); 30 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
24 let mut boot = embassy_boot::BootLoader::new(config); 31 let mut boot = embassy_boot::BootLoader::new(config);
25 let state = boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); 32 let state = boot.prepare_boot(aligned_buf.as_mut())?;
26 Self { state } 33 Ok(Self { state })
27 } 34 }
28 35
29 /// Boots the application. 36 /// Boots the application.
diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs
index e568001bc..ca1a1b10c 100644
--- a/embassy-boot/src/boot_loader.rs
+++ b/embassy-boot/src/boot_loader.rs
@@ -49,16 +49,51 @@ pub struct BootLoaderConfig<ACTIVE, DFU, STATE> {
49 pub state: STATE, 49 pub state: STATE,
50} 50}
51 51
52impl<'a, FLASH: NorFlash> 52impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>
53 BootLoaderConfig< 53 BootLoaderConfig<
54 BlockingPartition<'a, NoopRawMutex, FLASH>, 54 BlockingPartition<'a, NoopRawMutex, ACTIVE>,
55 BlockingPartition<'a, NoopRawMutex, FLASH>, 55 BlockingPartition<'a, NoopRawMutex, DFU>,
56 BlockingPartition<'a, NoopRawMutex, FLASH>, 56 BlockingPartition<'a, NoopRawMutex, STATE>,
57 > 57 >
58{ 58{
59 /// Create a bootloader config from the flash and address symbols defined in the linkerfile 59 /// Constructs a `BootLoaderConfig` instance from flash memory and address symbols defined in the linker file.
60 ///
61 /// This method initializes `BlockingPartition` instances for the active, DFU (Device Firmware Update),
62 /// and state partitions, leveraging start and end addresses specified by the linker. These partitions
63 /// are critical for managing firmware updates, application state, and boot operations within the bootloader.
64 ///
65 /// # Parameters
66 /// - `active_flash`: A reference to a mutex-protected `RefCell` for the active partition's flash interface.
67 /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface.
68 /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface.
69 ///
70 /// # Safety
71 /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses
72 /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined
73 /// in the memory.x file to prevent undefined behavior.
74 ///
75 /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory
76 /// interfaces provided are compatible with these regions.
77 ///
78 /// # Returns
79 /// A `BootLoaderConfig` instance with `BlockingPartition` instances for the active, DFU, and state partitions.
80 ///
81 /// # Example
82 /// ```ignore
83 /// // Assume `active_flash`, `dfu_flash`, and `state_flash` all share the same flash memory interface.
84 /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
85 /// let flash = Mutex::new(RefCell::new(layout.bank1_region));
86 ///
87 /// let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
88 /// // `config` can now be used to create a `BootLoader` instance for managing boot operations.
89 /// ```
90 /// Working examples can be found in the bootloader examples folder.
60 // #[cfg(target_os = "none")] 91 // #[cfg(target_os = "none")]
61 pub fn from_linkerfile_blocking(flash: &'a Mutex<NoopRawMutex, RefCell<FLASH>>) -> Self { 92 pub fn from_linkerfile_blocking(
93 active_flash: &'a Mutex<NoopRawMutex, RefCell<ACTIVE>>,
94 dfu_flash: &'a Mutex<NoopRawMutex, RefCell<DFU>>,
95 state_flash: &'a Mutex<NoopRawMutex, RefCell<STATE>>,
96 ) -> Self {
62 extern "C" { 97 extern "C" {
63 static __bootloader_state_start: u32; 98 static __bootloader_state_start: u32;
64 static __bootloader_state_end: u32; 99 static __bootloader_state_end: u32;
@@ -73,21 +108,21 @@ impl<'a, FLASH: NorFlash>
73 let end = &__bootloader_active_end as *const u32 as u32; 108 let end = &__bootloader_active_end as *const u32 as u32;
74 trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end); 109 trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end);
75 110
76 BlockingPartition::new(flash, start, end - start) 111 BlockingPartition::new(active_flash, start, end - start)
77 }; 112 };
78 let dfu = unsafe { 113 let dfu = unsafe {
79 let start = &__bootloader_dfu_start as *const u32 as u32; 114 let start = &__bootloader_dfu_start as *const u32 as u32;
80 let end = &__bootloader_dfu_end as *const u32 as u32; 115 let end = &__bootloader_dfu_end as *const u32 as u32;
81 trace!("DFU: 0x{:x} - 0x{:x}", start, end); 116 trace!("DFU: 0x{:x} - 0x{:x}", start, end);
82 117
83 BlockingPartition::new(flash, start, end - start) 118 BlockingPartition::new(dfu_flash, start, end - start)
84 }; 119 };
85 let state = unsafe { 120 let state = unsafe {
86 let start = &__bootloader_state_start as *const u32 as u32; 121 let start = &__bootloader_state_start as *const u32 as u32;
87 let end = &__bootloader_state_end as *const u32 as u32; 122 let end = &__bootloader_state_end as *const u32 as u32;
88 trace!("STATE: 0x{:x} - 0x{:x}", start, end); 123 trace!("STATE: 0x{:x} - 0x{:x}", start, end);
89 124
90 BlockingPartition::new(flash, start, end - start) 125 BlockingPartition::new(state_flash, start, end - start)
91 }; 126 };
92 127
93 Self { active, dfu, state } 128 Self { active, dfu, state }
diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs
index 2e43e1cc1..26f65f295 100644
--- a/embassy-boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/src/firmware_updater/asynch.rs
@@ -13,14 +13,18 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERA
13pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { 13pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> {
14 dfu: DFU, 14 dfu: DFU,
15 state: FirmwareState<'d, STATE>, 15 state: FirmwareState<'d, STATE>,
16 last_erased_dfu_sector_index: Option<usize>,
16} 17}
17 18
18#[cfg(target_os = "none")] 19#[cfg(target_os = "none")]
19impl<'a, FLASH: NorFlash> 20impl<'a, DFU: NorFlash, STATE: NorFlash>
20 FirmwareUpdaterConfig<Partition<'a, NoopRawMutex, FLASH>, Partition<'a, NoopRawMutex, FLASH>> 21 FirmwareUpdaterConfig<Partition<'a, NoopRawMutex, DFU>, Partition<'a, NoopRawMutex, STATE>>
21{ 22{
22 /// Create a firmware updater config from the flash and address symbols defined in the linkerfile 23 /// Create a firmware updater config from the flash and address symbols defined in the linkerfile
23 pub fn from_linkerfile(flash: &'a embassy_sync::mutex::Mutex<NoopRawMutex, FLASH>) -> Self { 24 pub fn from_linkerfile(
25 dfu_flash: &'a embassy_sync::mutex::Mutex<NoopRawMutex, DFU>,
26 state_flash: &'a embassy_sync::mutex::Mutex<NoopRawMutex, STATE>,
27 ) -> Self {
24 extern "C" { 28 extern "C" {
25 static __bootloader_state_start: u32; 29 static __bootloader_state_start: u32;
26 static __bootloader_state_end: u32; 30 static __bootloader_state_end: u32;
@@ -33,14 +37,14 @@ impl<'a, FLASH: NorFlash>
33 let end = &__bootloader_dfu_end as *const u32 as u32; 37 let end = &__bootloader_dfu_end as *const u32 as u32;
34 trace!("DFU: 0x{:x} - 0x{:x}", start, end); 38 trace!("DFU: 0x{:x} - 0x{:x}", start, end);
35 39
36 Partition::new(flash, start, end - start) 40 Partition::new(dfu_flash, start, end - start)
37 }; 41 };
38 let state = unsafe { 42 let state = unsafe {
39 let start = &__bootloader_state_start as *const u32 as u32; 43 let start = &__bootloader_state_start as *const u32 as u32;
40 let end = &__bootloader_state_end as *const u32 as u32; 44 let end = &__bootloader_state_end as *const u32 as u32;
41 trace!("STATE: 0x{:x} - 0x{:x}", start, end); 45 trace!("STATE: 0x{:x} - 0x{:x}", start, end);
42 46
43 Partition::new(flash, start, end - start) 47 Partition::new(state_flash, start, end - start)
44 }; 48 };
45 49
46 Self { dfu, state } 50 Self { dfu, state }
@@ -53,6 +57,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
53 Self { 57 Self {
54 dfu: config.dfu, 58 dfu: config.dfu,
55 state: FirmwareState::new(config.state, aligned), 59 state: FirmwareState::new(config.state, aligned),
60 last_erased_dfu_sector_index: None,
56 } 61 }
57 } 62 }
58 63
@@ -69,7 +74,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
69 /// proceed with updating the firmware as it must be signed with a 74 /// proceed with updating the firmware as it must be signed with a
70 /// corresponding private key (otherwise it could be malicious firmware). 75 /// corresponding private key (otherwise it could be malicious firmware).
71 /// 76 ///
72 /// Mark to trigger firmware swap on next boot if verify suceeds. 77 /// Mark to trigger firmware swap on next boot if verify succeeds.
73 /// 78 ///
74 /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have 79 /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have
75 /// been generated from a SHA-512 digest of the firmware bytes. 80 /// been generated from a SHA-512 digest of the firmware bytes.
@@ -169,21 +174,68 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
169 self.state.mark_booted().await 174 self.state.mark_booted().await
170 } 175 }
171 176
172 /// Write data to a flash page. 177 /// Writes firmware data to the device.
173 /// 178 ///
174 /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. 179 /// This function writes the given data to the firmware area starting at the specified offset.
180 /// It handles sector erasures and data writes while verifying the device is in a proper state
181 /// for firmware updates. The function ensures that only unerased sectors are erased before
182 /// writing and efficiently handles the writing process across sector boundaries and in
183 /// various configurations (data size, sector size, etc.).
175 /// 184 ///
176 /// # Safety 185 /// # Arguments
186 ///
187 /// * `offset` - The starting offset within the firmware area where data writing should begin.
188 /// * `data` - A slice of bytes representing the firmware data to be written. It must be a
189 /// multiple of NorFlash WRITE_SIZE.
190 ///
191 /// # Returns
192 ///
193 /// A `Result<(), FirmwareUpdaterError>` indicating the success or failure of the write operation.
194 ///
195 /// # Errors
177 /// 196 ///
178 /// Failing to meet alignment and size requirements may result in a panic. 197 /// This function will return an error if:
198 ///
199 /// - The device is not in a proper state to receive firmware updates (e.g., not booted).
200 /// - There is a failure erasing a sector before writing.
201 /// - There is a failure writing data to the device.
179 pub async fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { 202 pub async fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> {
180 assert!(data.len() >= DFU::ERASE_SIZE); 203 // Make sure we are running a booted firmware to avoid reverting to a bad state.
181
182 self.state.verify_booted().await?; 204 self.state.verify_booted().await?;
183 205
184 self.dfu.erase(offset as u32, (offset + data.len()) as u32).await?; 206 // Initialize variables to keep track of the remaining data and the current offset.
207 let mut remaining_data = data;
208 let mut offset = offset;
209
210 // Continue writing as long as there is data left to write.
211 while !remaining_data.is_empty() {
212 // Compute the current sector and its boundaries.
213 let current_sector = offset / DFU::ERASE_SIZE;
214 let sector_start = current_sector * DFU::ERASE_SIZE;
215 let sector_end = sector_start + DFU::ERASE_SIZE;
216 // Determine if the current sector needs to be erased before writing.
217 let need_erase = self
218 .last_erased_dfu_sector_index
219 .map_or(true, |last_erased_sector| current_sector != last_erased_sector);
220
221 // If the sector needs to be erased, erase it and update the last erased sector index.
222 if need_erase {
223 self.dfu.erase(sector_start as u32, sector_end as u32).await?;
224 self.last_erased_dfu_sector_index = Some(current_sector);
225 }
226
227 // Calculate the size of the data chunk that can be written in the current iteration.
228 let write_size = core::cmp::min(remaining_data.len(), sector_end - offset);
229 // Split the data to get the current chunk to be written and the remaining data.
230 let (data_chunk, rest) = remaining_data.split_at(write_size);
185 231
186 self.dfu.write(offset as u32, data).await?; 232 // Write the current data chunk.
233 self.dfu.write(offset as u32, data_chunk).await?;
234
235 // Update the offset and remaining data for the next iteration.
236 remaining_data = rest;
237 offset += write_size;
238 }
187 239
188 Ok(()) 240 Ok(())
189 } 241 }
@@ -273,16 +325,25 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
273 async fn set_magic(&mut self, magic: u8) -> Result<(), FirmwareUpdaterError> { 325 async fn set_magic(&mut self, magic: u8) -> Result<(), FirmwareUpdaterError> {
274 self.state.read(0, &mut self.aligned).await?; 326 self.state.read(0, &mut self.aligned).await?;
275 327
276 if self.aligned.iter().any(|&b| b != magic) { 328 if self.aligned[..STATE::WRITE_SIZE].iter().any(|&b| b != magic) {
277 // Read progress validity 329 // Read progress validity
278 self.state.read(STATE::WRITE_SIZE as u32, &mut self.aligned).await?; 330 if STATE::READ_SIZE <= 2 * STATE::WRITE_SIZE {
331 self.state.read(STATE::WRITE_SIZE as u32, &mut self.aligned).await?;
332 } else {
333 self.aligned.rotate_left(STATE::WRITE_SIZE);
334 }
279 335
280 if self.aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { 336 if self.aligned[..STATE::WRITE_SIZE]
337 .iter()
338 .any(|&b| b != STATE_ERASE_VALUE)
339 {
281 // The current progress validity marker is invalid 340 // The current progress validity marker is invalid
282 } else { 341 } else {
283 // Invalidate progress 342 // Invalidate progress
284 self.aligned.fill(!STATE_ERASE_VALUE); 343 self.aligned.fill(!STATE_ERASE_VALUE);
285 self.state.write(STATE::WRITE_SIZE as u32, &self.aligned).await?; 344 self.state
345 .write(STATE::WRITE_SIZE as u32, &self.aligned[..STATE::WRITE_SIZE])
346 .await?;
286 } 347 }
287 348
288 // Clear magic and progress 349 // Clear magic and progress
@@ -290,7 +351,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
290 351
291 // Set magic 352 // Set magic
292 self.aligned.fill(magic); 353 self.aligned.fill(magic);
293 self.state.write(0, &self.aligned).await?; 354 self.state.write(0, &self.aligned[..STATE::WRITE_SIZE]).await?;
294 } 355 }
295 Ok(()) 356 Ok(())
296 } 357 }
@@ -326,4 +387,76 @@ mod tests {
326 387
327 assert_eq!(Sha1::digest(update).as_slice(), hash); 388 assert_eq!(Sha1::digest(update).as_slice(), hash);
328 } 389 }
390
391 #[test]
392 fn can_verify_sha1_sector_bigger_than_chunk() {
393 let flash = Mutex::<NoopRawMutex, _>::new(MemFlash::<131072, 4096, 8>::default());
394 let state = Partition::new(&flash, 0, 4096);
395 let dfu = Partition::new(&flash, 65536, 65536);
396 let mut aligned = [0; 8];
397
398 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
399 let mut to_write = [0; 4096];
400 to_write[..7].copy_from_slice(update.as_slice());
401
402 let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned);
403 let mut offset = 0;
404 for chunk in to_write.chunks(1024) {
405 block_on(updater.write_firmware(offset, chunk)).unwrap();
406 offset += chunk.len();
407 }
408 let mut chunk_buf = [0; 2];
409 let mut hash = [0; 20];
410 block_on(updater.hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap();
411
412 assert_eq!(Sha1::digest(update).as_slice(), hash);
413 }
414
415 #[test]
416 fn can_verify_sha1_sector_smaller_than_chunk() {
417 let flash = Mutex::<NoopRawMutex, _>::new(MemFlash::<131072, 1024, 8>::default());
418 let state = Partition::new(&flash, 0, 4096);
419 let dfu = Partition::new(&flash, 65536, 65536);
420 let mut aligned = [0; 8];
421
422 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
423 let mut to_write = [0; 4096];
424 to_write[..7].copy_from_slice(update.as_slice());
425
426 let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned);
427 let mut offset = 0;
428 for chunk in to_write.chunks(2048) {
429 block_on(updater.write_firmware(offset, chunk)).unwrap();
430 offset += chunk.len();
431 }
432 let mut chunk_buf = [0; 2];
433 let mut hash = [0; 20];
434 block_on(updater.hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap();
435
436 assert_eq!(Sha1::digest(update).as_slice(), hash);
437 }
438
439 #[test]
440 fn can_verify_sha1_cross_sector_boundary() {
441 let flash = Mutex::<NoopRawMutex, _>::new(MemFlash::<131072, 1024, 8>::default());
442 let state = Partition::new(&flash, 0, 4096);
443 let dfu = Partition::new(&flash, 65536, 65536);
444 let mut aligned = [0; 8];
445
446 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
447 let mut to_write = [0; 4096];
448 to_write[..7].copy_from_slice(update.as_slice());
449
450 let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned);
451 let mut offset = 0;
452 for chunk in to_write.chunks(896) {
453 block_on(updater.write_firmware(offset, chunk)).unwrap();
454 offset += chunk.len();
455 }
456 let mut chunk_buf = [0; 2];
457 let mut hash = [0; 20];
458 block_on(updater.hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)).unwrap();
459
460 assert_eq!(Sha1::digest(update).as_slice(), hash);
461 }
329} 462}
diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs
index f1368540d..35772a856 100644
--- a/embassy-boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/src/firmware_updater/blocking.rs
@@ -13,15 +13,47 @@ use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERA
13pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { 13pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> {
14 dfu: DFU, 14 dfu: DFU,
15 state: BlockingFirmwareState<'d, STATE>, 15 state: BlockingFirmwareState<'d, STATE>,
16 last_erased_dfu_sector_index: Option<usize>,
16} 17}
17 18
18#[cfg(target_os = "none")] 19#[cfg(target_os = "none")]
19impl<'a, FLASH: NorFlash> 20impl<'a, DFU: NorFlash, STATE: NorFlash>
20 FirmwareUpdaterConfig<BlockingPartition<'a, NoopRawMutex, FLASH>, BlockingPartition<'a, NoopRawMutex, FLASH>> 21 FirmwareUpdaterConfig<BlockingPartition<'a, NoopRawMutex, DFU>, BlockingPartition<'a, NoopRawMutex, STATE>>
21{ 22{
22 /// Create a firmware updater config from the flash and address symbols defined in the linkerfile 23 /// Constructs a `FirmwareUpdaterConfig` instance from flash memory and address symbols defined in the linker file.
24 ///
25 /// This method initializes `BlockingPartition` instances for the DFU (Device Firmware Update), and state
26 /// partitions, leveraging start and end addresses specified by the linker. These partitions are critical
27 /// for managing firmware updates, application state, and boot operations within the bootloader.
28 ///
29 /// # Parameters
30 /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface.
31 /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface.
32 ///
33 /// # Safety
34 /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses
35 /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined
36 /// in the memory.x file to prevent undefined behavior.
37 ///
38 /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory
39 /// interfaces provided are compatible with these regions.
40 ///
41 /// # Returns
42 /// A `FirmwareUpdaterConfig` instance with `BlockingPartition` instances for the DFU, and state partitions.
43 ///
44 /// # Example
45 /// ```ignore
46 /// // Assume `dfu_flash`, and `state_flash` share the same flash memory interface.
47 /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
48 /// let flash = Mutex::new(RefCell::new(layout.bank1_region));
49 ///
50 /// let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
51 /// // `config` can now be used to create a `FirmwareUpdater` instance for managing boot operations.
52 /// ```
53 /// Working examples can be found in the bootloader examples folder.
23 pub fn from_linkerfile_blocking( 54 pub fn from_linkerfile_blocking(
24 flash: &'a embassy_sync::blocking_mutex::Mutex<NoopRawMutex, core::cell::RefCell<FLASH>>, 55 dfu_flash: &'a embassy_sync::blocking_mutex::Mutex<NoopRawMutex, core::cell::RefCell<DFU>>,
56 state_flash: &'a embassy_sync::blocking_mutex::Mutex<NoopRawMutex, core::cell::RefCell<STATE>>,
25 ) -> Self { 57 ) -> Self {
26 extern "C" { 58 extern "C" {
27 static __bootloader_state_start: u32; 59 static __bootloader_state_start: u32;
@@ -35,14 +67,14 @@ impl<'a, FLASH: NorFlash>
35 let end = &__bootloader_dfu_end as *const u32 as u32; 67 let end = &__bootloader_dfu_end as *const u32 as u32;
36 trace!("DFU: 0x{:x} - 0x{:x}", start, end); 68 trace!("DFU: 0x{:x} - 0x{:x}", start, end);
37 69
38 BlockingPartition::new(flash, start, end - start) 70 BlockingPartition::new(dfu_flash, start, end - start)
39 }; 71 };
40 let state = unsafe { 72 let state = unsafe {
41 let start = &__bootloader_state_start as *const u32 as u32; 73 let start = &__bootloader_state_start as *const u32 as u32;
42 let end = &__bootloader_state_end as *const u32 as u32; 74 let end = &__bootloader_state_end as *const u32 as u32;
43 trace!("STATE: 0x{:x} - 0x{:x}", start, end); 75 trace!("STATE: 0x{:x} - 0x{:x}", start, end);
44 76
45 BlockingPartition::new(flash, start, end - start) 77 BlockingPartition::new(state_flash, start, end - start)
46 }; 78 };
47 79
48 Self { dfu, state } 80 Self { dfu, state }
@@ -60,6 +92,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
60 Self { 92 Self {
61 dfu: config.dfu, 93 dfu: config.dfu,
62 state: BlockingFirmwareState::new(config.state, aligned), 94 state: BlockingFirmwareState::new(config.state, aligned),
95 last_erased_dfu_sector_index: None,
63 } 96 }
64 } 97 }
65 98
@@ -76,7 +109,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
76 /// proceed with updating the firmware as it must be signed with a 109 /// proceed with updating the firmware as it must be signed with a
77 /// corresponding private key (otherwise it could be malicious firmware). 110 /// corresponding private key (otherwise it could be malicious firmware).
78 /// 111 ///
79 /// Mark to trigger firmware swap on next boot if verify suceeds. 112 /// Mark to trigger firmware swap on next boot if verify succeeds.
80 /// 113 ///
81 /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have 114 /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have
82 /// been generated from a SHA-512 digest of the firmware bytes. 115 /// been generated from a SHA-512 digest of the firmware bytes.
@@ -176,20 +209,68 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
176 self.state.mark_booted() 209 self.state.mark_booted()
177 } 210 }
178 211
179 /// Write data to a flash page. 212 /// Writes firmware data to the device.
180 /// 213 ///
181 /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. 214 /// This function writes the given data to the firmware area starting at the specified offset.
215 /// It handles sector erasures and data writes while verifying the device is in a proper state
216 /// for firmware updates. The function ensures that only unerased sectors are erased before
217 /// writing and efficiently handles the writing process across sector boundaries and in
218 /// various configurations (data size, sector size, etc.).
182 /// 219 ///
183 /// # Safety 220 /// # Arguments
221 ///
222 /// * `offset` - The starting offset within the firmware area where data writing should begin.
223 /// * `data` - A slice of bytes representing the firmware data to be written. It must be a
224 /// multiple of NorFlash WRITE_SIZE.
184 /// 225 ///
185 /// Failing to meet alignment and size requirements may result in a panic. 226 /// # Returns
227 ///
228 /// A `Result<(), FirmwareUpdaterError>` indicating the success or failure of the write operation.
229 ///
230 /// # Errors
231 ///
232 /// This function will return an error if:
233 ///
234 /// - The device is not in a proper state to receive firmware updates (e.g., not booted).
235 /// - There is a failure erasing a sector before writing.
236 /// - There is a failure writing data to the device.
186 pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { 237 pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> {
187 assert!(data.len() >= DFU::ERASE_SIZE); 238 // Make sure we are running a booted firmware to avoid reverting to a bad state.
188 self.state.verify_booted()?; 239 self.state.verify_booted()?;
189 240
190 self.dfu.erase(offset as u32, (offset + data.len()) as u32)?; 241 // Initialize variables to keep track of the remaining data and the current offset.
242 let mut remaining_data = data;
243 let mut offset = offset;
244
245 // Continue writing as long as there is data left to write.
246 while !remaining_data.is_empty() {
247 // Compute the current sector and its boundaries.
248 let current_sector = offset / DFU::ERASE_SIZE;
249 let sector_start = current_sector * DFU::ERASE_SIZE;
250 let sector_end = sector_start + DFU::ERASE_SIZE;
251 // Determine if the current sector needs to be erased before writing.
252 let need_erase = self
253 .last_erased_dfu_sector_index
254 .map_or(true, |last_erased_sector| current_sector != last_erased_sector);
255
256 // If the sector needs to be erased, erase it and update the last erased sector index.
257 if need_erase {
258 self.dfu.erase(sector_start as u32, sector_end as u32)?;
259 self.last_erased_dfu_sector_index = Some(current_sector);
260 }
261
262 // Calculate the size of the data chunk that can be written in the current iteration.
263 let write_size = core::cmp::min(remaining_data.len(), sector_end - offset);
264 // Split the data to get the current chunk to be written and the remaining data.
265 let (data_chunk, rest) = remaining_data.split_at(write_size);
266
267 // Write the current data chunk.
268 self.dfu.write(offset as u32, data_chunk)?;
191 269
192 self.dfu.write(offset as u32, data)?; 270 // Update the offset and remaining data for the next iteration.
271 remaining_data = rest;
272 offset += write_size;
273 }
193 274
194 Ok(()) 275 Ok(())
195 } 276 }
@@ -337,4 +418,82 @@ mod tests {
337 418
338 assert_eq!(Sha1::digest(update).as_slice(), hash); 419 assert_eq!(Sha1::digest(update).as_slice(), hash);
339 } 420 }
421
422 #[test]
423 fn can_verify_sha1_sector_bigger_than_chunk() {
424 let flash = Mutex::<NoopRawMutex, _>::new(RefCell::new(MemFlash::<131072, 4096, 8>::default()));
425 let state = BlockingPartition::new(&flash, 0, 4096);
426 let dfu = BlockingPartition::new(&flash, 65536, 65536);
427 let mut aligned = [0; 8];
428
429 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
430 let mut to_write = [0; 4096];
431 to_write[..7].copy_from_slice(update.as_slice());
432
433 let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned);
434 let mut offset = 0;
435 for chunk in to_write.chunks(1024) {
436 updater.write_firmware(offset, chunk).unwrap();
437 offset += chunk.len();
438 }
439 let mut chunk_buf = [0; 2];
440 let mut hash = [0; 20];
441 updater
442 .hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)
443 .unwrap();
444
445 assert_eq!(Sha1::digest(update).as_slice(), hash);
446 }
447
448 #[test]
449 fn can_verify_sha1_sector_smaller_than_chunk() {
450 let flash = Mutex::<NoopRawMutex, _>::new(RefCell::new(MemFlash::<131072, 1024, 8>::default()));
451 let state = BlockingPartition::new(&flash, 0, 4096);
452 let dfu = BlockingPartition::new(&flash, 65536, 65536);
453 let mut aligned = [0; 8];
454
455 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
456 let mut to_write = [0; 4096];
457 to_write[..7].copy_from_slice(update.as_slice());
458
459 let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned);
460 let mut offset = 0;
461 for chunk in to_write.chunks(2048) {
462 updater.write_firmware(offset, chunk).unwrap();
463 offset += chunk.len();
464 }
465 let mut chunk_buf = [0; 2];
466 let mut hash = [0; 20];
467 updater
468 .hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)
469 .unwrap();
470
471 assert_eq!(Sha1::digest(update).as_slice(), hash);
472 }
473
474 #[test]
475 fn can_verify_sha1_cross_sector_boundary() {
476 let flash = Mutex::<NoopRawMutex, _>::new(RefCell::new(MemFlash::<131072, 1024, 8>::default()));
477 let state = BlockingPartition::new(&flash, 0, 4096);
478 let dfu = BlockingPartition::new(&flash, 65536, 65536);
479 let mut aligned = [0; 8];
480
481 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
482 let mut to_write = [0; 4096];
483 to_write[..7].copy_from_slice(update.as_slice());
484
485 let mut updater = BlockingFirmwareUpdater::new(FirmwareUpdaterConfig { dfu, state }, &mut aligned);
486 let mut offset = 0;
487 for chunk in to_write.chunks(896) {
488 updater.write_firmware(offset, chunk).unwrap();
489 offset += chunk.len();
490 }
491 let mut chunk_buf = [0; 2];
492 let mut hash = [0; 20];
493 updater
494 .hash::<Sha1>(update.len() as u32, &mut chunk_buf, &mut hash)
495 .unwrap();
496
497 assert_eq!(Sha1::digest(update).as_slice(), hash);
498 }
340} 499}
diff --git a/embassy-boot/src/firmware_updater/mod.rs b/embassy-boot/src/firmware_updater/mod.rs
index 4814786bf..4c4f4f10b 100644
--- a/embassy-boot/src/firmware_updater/mod.rs
+++ b/embassy-boot/src/firmware_updater/mod.rs
@@ -8,7 +8,7 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
8/// Firmware updater flash configuration holding the two flashes used by the updater 8/// Firmware updater flash configuration holding the two flashes used by the updater
9/// 9///
10/// If only a single flash is actually used, then that flash should be partitioned into two partitions before use. 10/// If only a single flash is actually used, then that flash should be partitioned into two partitions before use.
11/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition 11/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile_blocking`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition
12/// the provided flash according to symbols defined in the linkerfile. 12/// the provided flash according to symbols defined in the linkerfile.
13pub struct FirmwareUpdaterConfig<DFU, STATE> { 13pub struct FirmwareUpdaterConfig<DFU, STATE> {
14 /// The dfu flash partition 14 /// The dfu flash partition
diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs
index c9d58746a..5461fe04c 100644
--- a/embassy-executor-macros/src/lib.rs
+++ b/embassy-executor-macros/src/lib.rs
@@ -62,6 +62,13 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
62 task::run(&args.meta, f).unwrap_or_else(|x| x).into() 62 task::run(&args.meta, f).unwrap_or_else(|x| x).into()
63} 63}
64 64
65#[proc_macro_attribute]
66pub fn main_avr(args: TokenStream, item: TokenStream) -> TokenStream {
67 let args = syn::parse_macro_input!(args as Args);
68 let f = syn::parse_macro_input!(item as syn::ItemFn);
69 main::run(&args.meta, f, main::avr()).unwrap_or_else(|x| x).into()
70}
71
65/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task. 72/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
66/// 73///
67/// The following restrictions apply: 74/// The following restrictions apply:
diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs
index 3c0d58567..088e64d1c 100644
--- a/embassy-executor-macros/src/macros/main.rs
+++ b/embassy-executor-macros/src/macros/main.rs
@@ -12,6 +12,20 @@ struct Args {
12 entry: Option<String>, 12 entry: Option<String>,
13} 13}
14 14
15pub fn avr() -> TokenStream {
16 quote! {
17 #[avr_device::entry]
18 fn main() -> ! {
19 let mut executor = ::embassy_executor::Executor::new();
20 let executor = unsafe { __make_static(&mut executor) };
21
22 executor.run(|spawner| {
23 spawner.must_spawn(__embassy_main(spawner));
24 })
25 }
26 }
27}
28
15pub fn riscv(args: &[NestedMeta]) -> TokenStream { 29pub fn riscv(args: &[NestedMeta]) -> TokenStream {
16 let maybe_entry = match Args::from_list(args) { 30 let maybe_entry = match Args::from_list(args) {
17 Ok(args) => args.entry, 31 Ok(args) => args.entry,
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index b6b156c9f..431165cee 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -40,8 +40,7 @@ critical-section = "1.1"
40 40
41document-features = "0.2.7" 41document-features = "0.2.7"
42 42
43# needed for riscv 43# needed for AVR
44# remove when https://github.com/rust-lang/rust/pull/114499 is merged
45portable-atomic = { version = "1.5", optional = true } 44portable-atomic = { version = "1.5", optional = true }
46 45
47# arch-cortex-m dependencies 46# arch-cortex-m dependencies
@@ -51,6 +50,9 @@ cortex-m = { version = "0.7.6", optional = true }
51wasm-bindgen = { version = "0.2.82", optional = true } 50wasm-bindgen = { version = "0.2.82", optional = true }
52js-sys = { version = "0.3", optional = true } 51js-sys = { version = "0.3", optional = true }
53 52
53# arch-avr dependencies
54avr-device = { version = "0.5.3", optional = true }
55
54[dev-dependencies] 56[dev-dependencies]
55critical-section = { version = "1.1", features = ["std"] } 57critical-section = { version = "1.1", features = ["std"] }
56 58
@@ -75,9 +77,11 @@ arch-std = ["_arch", "critical-section/std"]
75## Cortex-M 77## Cortex-M
76arch-cortex-m = ["_arch", "dep:cortex-m"] 78arch-cortex-m = ["_arch", "dep:cortex-m"]
77## RISC-V 32 79## RISC-V 32
78arch-riscv32 = ["_arch", "dep:portable-atomic"] 80arch-riscv32 = ["_arch"]
79## WASM 81## WASM
80arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] 82arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
83## AVR
84arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"]
81 85
82#! ### Executor 86#! ### Executor
83 87
@@ -88,11 +92,11 @@ executor-interrupt = []
88 92
89#! ### Task Arena Size 93#! ### Task Arena Size
90#! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`. 94#! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`.
91#! 95#!
92#! <details> 96#! <details>
93#! <summary>Preconfigured Task Arena Sizes:</summary> 97#! <summary>Preconfigured Task Arena Sizes:</summary>
94#! <!-- rustdoc requires the following blank line for the feature list to render correctly! --> 98#! <!-- rustdoc requires the following blank line for the feature list to render correctly! -->
95#! 99#!
96 100
97# BEGIN AUTOGENERATED CONFIG FEATURES 101# BEGIN AUTOGENERATED CONFIG FEATURES
98# Generated by gen_config.py. DO NOT EDIT. 102# Generated by gen_config.py. DO NOT EDIT.
diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs
new file mode 100644
index 000000000..70085d04d
--- /dev/null
+++ b/embassy-executor/src/arch/avr.rs
@@ -0,0 +1,72 @@
1#[cfg(feature = "executor-interrupt")]
2compile_error!("`executor-interrupt` is not supported with `arch-avr`.");
3
4#[cfg(feature = "executor-thread")]
5pub use thread::*;
6#[cfg(feature = "executor-thread")]
7mod thread {
8 use core::marker::PhantomData;
9
10 pub use embassy_executor_macros::main_avr as main;
11 use portable_atomic::{AtomicBool, Ordering};
12
13 use crate::{raw, Spawner};
14
15 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
16
17 #[export_name = "__pender"]
18 fn __pender(_context: *mut ()) {
19 SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
20 }
21
22 /// avr Executor
23 pub struct Executor {
24 inner: raw::Executor,
25 not_send: PhantomData<*mut ()>,
26 }
27
28 impl Executor {
29 /// Create a new Executor.
30 pub fn new() -> Self {
31 Self {
32 inner: raw::Executor::new(core::ptr::null_mut()),
33 not_send: PhantomData,
34 }
35 }
36
37 /// Run the executor.
38 ///
39 /// The `init` closure is called with a [`Spawner`] that spawns tasks on
40 /// this executor. Use it to spawn the initial task(s). After `init` returns,
41 /// the executor starts running the tasks.
42 ///
43 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
44 /// for example by passing it as an argument to the initial tasks.
45 ///
46 /// This function requires `&'static mut self`. This means you have to store the
47 /// Executor instance in a place where it'll live forever and grants you mutable
48 /// access. There's a few ways to do this:
49 ///
50 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
51 /// - a `static mut` (unsafe)
52 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
53 ///
54 /// This function never returns.
55 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
56 init(self.inner.spawner());
57
58 loop {
59 unsafe {
60 avr_device::interrupt::disable();
61 if !SIGNAL_WORK_THREAD_MODE.swap(false, Ordering::SeqCst) {
62 avr_device::interrupt::enable();
63 avr_device::asm::sleep();
64 } else {
65 avr_device::interrupt::enable();
66 self.inner.poll();
67 }
68 }
69 }
70 }
71 }
72}
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index c56f502d3..01e63a9fd 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -6,9 +6,9 @@ pub use thread::*;
6#[cfg(feature = "executor-thread")] 6#[cfg(feature = "executor-thread")]
7mod thread { 7mod thread {
8 use core::marker::PhantomData; 8 use core::marker::PhantomData;
9 use core::sync::atomic::{AtomicBool, Ordering};
9 10
10 pub use embassy_executor_macros::main_riscv as main; 11 pub use embassy_executor_macros::main_riscv as main;
11 use portable_atomic::{AtomicBool, Ordering};
12 12
13 use crate::{raw, Spawner}; 13 use crate::{raw, Spawner};
14 14
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index eea118ade..6a2e493a2 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -23,9 +23,10 @@ macro_rules! check_at_most_one {
23 check_at_most_one!(@amo [$($f)*] [$($f)*] []); 23 check_at_most_one!(@amo [$($f)*] [$($f)*] []);
24 }; 24 };
25} 25}
26check_at_most_one!("arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); 26check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",);
27 27
28#[cfg(feature = "_arch")] 28#[cfg(feature = "_arch")]
29#[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")]
29#[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")] 30#[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")]
30#[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] 31#[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")]
31#[cfg_attr(feature = "arch-std", path = "arch/std.rs")] 32#[cfg_attr(feature = "arch-std", path = "arch/std.rs")]
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 3f00be4a8..3d5e3ab9f 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -581,6 +581,15 @@ impl embassy_time_queue_driver::TimerQueue for TimerQueue {
581#[cfg(feature = "integrated-timers")] 581#[cfg(feature = "integrated-timers")]
582embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); 582embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue);
583 583
584#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))]
585const fn gcd(a: u64, b: u64) -> u64 {
586 if b == 0 {
587 a
588 } else {
589 gcd(b, a % b)
590 }
591}
592
584#[cfg(feature = "rtos-trace")] 593#[cfg(feature = "rtos-trace")]
585impl rtos_trace::RtosTraceOSCallbacks for Executor { 594impl rtos_trace::RtosTraceOSCallbacks for Executor {
586 fn task_list() { 595 fn task_list() {
@@ -588,7 +597,8 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor {
588 } 597 }
589 #[cfg(feature = "integrated-timers")] 598 #[cfg(feature = "integrated-timers")]
590 fn time() -> u64 { 599 fn time() -> u64 {
591 Instant::now().as_micros() 600 const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000);
601 embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M)
592 } 602 }
593 #[cfg(not(feature = "integrated-timers"))] 603 #[cfg(not(feature = "integrated-timers"))]
594 fn time() -> u64 { 604 fn time() -> u64 {
diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs
index b4f2cec28..34ceac852 100644
--- a/embassy-hal-internal/src/atomic_ring_buffer.rs
+++ b/embassy-hal-internal/src/atomic_ring_buffer.rs
@@ -1,6 +1,6 @@
1//! Atomic reusable ringbuffer. 1//! Atomic reusable ringbuffer.
2use core::slice;
3use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; 2use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
3use core::{ptr, slice};
4 4
5/// Atomic reusable ringbuffer 5/// Atomic reusable ringbuffer
6/// 6///
@@ -73,6 +73,7 @@ impl RingBuffer {
73 pub unsafe fn deinit(&self) { 73 pub unsafe fn deinit(&self) {
74 // Ordering: it's OK to use `Relaxed` because this is not called 74 // Ordering: it's OK to use `Relaxed` because this is not called
75 // concurrently with other methods. 75 // concurrently with other methods.
76 self.buf.store(ptr::null_mut(), Ordering::Relaxed);
76 self.len.store(0, Ordering::Relaxed); 77 self.len.store(0, Ordering::Relaxed);
77 self.start.store(0, Ordering::Relaxed); 78 self.start.store(0, Ordering::Relaxed);
78 self.end.store(0, Ordering::Relaxed); 79 self.end.store(0, Ordering::Relaxed);
@@ -82,20 +83,46 @@ impl RingBuffer {
82 /// 83 ///
83 /// # Safety 84 /// # Safety
84 /// 85 ///
85 /// Only one reader can exist at a time. 86 /// - Only one reader can exist at a time.
87 /// - Ringbuffer must be initialized.
86 pub unsafe fn reader(&self) -> Reader<'_> { 88 pub unsafe fn reader(&self) -> Reader<'_> {
87 Reader(self) 89 Reader(self)
88 } 90 }
89 91
92 /// Try creating a reader, fails if not initialized.
93 ///
94 /// # Safety
95 ///
96 /// Only one reader can exist at a time.
97 pub unsafe fn try_reader(&self) -> Option<Reader<'_>> {
98 if self.buf.load(Ordering::Relaxed).is_null() {
99 return None;
100 }
101 Some(Reader(self))
102 }
103
90 /// Create a writer. 104 /// Create a writer.
91 /// 105 ///
92 /// # Safety 106 /// # Safety
93 /// 107 ///
94 /// Only one writer can exist at a time. 108 /// - Only one writer can exist at a time.
109 /// - Ringbuffer must be initialized.
95 pub unsafe fn writer(&self) -> Writer<'_> { 110 pub unsafe fn writer(&self) -> Writer<'_> {
96 Writer(self) 111 Writer(self)
97 } 112 }
98 113
114 /// Try creating a writer, fails if not initialized.
115 ///
116 /// # Safety
117 ///
118 /// Only one writer can exist at a time.
119 pub unsafe fn try_writer(&self) -> Option<Writer<'_>> {
120 if self.buf.load(Ordering::Relaxed).is_null() {
121 return None;
122 }
123 Some(Writer(self))
124 }
125
99 /// Return length of buffer. 126 /// Return length of buffer.
100 pub fn len(&self) -> usize { 127 pub fn len(&self) -> usize {
101 self.len.load(Ordering::Relaxed) 128 self.len.load(Ordering::Relaxed)
diff --git a/embassy-hal-internal/src/peripheral.rs b/embassy-hal-internal/src/peripheral.rs
index 16d49edfb..f03f41507 100644
--- a/embassy-hal-internal/src/peripheral.rs
+++ b/embassy-hal-internal/src/peripheral.rs
@@ -1,5 +1,5 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::ops::{Deref, DerefMut}; 2use core::ops::Deref;
3 3
4/// An exclusive reference to a peripheral. 4/// An exclusive reference to a peripheral.
5/// 5///
@@ -86,13 +86,6 @@ impl<'a, T> Deref for PeripheralRef<'a, T> {
86 } 86 }
87} 87}
88 88
89impl<'a, T> DerefMut for PeripheralRef<'a, T> {
90 #[inline]
91 fn deref_mut(&mut self) -> &mut Self::Target {
92 &mut self.inner
93 }
94}
95
96/// Trait for any type that can be used as a peripheral of type `P`. 89/// Trait for any type that can be used as a peripheral of type `P`.
97/// 90///
98/// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`), 91/// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`),
@@ -162,7 +155,7 @@ pub trait Peripheral: Sized {
162 } 155 }
163} 156}
164 157
165impl<'b, T: DerefMut> Peripheral for T 158impl<'b, T: Deref> Peripheral for T
166where 159where
167 T::Target: Peripheral, 160 T::Target: Peripheral,
168{ 161{
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 44bd2e8f3..be9f1d784 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -16,11 +16,11 @@ categories = [
16[package.metadata.embassy_docs] 16[package.metadata.embassy_docs]
17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" 17src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" 18src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
19features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp"] 19features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
20target = "thumbv7em-none-eabi" 20target = "thumbv7em-none-eabi"
21 21
22[package.metadata.docs.rs] 22[package.metadata.docs.rs]
23features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp"] 23features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
24 24
25[features] 25[features]
26default = [] 26default = []
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 72b0677b4..57c9b7a04 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -342,7 +342,7 @@ impl<'a> TcpSocket<'a> {
342 self.io.with(|s, _| s.may_send()) 342 self.io.with(|s, _| s.may_send())
343 } 343 }
344 344
345 /// return whether the recieve half of the full-duplex connection is open. 345 /// return whether the receive half of the full-duplex connection is open.
346 /// This function returns true if it’s possible to receive data from the remote endpoint. 346 /// This function returns true if it’s possible to receive data from the remote endpoint.
347 /// It will return true while there is data in the receive buffer, and if there isn’t, 347 /// It will return true while there is data in the receive buffer, and if there isn’t,
348 /// as long as the remote endpoint has not closed the connection. 348 /// as long as the remote endpoint has not closed the connection.
@@ -471,7 +471,7 @@ impl<'d> TcpIo<'d> {
471 s.register_recv_waker(cx.waker()); 471 s.register_recv_waker(cx.waker());
472 Poll::Pending 472 Poll::Pending
473 } else { 473 } else {
474 // if we can't receive because the recieve half of the duplex connection is closed then return an error 474 // if we can't receive because the receive half of the duplex connection is closed then return an error
475 Poll::Ready(Err(Error::ConnectionReset)) 475 Poll::Ready(Err(Error::ConnectionReset))
476 } 476 }
477 } else { 477 } else {
@@ -491,10 +491,16 @@ impl<'d> TcpIo<'d> {
491 async fn flush(&mut self) -> Result<(), Error> { 491 async fn flush(&mut self) -> Result<(), Error> {
492 poll_fn(move |cx| { 492 poll_fn(move |cx| {
493 self.with_mut(|s, _| { 493 self.with_mut(|s, _| {
494 let waiting_close = s.state() == tcp::State::Closed && s.remote_endpoint().is_some(); 494 let data_pending = s.send_queue() > 0;
495 let fin_pending = matches!(
496 s.state(),
497 tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck
498 );
499 let rst_pending = s.state() == tcp::State::Closed && s.remote_endpoint().is_some();
500
495 // If there are outstanding send operations, register for wake up and wait 501 // If there are outstanding send operations, register for wake up and wait
496 // smoltcp issues wake-ups when octets are dequeued from the send buffer 502 // smoltcp issues wake-ups when octets are dequeued from the send buffer
497 if s.send_queue() > 0 || waiting_close { 503 if data_pending || fin_pending || rst_pending {
498 s.register_send_waker(cx.waker()); 504 s.register_send_waker(cx.waker());
499 Poll::Pending 505 Poll::Pending
500 // No outstanding sends, socket is flushed 506 // No outstanding sends, socket is flushed
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 10f268b51..0045d9f97 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -15,6 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s
15 15
16features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] 16features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"]
17flavors = [ 17flavors = [
18 { regex_feature = "nrf51", target = "thumbv6m-none-eabi" },
18 { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, 19 { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" },
19 { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, 20 { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" },
20 { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, 21 { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" },
@@ -28,6 +29,7 @@ rustdoc-args = ["--cfg", "docsrs"]
28default = ["rt"] 29default = ["rt"]
29## Cortex-M runtime (enabled by default) 30## Cortex-M runtime (enabled by default)
30rt = [ 31rt = [
32 "nrf51-pac?/rt",
31 "nrf52805-pac?/rt", 33 "nrf52805-pac?/rt",
32 "nrf52810-pac?/rt", 34 "nrf52810-pac?/rt",
33 "nrf52811-pac?/rt", 35 "nrf52811-pac?/rt",
@@ -71,6 +73,8 @@ reset-pin-as-gpio = []
71qspi-multiwrite-flash = [] 73qspi-multiwrite-flash = []
72 74
73#! ### Chip selection features 75#! ### Chip selection features
76## nRF51
77nrf51 = ["nrf51-pac", "_nrf51"]
74## nRF52805 78## nRF52805
75nrf52805 = ["nrf52805-pac", "_nrf52"] 79nrf52805 = ["nrf52805-pac", "_nrf52"]
76## nRF52810 80## nRF52810
@@ -104,6 +108,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
104_nrf5340 = ["_gpio-p1", "_dppi"] 108_nrf5340 = ["_gpio-p1", "_dppi"]
105_nrf9160 = ["nrf9160-pac", "_dppi"] 109_nrf9160 = ["nrf9160-pac", "_dppi"]
106_nrf52 = ["_ppi"] 110_nrf52 = ["_ppi"]
111_nrf51 = ["_ppi"]
107 112
108_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] 113_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
109 114
@@ -133,6 +138,7 @@ embedded-io = { version = "0.6.0" }
133embedded-io-async = { version = "0.6.1" } 138embedded-io-async = { version = "0.6.1" }
134 139
135defmt = { version = "0.3", optional = true } 140defmt = { version = "0.3", optional = true }
141bitflags = "2.4.2"
136log = { version = "0.4.14", optional = true } 142log = { version = "0.4.14", optional = true }
137cortex-m-rt = ">=0.6.15,<0.8" 143cortex-m-rt = ">=0.6.15,<0.8"
138cortex-m = "0.7.6" 144cortex-m = "0.7.6"
@@ -140,10 +146,11 @@ critical-section = "1.1"
140rand_core = "0.6.3" 146rand_core = "0.6.3"
141fixed = "1.10.0" 147fixed = "1.10.0"
142embedded-storage = "0.3.1" 148embedded-storage = "0.3.1"
143embedded-storage-async = "0.4.0" 149embedded-storage-async = "0.4.1"
144cfg-if = "1.0.0" 150cfg-if = "1.0.0"
145document-features = "0.2.7" 151document-features = "0.2.7"
146 152
153nrf51-pac = { version = "0.12.0", optional = true }
147nrf52805-pac = { version = "0.12.0", optional = true } 154nrf52805-pac = { version = "0.12.0", optional = true }
148nrf52810-pac = { version = "0.12.0", optional = true } 155nrf52810-pac = { version = "0.12.0", optional = true }
149nrf52811-pac = { version = "0.12.0", optional = true } 156nrf52811-pac = { version = "0.12.0", optional = true }
diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md
index 50662749d..3df5f1fa5 100644
--- a/embassy-nrf/README.md
+++ b/embassy-nrf/README.md
@@ -14,11 +14,12 @@ For a complete list of available peripherals and features, see the [embassy-nrf
14 14
15The `embassy-nrf` HAL supports most variants of the nRF family: 15The `embassy-nrf` HAL supports most variants of the nRF family:
16 16
17* nRF51 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf51))
17* nRF52 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840)) 18* nRF52 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840))
18* nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340)) 19* nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340))
19* nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160)) 20* nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160))
20 21
21Most peripherals are supported. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf). 22Most peripherals are supported, but can vary between chip families. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf).
22 23
23For MCUs with TrustZone support, both Secure (S) and Non-Secure (NS) modes are supported. Running in Secure mode 24For MCUs with TrustZone support, both Secure (S) and Non-Secure (NS) modes are supported. Running in Secure mode
24allows running Rust code without a SPM or TF-M binary, saving flash space and simplifying development. 25allows running Rust code without a SPM or TF-M binary, saving flash space and simplifying development.
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 2c620798d..b04c96e09 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -17,29 +17,26 @@ use core::task::Poll;
17 17
18use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 18use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
19use embassy_hal_internal::{into_ref, PeripheralRef}; 19use embassy_hal_internal::{into_ref, PeripheralRef};
20use embassy_sync::waitqueue::AtomicWaker;
21// Re-export SVD variants to allow user to directly set values 20// Re-export SVD variants to allow user to directly set values
22pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 21pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
23 22
24use crate::gpio::sealed::Pin; 23use crate::gpio::sealed::Pin;
25use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 24use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
26use crate::interrupt::typelevel::Interrupt; 25use crate::interrupt::typelevel::Interrupt;
27use crate::ppi::{ 26use crate::ppi::{
28 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, 27 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
29}; 28};
30use crate::timer::{Instance as TimerInstance, Timer}; 29use crate::timer::{Instance as TimerInstance, Timer};
31use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; 30use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance};
32use crate::{interrupt, pac, Peripheral}; 31use crate::{interrupt, pac, Peripheral};
33 32
34mod sealed { 33mod sealed {
35 use super::*; 34 use super::*;
36 35
37 pub struct State { 36 pub struct State {
38 pub tx_waker: AtomicWaker,
39 pub tx_buf: RingBuffer, 37 pub tx_buf: RingBuffer,
40 pub tx_count: AtomicUsize, 38 pub tx_count: AtomicUsize,
41 39
42 pub rx_waker: AtomicWaker,
43 pub rx_buf: RingBuffer, 40 pub rx_buf: RingBuffer,
44 pub rx_started: AtomicBool, 41 pub rx_started: AtomicBool,
45 pub rx_started_count: AtomicU8, 42 pub rx_started_count: AtomicU8,
@@ -61,11 +58,9 @@ pub(crate) use sealed::State;
61impl State { 58impl State {
62 pub(crate) const fn new() -> Self { 59 pub(crate) const fn new() -> Self {
63 Self { 60 Self {
64 tx_waker: AtomicWaker::new(),
65 tx_buf: RingBuffer::new(), 61 tx_buf: RingBuffer::new(),
66 tx_count: AtomicUsize::new(0), 62 tx_count: AtomicUsize::new(0),
67 63
68 rx_waker: AtomicWaker::new(),
69 rx_buf: RingBuffer::new(), 64 rx_buf: RingBuffer::new(),
70 rx_started: AtomicBool::new(false), 65 rx_started: AtomicBool::new(false),
71 rx_started_count: AtomicU8::new(0), 66 rx_started_count: AtomicU8::new(0),
@@ -84,128 +79,131 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
84 unsafe fn on_interrupt() { 79 unsafe fn on_interrupt() {
85 //trace!("irq: start"); 80 //trace!("irq: start");
86 let r = U::regs(); 81 let r = U::regs();
82 let ss = U::state();
87 let s = U::buffered_state(); 83 let s = U::buffered_state();
88 84
89 let buf_len = s.rx_buf.len(); 85 if let Some(mut rx) = unsafe { s.rx_buf.try_writer() } {
90 let half_len = buf_len / 2; 86 let buf_len = s.rx_buf.len();
91 let mut tx = unsafe { s.tx_buf.reader() }; 87 let half_len = buf_len / 2;
92 let mut rx = unsafe { s.rx_buf.writer() };
93 88
94 if r.events_error.read().bits() != 0 { 89 if r.events_error.read().bits() != 0 {
95 r.events_error.reset(); 90 r.events_error.reset();
96 let errs = r.errorsrc.read(); 91 let errs = r.errorsrc.read();
97 r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) }); 92 r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) });
98 93
99 if errs.overrun().bit() { 94 if errs.overrun().bit() {
100 panic!("BufferedUarte overrun"); 95 panic!("BufferedUarte overrun");
96 }
101 } 97 }
102 }
103 98
104 // Received some bytes, wake task. 99 // Received some bytes, wake task.
105 if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 { 100 if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 {
106 r.intenclr.write(|w| w.rxdrdy().clear()); 101 r.intenclr.write(|w| w.rxdrdy().clear());
107 r.events_rxdrdy.reset(); 102 r.events_rxdrdy.reset();
108 s.rx_waker.wake(); 103 ss.rx_waker.wake();
109 } 104 }
110 105
111 if r.events_endrx.read().bits() != 0 { 106 if r.events_endrx.read().bits() != 0 {
112 //trace!(" irq_rx: endrx"); 107 //trace!(" irq_rx: endrx");
113 r.events_endrx.reset(); 108 r.events_endrx.reset();
114 109
115 let val = s.rx_ended_count.load(Ordering::Relaxed); 110 let val = s.rx_ended_count.load(Ordering::Relaxed);
116 s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); 111 s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
117 } 112 }
118 113
119 if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) { 114 if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) {
120 //trace!(" irq_rx: rxstarted"); 115 //trace!(" irq_rx: rxstarted");
121 let (ptr, len) = rx.push_buf(); 116 let (ptr, len) = rx.push_buf();
122 if len >= half_len { 117 if len >= half_len {
123 r.events_rxstarted.reset(); 118 r.events_rxstarted.reset();
124 119
125 //trace!(" irq_rx: starting second {:?}", half_len); 120 //trace!(" irq_rx: starting second {:?}", half_len);
126 121
127 // Set up the DMA read 122 // Set up the DMA read
128 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); 123 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
129 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); 124 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
130 125
131 let chn = s.rx_ppi_ch.load(Ordering::Relaxed); 126 let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
132 127
133 // Enable endrx -> startrx PPI channel. 128 // Enable endrx -> startrx PPI channel.
134 // From this point on, if endrx happens, startrx is automatically fired. 129 // From this point on, if endrx happens, startrx is automatically fired.
135 ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); 130 ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
136 131
137 // It is possible that endrx happened BEFORE enabling the PPI. In this case 132 // It is possible that endrx happened BEFORE enabling the PPI. In this case
138 // the PPI channel doesn't trigger, and we'd hang. We have to detect this 133 // the PPI channel doesn't trigger, and we'd hang. We have to detect this
139 // and manually start. 134 // and manually start.
140 135
141 // check again in case endrx has happened between the last check and now. 136 // check again in case endrx has happened between the last check and now.
142 if r.events_endrx.read().bits() != 0 { 137 if r.events_endrx.read().bits() != 0 {
143 //trace!(" irq_rx: endrx"); 138 //trace!(" irq_rx: endrx");
144 r.events_endrx.reset(); 139 r.events_endrx.reset();
145 140
146 let val = s.rx_ended_count.load(Ordering::Relaxed); 141 let val = s.rx_ended_count.load(Ordering::Relaxed);
147 s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); 142 s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
148 } 143 }
149 144
150 let rx_ended = s.rx_ended_count.load(Ordering::Relaxed); 145 let rx_ended = s.rx_ended_count.load(Ordering::Relaxed);
151 let rx_started = s.rx_started_count.load(Ordering::Relaxed); 146 let rx_started = s.rx_started_count.load(Ordering::Relaxed);
152 147
153 // If we started the same amount of transfers as ended, the last rxend has 148 // If we started the same amount of transfers as ended, the last rxend has
154 // already occured. 149 // already occured.
155 let rxend_happened = rx_started == rx_ended; 150 let rxend_happened = rx_started == rx_ended;
156 151
157 // Check if the PPI channel is still enabled. The PPI channel disables itself 152 // Check if the PPI channel is still enabled. The PPI channel disables itself
158 // when it fires, so if it's still enabled it hasn't fired. 153 // when it fires, so if it's still enabled it hasn't fired.
159 let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0; 154 let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0;
160 155
161 // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed. 156 // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed.
162 // this condition also naturally matches if `!started`, needed to kickstart the DMA. 157 // this condition also naturally matches if `!started`, needed to kickstart the DMA.
163 if rxend_happened && ppi_ch_enabled { 158 if rxend_happened && ppi_ch_enabled {
164 //trace!("manually starting."); 159 //trace!("manually starting.");
165 160
166 // disable the ppi ch, it's of no use anymore. 161 // disable the ppi ch, it's of no use anymore.
167 ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) }); 162 ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) });
168 163
169 // manually start 164 // manually start
170 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 165 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
171 } 166 }
172 167
173 rx.push_done(half_len); 168 rx.push_done(half_len);
174 169
175 s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed); 170 s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed);
176 s.rx_started.store(true, Ordering::Relaxed); 171 s.rx_started.store(true, Ordering::Relaxed);
177 } else { 172 } else {
178 //trace!(" irq_rx: rxstarted no buf"); 173 //trace!(" irq_rx: rxstarted no buf");
179 r.intenclr.write(|w| w.rxstarted().clear()); 174 r.intenclr.write(|w| w.rxstarted().clear());
175 }
180 } 176 }
181 } 177 }
182 178
183 // ============================= 179 // =============================
184 180
185 // TX end 181 if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } {
186 if r.events_endtx.read().bits() != 0 { 182 // TX end
187 r.events_endtx.reset(); 183 if r.events_endtx.read().bits() != 0 {
184 r.events_endtx.reset();
188 185
189 let n = s.tx_count.load(Ordering::Relaxed); 186 let n = s.tx_count.load(Ordering::Relaxed);
190 //trace!(" irq_tx: endtx {:?}", n); 187 //trace!(" irq_tx: endtx {:?}", n);
191 tx.pop_done(n); 188 tx.pop_done(n);
192 s.tx_waker.wake(); 189 ss.tx_waker.wake();
193 s.tx_count.store(0, Ordering::Relaxed); 190 s.tx_count.store(0, Ordering::Relaxed);
194 } 191 }
195 192
196 // If not TXing, start. 193 // If not TXing, start.
197 if s.tx_count.load(Ordering::Relaxed) == 0 { 194 if s.tx_count.load(Ordering::Relaxed) == 0 {
198 let (ptr, len) = tx.pop_buf(); 195 let (ptr, len) = tx.pop_buf();
199 if len != 0 { 196 if len != 0 {
200 //trace!(" irq_tx: starting {:?}", len); 197 //trace!(" irq_tx: starting {:?}", len);
201 s.tx_count.store(len, Ordering::Relaxed); 198 s.tx_count.store(len, Ordering::Relaxed);
202 199
203 // Set up the DMA write 200 // Set up the DMA write
204 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); 201 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
205 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 202 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
206 203
207 // Start UARTE Transmit transaction 204 // Start UARTE Transmit transaction
208 r.tasks_starttx.write(|w| unsafe { w.bits(1) }); 205 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
206 }
209 } 207 }
210 } 208 }
211 209
@@ -215,11 +213,8 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
215 213
216/// Buffered UARTE driver. 214/// Buffered UARTE driver.
217pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { 215pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
218 _peri: PeripheralRef<'d, U>, 216 tx: BufferedUarteTx<'d, U>,
219 timer: Timer<'d, T>, 217 rx: BufferedUarteRx<'d, U, T>,
220 _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>,
221 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>,
222 _ppi_group: PpiGroup<'d, AnyGroup>,
223} 218}
224 219
225impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} 220impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
@@ -243,7 +238,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
243 rx_buffer: &'d mut [u8], 238 rx_buffer: &'d mut [u8],
244 tx_buffer: &'d mut [u8], 239 tx_buffer: &'d mut [u8],
245 ) -> Self { 240 ) -> Self {
246 into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group); 241 into_ref!(uarte, timer, rxd, txd, ppi_ch1, ppi_ch2, ppi_group);
247 Self::new_inner( 242 Self::new_inner(
248 uarte, 243 uarte,
249 timer, 244 timer,
@@ -280,7 +275,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
280 rx_buffer: &'d mut [u8], 275 rx_buffer: &'d mut [u8],
281 tx_buffer: &'d mut [u8], 276 tx_buffer: &'d mut [u8],
282 ) -> Self { 277 ) -> Self {
283 into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); 278 into_ref!(uarte, timer, rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group);
284 Self::new_inner( 279 Self::new_inner(
285 uarte, 280 uarte,
286 timer, 281 timer,
@@ -298,8 +293,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
298 } 293 }
299 294
300 fn new_inner( 295 fn new_inner(
301 peri: impl Peripheral<P = U> + 'd, 296 peri: PeripheralRef<'d, U>,
302 timer: impl Peripheral<P = T> + 'd, 297 timer: PeripheralRef<'d, T>,
303 ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, 298 ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>,
304 ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, 299 ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>,
305 ppi_group: PeripheralRef<'d, AnyGroup>, 300 ppi_group: PeripheralRef<'d, AnyGroup>,
@@ -311,16 +306,127 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
311 rx_buffer: &'d mut [u8], 306 rx_buffer: &'d mut [u8],
312 tx_buffer: &'d mut [u8], 307 tx_buffer: &'d mut [u8],
313 ) -> Self { 308 ) -> Self {
314 into_ref!(peri, timer); 309 configure(U::regs(), config, cts.is_some());
315 310
316 assert!(rx_buffer.len() % 2 == 0); 311 let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer);
312 let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer);
317 313
314 U::Interrupt::pend();
315 unsafe { U::Interrupt::enable() };
316
317 U::state().tx_rx_refcount.store(2, Ordering::Relaxed);
318
319 Self { tx, rx }
320 }
321
322 /// Adjust the baud rate to the provided value.
323 pub fn set_baudrate(&mut self, baudrate: Baudrate) {
318 let r = U::regs(); 324 let r = U::regs();
325 r.baudrate.write(|w| w.baudrate().variant(baudrate));
326 }
319 327
320 let hwfc = cts.is_some(); 328 /// Split the UART in reader and writer parts.
329 ///
330 /// This allows reading and writing concurrently from independent tasks.
331 pub fn split(self) -> (BufferedUarteRx<'d, U, T>, BufferedUarteTx<'d, U>) {
332 (self.rx, self.tx)
333 }
321 334
322 rxd.conf().write(|w| w.input().connect().drive().h0h1()); 335 /// Split the UART in reader and writer parts, by reference.
323 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); 336 ///
337 /// The returned halves borrow from `self`, so you can drop them and go back to using
338 /// the "un-split" `self`. This allows temporarily splitting the UART.
339 pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d, U, T>, &mut BufferedUarteTx<'d, U>) {
340 (&mut self.rx, &mut self.tx)
341 }
342
343 /// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
344 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
345 self.rx.read(buf).await
346 }
347
348 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
349 pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
350 self.rx.fill_buf().await
351 }
352
353 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
354 pub fn consume(&mut self, amt: usize) {
355 self.rx.consume(amt)
356 }
357
358 /// Write a buffer into this writer, returning how many bytes were written.
359 pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
360 self.tx.write(buf).await
361 }
362
363 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
364 pub async fn flush(&mut self) -> Result<(), Error> {
365 self.tx.flush().await
366 }
367}
368
369/// Reader part of the buffered UARTE driver.
370pub struct BufferedUarteTx<'d, U: UarteInstance> {
371 _peri: PeripheralRef<'d, U>,
372}
373
374impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
375 /// Create a new BufferedUarteTx without hardware flow control.
376 pub fn new(
377 uarte: impl Peripheral<P = U> + 'd,
378 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
379 txd: impl Peripheral<P = impl GpioPin> + 'd,
380 config: Config,
381 tx_buffer: &'d mut [u8],
382 ) -> Self {
383 into_ref!(uarte, txd);
384 Self::new_inner(uarte, txd.map_into(), None, config, tx_buffer)
385 }
386
387 /// Create a new BufferedUarte with hardware flow control (RTS/CTS)
388 ///
389 /// # Panics
390 ///
391 /// Panics if `rx_buffer.len()` is odd.
392 pub fn new_with_cts(
393 uarte: impl Peripheral<P = U> + 'd,
394 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
395 txd: impl Peripheral<P = impl GpioPin> + 'd,
396 cts: impl Peripheral<P = impl GpioPin> + 'd,
397 config: Config,
398 tx_buffer: &'d mut [u8],
399 ) -> Self {
400 into_ref!(uarte, txd, cts);
401 Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config, tx_buffer)
402 }
403
404 fn new_inner(
405 peri: PeripheralRef<'d, U>,
406 txd: PeripheralRef<'d, AnyPin>,
407 cts: Option<PeripheralRef<'d, AnyPin>>,
408 config: Config,
409 tx_buffer: &'d mut [u8],
410 ) -> Self {
411 configure(U::regs(), config, cts.is_some());
412
413 let this = Self::new_innerer(peri, txd, cts, tx_buffer);
414
415 U::Interrupt::pend();
416 unsafe { U::Interrupt::enable() };
417
418 U::state().tx_rx_refcount.store(1, Ordering::Relaxed);
419
420 this
421 }
422
423 fn new_innerer(
424 peri: PeripheralRef<'d, U>,
425 txd: PeripheralRef<'d, AnyPin>,
426 cts: Option<PeripheralRef<'d, AnyPin>>,
427 tx_buffer: &'d mut [u8],
428 ) -> Self {
429 let r = U::regs();
324 430
325 txd.set_high(); 431 txd.set_high();
326 txd.conf().write(|w| w.dir().output().drive().h0h1()); 432 txd.conf().write(|w| w.dir().output().drive().h0h1());
@@ -331,6 +437,203 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
331 } 437 }
332 r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); 438 r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
333 439
440 // Initialize state
441 let s = U::buffered_state();
442 s.tx_count.store(0, Ordering::Relaxed);
443 let len = tx_buffer.len();
444 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
445
446 r.events_txstarted.reset();
447
448 // Enable interrupts
449 r.intenset.write(|w| {
450 w.endtx().set();
451 w
452 });
453
454 Self { _peri: peri }
455 }
456
457 /// Write a buffer into this writer, returning how many bytes were written.
458 pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
459 poll_fn(move |cx| {
460 //trace!("poll_write: {:?}", buf.len());
461 let ss = U::state();
462 let s = U::buffered_state();
463 let mut tx = unsafe { s.tx_buf.writer() };
464
465 let tx_buf = tx.push_slice();
466 if tx_buf.is_empty() {
467 //trace!("poll_write: pending");
468 ss.tx_waker.register(cx.waker());
469 return Poll::Pending;
470 }
471
472 let n = min(tx_buf.len(), buf.len());
473 tx_buf[..n].copy_from_slice(&buf[..n]);
474 tx.push_done(n);
475
476 //trace!("poll_write: queued {:?}", n);
477
478 compiler_fence(Ordering::SeqCst);
479 U::Interrupt::pend();
480
481 Poll::Ready(Ok(n))
482 })
483 .await
484 }
485
486 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
487 pub async fn flush(&mut self) -> Result<(), Error> {
488 poll_fn(move |cx| {
489 //trace!("poll_flush");
490 let ss = U::state();
491 let s = U::buffered_state();
492 if !s.tx_buf.is_empty() {
493 //trace!("poll_flush: pending");
494 ss.tx_waker.register(cx.waker());
495 return Poll::Pending;
496 }
497
498 Poll::Ready(Ok(()))
499 })
500 .await
501 }
502}
503
504impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> {
505 fn drop(&mut self) {
506 let r = U::regs();
507
508 r.intenclr.write(|w| {
509 w.txdrdy().set_bit();
510 w.txstarted().set_bit();
511 w.txstopped().set_bit();
512 w
513 });
514 r.events_txstopped.reset();
515 r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
516 while r.events_txstopped.read().bits() == 0 {}
517
518 let s = U::buffered_state();
519 unsafe { s.tx_buf.deinit() }
520
521 let s = U::state();
522 drop_tx_rx(r, s);
523 }
524}
525
526/// Reader part of the buffered UARTE driver.
527pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> {
528 _peri: PeripheralRef<'d, U>,
529 timer: Timer<'d, T>,
530 _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>,
531 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>,
532 _ppi_group: PpiGroup<'d, AnyGroup>,
533}
534
535impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
536 /// Create a new BufferedUarte without hardware flow control.
537 ///
538 /// # Panics
539 ///
540 /// Panics if `rx_buffer.len()` is odd.
541 pub fn new(
542 uarte: impl Peripheral<P = U> + 'd,
543 timer: impl Peripheral<P = T> + 'd,
544 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
545 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
546 ppi_group: impl Peripheral<P = impl Group> + 'd,
547 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
548 rxd: impl Peripheral<P = impl GpioPin> + 'd,
549 config: Config,
550 rx_buffer: &'d mut [u8],
551 ) -> Self {
552 into_ref!(uarte, timer, rxd, ppi_ch1, ppi_ch2, ppi_group);
553 Self::new_inner(
554 uarte,
555 timer,
556 ppi_ch1.map_into(),
557 ppi_ch2.map_into(),
558 ppi_group.map_into(),
559 rxd.map_into(),
560 None,
561 config,
562 rx_buffer,
563 )
564 }
565
566 /// Create a new BufferedUarte with hardware flow control (RTS/CTS)
567 ///
568 /// # Panics
569 ///
570 /// Panics if `rx_buffer.len()` is odd.
571 pub fn new_with_rts(
572 uarte: impl Peripheral<P = U> + 'd,
573 timer: impl Peripheral<P = T> + 'd,
574 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
575 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
576 ppi_group: impl Peripheral<P = impl Group> + 'd,
577 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
578 rxd: impl Peripheral<P = impl GpioPin> + 'd,
579 rts: impl Peripheral<P = impl GpioPin> + 'd,
580 config: Config,
581 rx_buffer: &'d mut [u8],
582 ) -> Self {
583 into_ref!(uarte, timer, rxd, rts, ppi_ch1, ppi_ch2, ppi_group);
584 Self::new_inner(
585 uarte,
586 timer,
587 ppi_ch1.map_into(),
588 ppi_ch2.map_into(),
589 ppi_group.map_into(),
590 rxd.map_into(),
591 Some(rts.map_into()),
592 config,
593 rx_buffer,
594 )
595 }
596
597 fn new_inner(
598 peri: PeripheralRef<'d, U>,
599 timer: PeripheralRef<'d, T>,
600 ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>,
601 ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>,
602 ppi_group: PeripheralRef<'d, AnyGroup>,
603 rxd: PeripheralRef<'d, AnyPin>,
604 rts: Option<PeripheralRef<'d, AnyPin>>,
605 config: Config,
606 rx_buffer: &'d mut [u8],
607 ) -> Self {
608 configure(U::regs(), config, rts.is_some());
609
610 let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer);
611
612 U::Interrupt::pend();
613 unsafe { U::Interrupt::enable() };
614
615 U::state().tx_rx_refcount.store(1, Ordering::Relaxed);
616
617 this
618 }
619
620 fn new_innerer(
621 peri: PeripheralRef<'d, U>,
622 timer: PeripheralRef<'d, T>,
623 ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>,
624 ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>,
625 ppi_group: PeripheralRef<'d, AnyGroup>,
626 rxd: PeripheralRef<'d, AnyPin>,
627 rts: Option<PeripheralRef<'d, AnyPin>>,
628 rx_buffer: &'d mut [u8],
629 ) -> Self {
630 assert!(rx_buffer.len() % 2 == 0);
631
632 let r = U::regs();
633
634 rxd.conf().write(|w| w.input().connect().drive().h0h1());
635 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
636
334 if let Some(pin) = &rts { 637 if let Some(pin) = &rts {
335 pin.set_high(); 638 pin.set_high();
336 pin.conf().write(|w| w.dir().output().drive().h0h1()); 639 pin.conf().write(|w| w.dir().output().drive().h0h1());
@@ -339,35 +642,21 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
339 642
340 // Initialize state 643 // Initialize state
341 let s = U::buffered_state(); 644 let s = U::buffered_state();
342 s.tx_count.store(0, Ordering::Relaxed);
343 s.rx_started_count.store(0, Ordering::Relaxed); 645 s.rx_started_count.store(0, Ordering::Relaxed);
344 s.rx_ended_count.store(0, Ordering::Relaxed); 646 s.rx_ended_count.store(0, Ordering::Relaxed);
345 s.rx_started.store(false, Ordering::Relaxed); 647 s.rx_started.store(false, Ordering::Relaxed);
346 let len = tx_buffer.len();
347 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
348 let len = rx_buffer.len(); 648 let len = rx_buffer.len();
349 unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; 649 unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
350 650
351 // Configure
352 r.config.write(|w| {
353 w.hwfc().bit(hwfc);
354 w.parity().variant(config.parity);
355 w
356 });
357 r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
358
359 // clear errors 651 // clear errors
360 let errors = r.errorsrc.read().bits(); 652 let errors = r.errorsrc.read().bits();
361 r.errorsrc.write(|w| unsafe { w.bits(errors) }); 653 r.errorsrc.write(|w| unsafe { w.bits(errors) });
362 654
363 r.events_rxstarted.reset(); 655 r.events_rxstarted.reset();
364 r.events_txstarted.reset();
365 r.events_error.reset(); 656 r.events_error.reset();
366 r.events_endrx.reset(); 657 r.events_endrx.reset();
367 r.events_endtx.reset();
368 658
369 // Enable interrupts 659 // Enable interrupts
370 r.intenclr.write(|w| unsafe { w.bits(!0) });
371 r.intenset.write(|w| { 660 r.intenset.write(|w| {
372 w.endtx().set(); 661 w.endtx().set();
373 w.rxstarted().set(); 662 w.rxstarted().set();
@@ -376,10 +665,6 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
376 w 665 w
377 }); 666 });
378 667
379 // Enable UARTE instance
380 apply_workaround_for_enable_anomaly(&r);
381 r.enable.write(|w| w.enable().enabled());
382
383 // Configure byte counter. 668 // Configure byte counter.
384 let timer = Timer::new_counter(timer); 669 let timer = Timer::new_counter(timer);
385 timer.cc(1).write(rx_buffer.len() as u32 * 2); 670 timer.cc(1).write(rx_buffer.len() as u32 * 2);
@@ -401,9 +686,6 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
401 ppi_ch2.disable(); 686 ppi_ch2.disable();
402 ppi_group.add_channel(&ppi_ch2); 687 ppi_group.add_channel(&ppi_ch2);
403 688
404 U::Interrupt::pend();
405 unsafe { U::Interrupt::enable() };
406
407 Self { 689 Self {
408 _peri: peri, 690 _peri: peri,
409 timer, 691 timer,
@@ -413,80 +695,24 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
413 } 695 }
414 } 696 }
415 697
416 fn pend_irq() { 698 /// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
417 U::Interrupt::pend() 699 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
418 } 700 let data = self.fill_buf().await?;
419
420 /// Adjust the baud rate to the provided value.
421 pub fn set_baudrate(&mut self, baudrate: Baudrate) {
422 let r = U::regs();
423 r.baudrate.write(|w| w.baudrate().variant(baudrate));
424 }
425
426 /// Split the UART in reader and writer parts.
427 ///
428 /// This allows reading and writing concurrently from independent tasks.
429 pub fn split<'u>(&'u mut self) -> (BufferedUarteRx<'u, 'd, U, T>, BufferedUarteTx<'u, 'd, U, T>) {
430 (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self })
431 }
432
433 async fn inner_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
434 let data = self.inner_fill_buf().await?;
435 let n = data.len().min(buf.len()); 701 let n = data.len().min(buf.len());
436 buf[..n].copy_from_slice(&data[..n]); 702 buf[..n].copy_from_slice(&data[..n]);
437 self.inner_consume(n); 703 self.consume(n);
438 Ok(n) 704 Ok(n)
439 } 705 }
440 706
441 async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> { 707 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
442 poll_fn(move |cx| { 708 pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
443 //trace!("poll_write: {:?}", buf.len());
444 let s = U::buffered_state();
445 let mut tx = unsafe { s.tx_buf.writer() };
446
447 let tx_buf = tx.push_slice();
448 if tx_buf.is_empty() {
449 //trace!("poll_write: pending");
450 s.tx_waker.register(cx.waker());
451 return Poll::Pending;
452 }
453
454 let n = min(tx_buf.len(), buf.len());
455 tx_buf[..n].copy_from_slice(&buf[..n]);
456 tx.push_done(n);
457
458 //trace!("poll_write: queued {:?}", n);
459
460 compiler_fence(Ordering::SeqCst);
461 Self::pend_irq();
462
463 Poll::Ready(Ok(n))
464 })
465 .await
466 }
467
468 async fn inner_flush<'a>(&'a self) -> Result<(), Error> {
469 poll_fn(move |cx| {
470 //trace!("poll_flush");
471 let s = U::buffered_state();
472 if !s.tx_buf.is_empty() {
473 //trace!("poll_flush: pending");
474 s.tx_waker.register(cx.waker());
475 return Poll::Pending;
476 }
477
478 Poll::Ready(Ok(()))
479 })
480 .await
481 }
482
483 async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> {
484 poll_fn(move |cx| { 709 poll_fn(move |cx| {
485 compiler_fence(Ordering::SeqCst); 710 compiler_fence(Ordering::SeqCst);
486 //trace!("poll_read"); 711 //trace!("poll_read");
487 712
488 let r = U::regs(); 713 let r = U::regs();
489 let s = U::buffered_state(); 714 let s = U::buffered_state();
715 let ss = U::state();
490 716
491 // Read the RXDRDY counter. 717 // Read the RXDRDY counter.
492 T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) }); 718 T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) });
@@ -510,7 +736,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
510 let len = s.rx_buf.len(); 736 let len = s.rx_buf.len();
511 if start == end { 737 if start == end {
512 //trace!(" empty"); 738 //trace!(" empty");
513 s.rx_waker.register(cx.waker()); 739 ss.rx_waker.register(cx.waker());
514 r.intenset.write(|w| w.rxdrdy().set_bit()); 740 r.intenset.write(|w| w.rxdrdy().set_bit());
515 return Poll::Pending; 741 return Poll::Pending;
516 } 742 }
@@ -532,7 +758,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
532 .await 758 .await
533 } 759 }
534 760
535 fn inner_consume(&self, amt: usize) { 761 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
762 pub fn consume(&mut self, amt: usize) {
536 if amt == 0 { 763 if amt == 0 {
537 return; 764 return;
538 } 765 }
@@ -542,69 +769,31 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
542 rx.pop_done(amt); 769 rx.pop_done(amt);
543 U::regs().intenset.write(|w| w.rxstarted().set()); 770 U::regs().intenset.write(|w| w.rxstarted().set());
544 } 771 }
545
546 /// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
547 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
548 self.inner_read(buf).await
549 }
550
551 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
552 pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
553 self.inner_fill_buf().await
554 }
555
556 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
557 pub fn consume(&mut self, amt: usize) {
558 self.inner_consume(amt)
559 }
560
561 /// Write a buffer into this writer, returning how many bytes were written.
562 pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
563 self.inner_write(buf).await
564 }
565
566 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
567 pub async fn flush(&mut self) -> Result<(), Error> {
568 self.inner_flush().await
569 }
570} 772}
571 773
572/// Reader part of the buffered UARTE driver. 774impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> {
573pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> { 775 fn drop(&mut self) {
574 inner: &'u BufferedUarte<'d, U, T>, 776 self._ppi_group.disable_all();
575}
576
577impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'u, 'd, U, T> {
578 /// Write a buffer into this writer, returning how many bytes were written.
579 pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
580 self.inner.inner_write(buf).await
581 }
582 777
583 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. 778 let r = U::regs();
584 pub async fn flush(&mut self) -> Result<(), Error> {
585 self.inner.inner_flush().await
586 }
587}
588 779
589/// Writer part of the buffered UARTE driver. 780 self.timer.stop();
590pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> {
591 inner: &'u BufferedUarte<'d, U, T>,
592}
593 781
594impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'u, 'd, U, T> { 782 r.intenclr.write(|w| {
595 /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. 783 w.rxdrdy().set_bit();
596 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 784 w.rxstarted().set_bit();
597 self.inner.inner_read(buf).await 785 w.rxto().set_bit();
598 } 786 w
787 });
788 r.events_rxto.reset();
789 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
790 while r.events_rxto.read().bits() == 0 {}
599 791
600 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. 792 let s = U::buffered_state();
601 pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { 793 unsafe { s.rx_buf.deinit() }
602 self.inner.inner_fill_buf().await
603 }
604 794
605 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. 795 let s = U::state();
606 pub fn consume(&mut self, amt: usize) { 796 drop_tx_rx(r, s);
607 self.inner.inner_consume(amt)
608 } 797 }
609} 798}
610 799
@@ -621,95 +810,63 @@ mod _embedded_io {
621 type Error = Error; 810 type Error = Error;
622 } 811 }
623 812
624 impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteRx<'u, 'd, U, T> { 813 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteRx<'d, U, T> {
625 type Error = Error; 814 type Error = Error;
626 } 815 }
627 816
628 impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteTx<'u, 'd, U, T> { 817 impl<'d, U: UarteInstance> embedded_io_async::ErrorType for BufferedUarteTx<'d, U> {
629 type Error = Error; 818 type Error = Error;
630 } 819 }
631 820
632 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarte<'d, U, T> { 821 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarte<'d, U, T> {
633 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 822 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
634 self.inner_read(buf).await 823 self.read(buf).await
635 } 824 }
636 } 825 }
637 826
638 impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarteRx<'u, 'd, U, T> { 827 impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarteRx<'d, U, T> {
639 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 828 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
640 self.inner.inner_read(buf).await 829 self.read(buf).await
641 } 830 }
642 } 831 }
643 832
644 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> { 833 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> {
645 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 834 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
646 self.inner_fill_buf().await 835 self.fill_buf().await
647 } 836 }
648 837
649 fn consume(&mut self, amt: usize) { 838 fn consume(&mut self, amt: usize) {
650 self.inner_consume(amt) 839 self.consume(amt)
651 } 840 }
652 } 841 }
653 842
654 impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarteRx<'u, 'd, U, T> { 843 impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarteRx<'d, U, T> {
655 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 844 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
656 self.inner.inner_fill_buf().await 845 self.fill_buf().await
657 } 846 }
658 847
659 fn consume(&mut self, amt: usize) { 848 fn consume(&mut self, amt: usize) {
660 self.inner.inner_consume(amt) 849 self.consume(amt)
661 } 850 }
662 } 851 }
663 852
664 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarte<'d, U, T> { 853 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarte<'d, U, T> {
665 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 854 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
666 self.inner_write(buf).await 855 self.write(buf).await
667 } 856 }
668 857
669 async fn flush(&mut self) -> Result<(), Self::Error> { 858 async fn flush(&mut self) -> Result<(), Self::Error> {
670 self.inner_flush().await 859 self.flush().await
671 } 860 }
672 } 861 }
673 862
674 impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarteTx<'u, 'd, U, T> { 863 impl<'d: 'd, U: UarteInstance> embedded_io_async::Write for BufferedUarteTx<'d, U> {
675 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 864 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
676 self.inner.inner_write(buf).await 865 self.write(buf).await
677 } 866 }
678 867
679 async fn flush(&mut self) -> Result<(), Self::Error> { 868 async fn flush(&mut self) -> Result<(), Self::Error> {
680 self.inner.inner_flush().await 869 self.flush().await
681 }
682 }
683}
684
685impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarte<'a, U, T> {
686 fn drop(&mut self) {
687 self._ppi_group.disable_all();
688
689 let r = U::regs();
690
691 self.timer.stop();
692
693 r.inten.reset();
694 r.events_rxto.reset();
695 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
696 r.events_txstopped.reset();
697 r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
698
699 while r.events_txstopped.read().bits() == 0 {}
700 while r.events_rxto.read().bits() == 0 {}
701
702 r.enable.write(|w| w.enable().disabled());
703
704 gpio::deconfigure_pin(r.psel.rxd.read().bits());
705 gpio::deconfigure_pin(r.psel.txd.read().bits());
706 gpio::deconfigure_pin(r.psel.rts.read().bits());
707 gpio::deconfigure_pin(r.psel.cts.read().bits());
708
709 let s = U::buffered_state();
710 unsafe {
711 s.rx_buf.deinit();
712 s.tx_buf.deinit();
713 } 870 }
714 } 871 }
715} 872}
diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs
new file mode 100644
index 000000000..cc1cbc8a0
--- /dev/null
+++ b/embassy-nrf/src/chips/nrf51.rs
@@ -0,0 +1,174 @@
1pub use nrf51_pac as pac;
2
3/// The maximum buffer size that the EasyDMA can send/recv in one operation.
4pub const EASY_DMA_SIZE: usize = (1 << 14) - 1;
5
6pub const FLASH_SIZE: usize = 128 * 1024;
7
8embassy_hal_internal::peripherals! {
9 // RTC
10 RTC0,
11 RTC1,
12
13 // WDT
14 WDT,
15
16 // NVMC
17 NVMC,
18
19 // RNG
20 RNG,
21
22 // UARTE
23 UART0,
24
25 // SPI/TWI
26 TWI0,
27 SPI0,
28
29 // ADC
30 ADC,
31
32 // TIMER
33 TIMER0,
34 TIMER1,
35 TIMER2,
36
37 // GPIOTE
38 GPIOTE_CH0,
39 GPIOTE_CH1,
40 GPIOTE_CH2,
41 GPIOTE_CH3,
42
43 // PPI
44 PPI_CH0,
45 PPI_CH1,
46 PPI_CH2,
47 PPI_CH3,
48 PPI_CH4,
49 PPI_CH5,
50 PPI_CH6,
51 PPI_CH7,
52 PPI_CH8,
53 PPI_CH9,
54 PPI_CH10,
55 PPI_CH11,
56 PPI_CH12,
57 PPI_CH13,
58 PPI_CH14,
59 PPI_CH15,
60
61 PPI_GROUP0,
62 PPI_GROUP1,
63 PPI_GROUP2,
64 PPI_GROUP3,
65
66 // GPIO port 0
67 P0_00,
68 P0_01,
69 P0_02,
70 P0_03,
71 P0_04,
72 P0_05,
73 P0_06,
74 P0_07,
75 P0_08,
76 P0_09,
77 P0_10,
78 P0_11,
79 P0_12,
80 P0_13,
81 P0_14,
82 P0_15,
83 P0_16,
84 P0_17,
85 P0_18,
86 P0_19,
87 P0_20,
88 P0_21,
89 P0_22,
90 P0_23,
91 P0_24,
92 P0_25,
93 P0_26,
94 P0_27,
95 P0_28,
96 P0_29,
97 P0_30,
98 P0_31,
99
100 // TEMP
101 TEMP,
102
103 // Radio
104 RADIO,
105}
106
107impl_timer!(TIMER0, TIMER0, TIMER0);
108impl_timer!(TIMER1, TIMER1, TIMER1);
109impl_timer!(TIMER2, TIMER2, TIMER2);
110
111impl_rng!(RNG, RNG, RNG);
112
113impl_pin!(P0_00, 0, 0);
114impl_pin!(P0_01, 0, 1);
115impl_pin!(P0_02, 0, 2);
116impl_pin!(P0_03, 0, 3);
117impl_pin!(P0_04, 0, 4);
118impl_pin!(P0_05, 0, 5);
119impl_pin!(P0_06, 0, 6);
120impl_pin!(P0_07, 0, 7);
121impl_pin!(P0_08, 0, 8);
122impl_pin!(P0_09, 0, 9);
123impl_pin!(P0_10, 0, 10);
124impl_pin!(P0_11, 0, 11);
125impl_pin!(P0_12, 0, 12);
126impl_pin!(P0_13, 0, 13);
127impl_pin!(P0_14, 0, 14);
128impl_pin!(P0_15, 0, 15);
129impl_pin!(P0_16, 0, 16);
130impl_pin!(P0_17, 0, 17);
131impl_pin!(P0_18, 0, 18);
132impl_pin!(P0_19, 0, 19);
133impl_pin!(P0_20, 0, 20);
134impl_pin!(P0_21, 0, 21);
135impl_pin!(P0_22, 0, 22);
136impl_pin!(P0_23, 0, 23);
137impl_pin!(P0_24, 0, 24);
138impl_pin!(P0_25, 0, 25);
139impl_pin!(P0_26, 0, 26);
140impl_pin!(P0_27, 0, 27);
141impl_pin!(P0_28, 0, 28);
142impl_pin!(P0_29, 0, 29);
143impl_pin!(P0_30, 0, 30);
144impl_pin!(P0_31, 0, 31);
145
146impl_radio!(RADIO, RADIO, RADIO);
147
148embassy_hal_internal::interrupt_mod!(
149 POWER_CLOCK,
150 RADIO,
151 UART0,
152 SPI0_TWI0,
153 SPI1_TWI1,
154 GPIOTE,
155 ADC,
156 TIMER0,
157 TIMER1,
158 TIMER2,
159 RTC0,
160 TEMP,
161 RNG,
162 ECB,
163 CCM_AAR,
164 WDT,
165 RTC1,
166 QDEC,
167 LPCOMP,
168 SWI0,
169 SWI1,
170 SWI2,
171 SWI3,
172 SWI4,
173 SWI5,
174);
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index 624d6613d..14c3f9b1a 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -129,6 +129,9 @@ embassy_hal_internal::peripherals! {
129 129
130 // QDEC 130 // QDEC
131 QDEC, 131 QDEC,
132
133 // Radio
134 RADIO,
132} 135}
133 136
134impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 137impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
@@ -209,6 +212,8 @@ impl_ppi_channel!(PPI_CH31, 31 => static);
209impl_saadc_input!(P0_04, ANALOG_INPUT2); 212impl_saadc_input!(P0_04, ANALOG_INPUT2);
210impl_saadc_input!(P0_05, ANALOG_INPUT3); 213impl_saadc_input!(P0_05, ANALOG_INPUT3);
211 214
215impl_radio!(RADIO, RADIO, RADIO);
216
212embassy_hal_internal::interrupt_mod!( 217embassy_hal_internal::interrupt_mod!(
213 POWER_CLOCK, 218 POWER_CLOCK,
214 RADIO, 219 RADIO,
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index 002feab3b..c607586db 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -135,6 +135,9 @@ embassy_hal_internal::peripherals! {
135 135
136 // PDM 136 // PDM
137 PDM, 137 PDM,
138
139 // Radio
140 RADIO,
138} 141}
139 142
140impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 143impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
@@ -235,6 +238,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
235impl_saadc_input!(P0_30, ANALOG_INPUT6); 238impl_saadc_input!(P0_30, ANALOG_INPUT6);
236impl_saadc_input!(P0_31, ANALOG_INPUT7); 239impl_saadc_input!(P0_31, ANALOG_INPUT7);
237 240
241impl_radio!(RADIO, RADIO, RADIO);
242
238embassy_hal_internal::interrupt_mod!( 243embassy_hal_internal::interrupt_mod!(
239 POWER_CLOCK, 244 POWER_CLOCK,
240 RADIO, 245 RADIO,
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index 5952907f8..5f70365b4 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -135,6 +135,9 @@ embassy_hal_internal::peripherals! {
135 135
136 // PDM 136 // PDM
137 PDM, 137 PDM,
138
139 // Radio
140 RADIO,
138} 141}
139 142
140impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 143impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
@@ -237,6 +240,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
237impl_saadc_input!(P0_30, ANALOG_INPUT6); 240impl_saadc_input!(P0_30, ANALOG_INPUT6);
238impl_saadc_input!(P0_31, ANALOG_INPUT7); 241impl_saadc_input!(P0_31, ANALOG_INPUT7);
239 242
243impl_radio!(RADIO, RADIO, RADIO);
244
240embassy_hal_internal::interrupt_mod!( 245embassy_hal_internal::interrupt_mod!(
241 POWER_CLOCK, 246 POWER_CLOCK,
242 RADIO, 247 RADIO,
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index c2f792cb9..82d097407 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -130,6 +130,9 @@ embassy_hal_internal::peripherals! {
130 130
131 // QDEC 131 // QDEC
132 QDEC, 132 QDEC,
133
134 // Radio
135 RADIO,
133} 136}
134 137
135impl_usb!(USBD, USBD, USBD); 138impl_usb!(USBD, USBD, USBD);
@@ -224,6 +227,8 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
224impl_ppi_channel!(PPI_CH30, 30 => static); 227impl_ppi_channel!(PPI_CH30, 30 => static);
225impl_ppi_channel!(PPI_CH31, 31 => static); 228impl_ppi_channel!(PPI_CH31, 31 => static);
226 229
230impl_radio!(RADIO, RADIO, RADIO);
231
227embassy_hal_internal::interrupt_mod!( 232embassy_hal_internal::interrupt_mod!(
228 POWER_CLOCK, 233 POWER_CLOCK,
229 RADIO, 234 RADIO,
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index 65d52364d..67b32fe5f 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -150,6 +150,9 @@ embassy_hal_internal::peripherals! {
150 150
151 // PDM 151 // PDM
152 PDM, 152 PDM,
153
154 // Radio
155 RADIO,
153} 156}
154 157
155impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 158impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
@@ -264,6 +267,8 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
264 267
265impl_i2s!(I2S, I2S, I2S); 268impl_i2s!(I2S, I2S, I2S);
266 269
270impl_radio!(RADIO, RADIO, RADIO);
271
267embassy_hal_internal::interrupt_mod!( 272embassy_hal_internal::interrupt_mod!(
268 POWER_CLOCK, 273 POWER_CLOCK,
269 RADIO, 274 RADIO,
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 7c9b66d69..20f14e2d6 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -170,6 +170,9 @@ embassy_hal_internal::peripherals! {
170 170
171 // I2S 171 // I2S
172 I2S, 172 I2S,
173
174 // Radio
175 RADIO,
173} 176}
174 177
175impl_usb!(USBD, USBD, USBD); 178impl_usb!(USBD, USBD, USBD);
@@ -306,6 +309,8 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
306 309
307impl_i2s!(I2S, I2S, I2S); 310impl_i2s!(I2S, I2S, I2S);
308 311
312impl_radio!(RADIO, RADIO, RADIO);
313
309embassy_hal_internal::interrupt_mod!( 314embassy_hal_internal::interrupt_mod!(
310 POWER_CLOCK, 315 POWER_CLOCK,
311 RADIO, 316 RADIO,
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 51c55cd4d..d3272b2e8 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -173,6 +173,9 @@ embassy_hal_internal::peripherals! {
173 173
174 // I2S 174 // I2S
175 I2S, 175 I2S,
176
177 // Radio
178 RADIO,
176} 179}
177 180
178impl_usb!(USBD, USBD, USBD); 181impl_usb!(USBD, USBD, USBD);
@@ -311,6 +314,8 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
311 314
312impl_i2s!(I2S, I2S, I2S); 315impl_i2s!(I2S, I2S, I2S);
313 316
317impl_radio!(RADIO, RADIO, RADIO);
318
314embassy_hal_internal::interrupt_mod!( 319embassy_hal_internal::interrupt_mod!(
315 POWER_CLOCK, 320 POWER_CLOCK,
316 RADIO, 321 RADIO,
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index a7cf82872..65e8f9653 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -248,6 +248,9 @@ embassy_hal_internal::peripherals! {
248 P1_13, 248 P1_13,
249 P1_14, 249 P1_14,
250 P1_15, 250 P1_15,
251
252 // Radio
253 RADIO,
251} 254}
252 255
253impl_uarte!(SERIAL0, UARTE0, SERIAL0); 256impl_uarte!(SERIAL0, UARTE0, SERIAL0);
@@ -345,6 +348,8 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable);
345impl_ppi_channel!(PPI_CH30, 30 => configurable); 348impl_ppi_channel!(PPI_CH30, 30 => configurable);
346impl_ppi_channel!(PPI_CH31, 31 => configurable); 349impl_ppi_channel!(PPI_CH31, 31 => configurable);
347 350
351impl_radio!(RADIO, RADIO, RADIO);
352
348embassy_hal_internal::interrupt_mod!( 353embassy_hal_internal::interrupt_mod!(
349 CLOCK_POWER, 354 CLOCK_POWER,
350 RADIO, 355 RADIO,
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index eabf409dd..3649ea61a 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -8,7 +8,13 @@ use cfg_if::cfg_if;
8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
9 9
10use self::sealed::Pin as _; 10use self::sealed::Pin as _;
11#[cfg(feature = "nrf51")]
12use crate::pac::gpio;
13#[cfg(feature = "nrf51")]
14use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A};
15#[cfg(not(feature = "nrf51"))]
11use crate::pac::p0 as gpio; 16use crate::pac::p0 as gpio;
17#[cfg(not(feature = "nrf51"))]
12use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; 18use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A};
13use crate::{pac, Peripheral}; 19use crate::{pac, Peripheral};
14 20
@@ -36,14 +42,14 @@ pub enum Pull {
36} 42}
37 43
38/// GPIO input driver. 44/// GPIO input driver.
39pub struct Input<'d, T: Pin> { 45pub struct Input<'d> {
40 pub(crate) pin: Flex<'d, T>, 46 pub(crate) pin: Flex<'d>,
41} 47}
42 48
43impl<'d, T: Pin> Input<'d, T> { 49impl<'d> Input<'d> {
44 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. 50 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
45 #[inline] 51 #[inline]
46 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { 52 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self {
47 let mut pin = Flex::new(pin); 53 let mut pin = Flex::new(pin);
48 pin.set_as_input(pull); 54 pin.set_as_input(pull);
49 55
@@ -122,14 +128,14 @@ pub enum OutputDrive {
122} 128}
123 129
124/// GPIO output driver. 130/// GPIO output driver.
125pub struct Output<'d, T: Pin> { 131pub struct Output<'d> {
126 pub(crate) pin: Flex<'d, T>, 132 pub(crate) pin: Flex<'d>,
127} 133}
128 134
129impl<'d, T: Pin> Output<'d, T> { 135impl<'d> Output<'d> {
130 /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration. 136 /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration.
131 #[inline] 137 #[inline]
132 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, drive: OutputDrive) -> Self { 138 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, drive: OutputDrive) -> Self {
133 let mut pin = Flex::new(pin); 139 let mut pin = Flex::new(pin);
134 match initial_output { 140 match initial_output {
135 Level::High => pin.set_high(), 141 Level::High => pin.set_high(),
@@ -183,7 +189,7 @@ impl<'d, T: Pin> Output<'d, T> {
183 } 189 }
184} 190}
185 191
186fn convert_drive(drive: OutputDrive) -> DRIVE_A { 192pub(crate) fn convert_drive(drive: OutputDrive) -> DRIVE_A {
187 match drive { 193 match drive {
188 OutputDrive::Standard => DRIVE_A::S0S1, 194 OutputDrive::Standard => DRIVE_A::S0S1,
189 OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, 195 OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1,
@@ -209,20 +215,20 @@ fn convert_pull(pull: Pull) -> PULL_A {
209/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain 215/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
210/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output 216/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
211/// mode. 217/// mode.
212pub struct Flex<'d, T: Pin> { 218pub struct Flex<'d> {
213 pub(crate) pin: PeripheralRef<'d, T>, 219 pub(crate) pin: PeripheralRef<'d, AnyPin>,
214} 220}
215 221
216impl<'d, T: Pin> Flex<'d, T> { 222impl<'d> Flex<'d> {
217 /// Wrap the pin in a `Flex`. 223 /// Wrap the pin in a `Flex`.
218 /// 224 ///
219 /// The pin remains disconnected. The initial output level is unspecified, but can be changed 225 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
220 /// before the pin is put into output mode. 226 /// before the pin is put into output mode.
221 #[inline] 227 #[inline]
222 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { 228 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self {
223 into_ref!(pin); 229 into_ref!(pin);
224 // Pin will be in disconnected state. 230 // Pin will be in disconnected state.
225 Self { pin } 231 Self { pin: pin.map_into() }
226 } 232 }
227 233
228 /// Put the pin into input mode. 234 /// Put the pin into input mode.
@@ -349,7 +355,7 @@ impl<'d, T: Pin> Flex<'d, T> {
349 } 355 }
350} 356}
351 357
352impl<'d, T: Pin> Drop for Flex<'d, T> { 358impl<'d> Drop for Flex<'d> {
353 fn drop(&mut self) { 359 fn drop(&mut self) {
354 self.pin.conf().reset(); 360 self.pin.conf().reset();
355 } 361 }
@@ -376,6 +382,9 @@ pub(crate) mod sealed {
376 fn block(&self) -> &gpio::RegisterBlock { 382 fn block(&self) -> &gpio::RegisterBlock {
377 unsafe { 383 unsafe {
378 match self.pin_port() / 32 { 384 match self.pin_port() / 32 {
385 #[cfg(feature = "nrf51")]
386 0 => &*pac::GPIO::ptr(),
387 #[cfg(not(feature = "nrf51"))]
379 0 => &*pac::P0::ptr(), 388 0 => &*pac::P0::ptr(),
380 #[cfg(feature = "_gpio-p1")] 389 #[cfg(feature = "_gpio-p1")]
381 1 => &*pac::P1::ptr(), 390 1 => &*pac::P1::ptr(),
@@ -478,6 +487,7 @@ impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> {
478 } 487 }
479} 488}
480 489
490#[allow(dead_code)]
481pub(crate) fn deconfigure_pin(psel_bits: u32) { 491pub(crate) fn deconfigure_pin(psel_bits: u32) {
482 if psel_bits & 0x8000_0000 != 0 { 492 if psel_bits & 0x8000_0000 != 0 {
483 return; 493 return;
@@ -510,7 +520,7 @@ macro_rules! impl_pin {
510mod eh02 { 520mod eh02 {
511 use super::*; 521 use super::*;
512 522
513 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { 523 impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> {
514 type Error = Infallible; 524 type Error = Infallible;
515 525
516 fn is_high(&self) -> Result<bool, Self::Error> { 526 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -522,7 +532,7 @@ mod eh02 {
522 } 532 }
523 } 533 }
524 534
525 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { 535 impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> {
526 type Error = Infallible; 536 type Error = Infallible;
527 537
528 fn set_high(&mut self) -> Result<(), Self::Error> { 538 fn set_high(&mut self) -> Result<(), Self::Error> {
@@ -534,7 +544,7 @@ mod eh02 {
534 } 544 }
535 } 545 }
536 546
537 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { 547 impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> {
538 fn is_set_high(&self) -> Result<bool, Self::Error> { 548 fn is_set_high(&self) -> Result<bool, Self::Error> {
539 Ok(self.is_set_high()) 549 Ok(self.is_set_high())
540 } 550 }
@@ -544,7 +554,7 @@ mod eh02 {
544 } 554 }
545 } 555 }
546 556
547 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> { 557 impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> {
548 type Error = Infallible; 558 type Error = Infallible;
549 #[inline] 559 #[inline]
550 fn toggle(&mut self) -> Result<(), Self::Error> { 560 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -556,7 +566,7 @@ mod eh02 {
556 /// Implement [`embedded_hal_02::digital::v2::InputPin`] for [`Flex`]; 566 /// Implement [`embedded_hal_02::digital::v2::InputPin`] for [`Flex`];
557 /// 567 ///
558 /// If the pin is not in input mode the result is unspecified. 568 /// If the pin is not in input mode the result is unspecified.
559 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { 569 impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> {
560 type Error = Infallible; 570 type Error = Infallible;
561 571
562 fn is_high(&self) -> Result<bool, Self::Error> { 572 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -568,7 +578,7 @@ mod eh02 {
568 } 578 }
569 } 579 }
570 580
571 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { 581 impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> {
572 type Error = Infallible; 582 type Error = Infallible;
573 583
574 fn set_high(&mut self) -> Result<(), Self::Error> { 584 fn set_high(&mut self) -> Result<(), Self::Error> {
@@ -580,7 +590,7 @@ mod eh02 {
580 } 590 }
581 } 591 }
582 592
583 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { 593 impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> {
584 fn is_set_high(&self) -> Result<bool, Self::Error> { 594 fn is_set_high(&self) -> Result<bool, Self::Error> {
585 Ok(self.is_set_high()) 595 Ok(self.is_set_high())
586 } 596 }
@@ -590,7 +600,7 @@ mod eh02 {
590 } 600 }
591 } 601 }
592 602
593 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> { 603 impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> {
594 type Error = Infallible; 604 type Error = Infallible;
595 #[inline] 605 #[inline]
596 fn toggle(&mut self) -> Result<(), Self::Error> { 606 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -600,11 +610,11 @@ mod eh02 {
600 } 610 }
601} 611}
602 612
603impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { 613impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> {
604 type Error = Infallible; 614 type Error = Infallible;
605} 615}
606 616
607impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { 617impl<'d> embedded_hal_1::digital::InputPin for Input<'d> {
608 fn is_high(&mut self) -> Result<bool, Self::Error> { 618 fn is_high(&mut self) -> Result<bool, Self::Error> {
609 Ok((*self).is_high()) 619 Ok((*self).is_high())
610 } 620 }
@@ -614,11 +624,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
614 } 624 }
615} 625}
616 626
617impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> { 627impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
618 type Error = Infallible; 628 type Error = Infallible;
619} 629}
620 630
621impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { 631impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
622 fn set_high(&mut self) -> Result<(), Self::Error> { 632 fn set_high(&mut self) -> Result<(), Self::Error> {
623 Ok(self.set_high()) 633 Ok(self.set_high())
624 } 634 }
@@ -628,7 +638,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
628 } 638 }
629} 639}
630 640
631impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { 641impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> {
632 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 642 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
633 Ok((*self).is_set_high()) 643 Ok((*self).is_set_high())
634 } 644 }
@@ -638,14 +648,14 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
638 } 648 }
639} 649}
640 650
641impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { 651impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> {
642 type Error = Infallible; 652 type Error = Infallible;
643} 653}
644 654
645/// Implement [`InputPin`] for [`Flex`]; 655/// Implement [`InputPin`] for [`Flex`];
646/// 656///
647/// 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.
648impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { 658impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
649 fn is_high(&mut self) -> Result<bool, Self::Error> { 659 fn is_high(&mut self) -> Result<bool, Self::Error> {
650 Ok((*self).is_high()) 660 Ok((*self).is_high())
651 } 661 }
@@ -655,7 +665,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
655 } 665 }
656} 666}
657 667
658impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { 668impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
659 fn set_high(&mut self) -> Result<(), Self::Error> { 669 fn set_high(&mut self) -> Result<(), Self::Error> {
660 Ok(self.set_high()) 670 Ok(self.set_high())
661 } 671 }
@@ -665,7 +675,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
665 } 675 }
666} 676}
667 677
668impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { 678impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> {
669 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 679 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
670 Ok((*self).is_set_high()) 680 Ok((*self).is_set_high())
671 } 681 }
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 8020b8dc2..12f4ed0a0 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -13,6 +13,10 @@ use crate::interrupt::InterruptExt;
13use crate::ppi::{Event, Task}; 13use crate::ppi::{Event, Task};
14use crate::{interrupt, pac, peripherals}; 14use crate::{interrupt, pac, peripherals};
15 15
16#[cfg(feature = "nrf51")]
17/// Amount of GPIOTE channels in the chip.
18const CHANNEL_COUNT: usize = 4;
19#[cfg(not(feature = "_nrf51"))]
16/// Amount of GPIOTE channels in the chip. 20/// Amount of GPIOTE channels in the chip.
17const CHANNEL_COUNT: usize = 8; 21const CHANNEL_COUNT: usize = 8;
18 22
@@ -61,16 +65,20 @@ fn regs() -> &'static pac::gpiote::RegisterBlock {
61} 65}
62 66
63pub(crate) fn init(irq_prio: crate::interrupt::Priority) { 67pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
64 #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] 68 // no latched GPIO detect in nrf51.
65 let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; 69 #[cfg(not(feature = "_nrf51"))]
66 #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] 70 {
67 let ports = unsafe { &[&*pac::P0::ptr()] }; 71 #[cfg(any(feature = "nrf52833", feature = "nrf52840"))]
68 72 let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] };
69 for &p in ports { 73 #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840")))]
70 // Enable latched detection 74 let ports = unsafe { &[&*pac::P0::ptr()] };
71 p.detectmode.write(|w| w.detectmode().ldetect()); 75
72 // Clear latch 76 for &p in ports {
73 p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) 77 // Enable latched detection
78 p.detectmode.write(|w| w.detectmode().ldetect());
79 // Clear latch
80 p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) })
81 }
74 } 82 }
75 83
76 // Enable interrupts 84 // Enable interrupts
@@ -78,7 +86,7 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
78 let irq = interrupt::GPIOTE0; 86 let irq = interrupt::GPIOTE0;
79 #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] 87 #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
80 let irq = interrupt::GPIOTE1; 88 let irq = interrupt::GPIOTE1;
81 #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] 89 #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))]
82 let irq = interrupt::GPIOTE; 90 let irq = interrupt::GPIOTE;
83 91
84 irq.unpend(); 92 irq.unpend();
@@ -103,7 +111,7 @@ fn GPIOTE1() {
103 unsafe { handle_gpiote_interrupt() }; 111 unsafe { handle_gpiote_interrupt() };
104} 112}
105 113
106#[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] 114#[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))]
107#[cfg(feature = "rt")] 115#[cfg(feature = "rt")]
108#[interrupt] 116#[interrupt]
109fn GPIOTE() { 117fn GPIOTE() {
@@ -125,9 +133,29 @@ unsafe fn handle_gpiote_interrupt() {
125 133
126 #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] 134 #[cfg(any(feature = "nrf52833", feature = "nrf52840"))]
127 let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; 135 let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()];
128 #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] 136 #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840")))]
129 let ports = &[&*pac::P0::ptr()]; 137 let ports = &[&*pac::P0::ptr()];
138 #[cfg(feature = "_nrf51")]
139 let ports = unsafe { &[&*pac::GPIO::ptr()] };
140
141 #[cfg(feature = "_nrf51")]
142 for (port, &p) in ports.iter().enumerate() {
143 let inp = p.in_.read().bits();
144 for pin in 0..32 {
145 let fired = match p.pin_cnf[pin as usize].read().sense().variant() {
146 Some(pac::gpio::pin_cnf::SENSE_A::HIGH) => inp & (1 << pin) != 0,
147 Some(pac::gpio::pin_cnf::SENSE_A::LOW) => inp & (1 << pin) == 0,
148 _ => false,
149 };
150
151 if fired {
152 PORT_WAKERS[port * 32 + pin as usize].wake();
153 p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled());
154 }
155 }
156 }
130 157
158 #[cfg(not(feature = "_nrf51"))]
131 for (port, &p) in ports.iter().enumerate() { 159 for (port, &p) in ports.iter().enumerate() {
132 let bits = p.latch.read().bits(); 160 let bits = p.latch.read().bits();
133 for pin in BitIter(bits) { 161 for pin in BitIter(bits) {
@@ -156,12 +184,12 @@ impl Iterator for BitIter {
156} 184}
157 185
158/// GPIOTE channel driver in input mode 186/// GPIOTE channel driver in input mode
159pub struct InputChannel<'d, C: Channel, T: GpioPin> { 187pub struct InputChannel<'d> {
160 ch: PeripheralRef<'d, C>, 188 ch: PeripheralRef<'d, AnyChannel>,
161 pin: Input<'d, T>, 189 pin: Input<'d>,
162} 190}
163 191
164impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { 192impl<'d> Drop for InputChannel<'d> {
165 fn drop(&mut self) { 193 fn drop(&mut self) {
166 let g = regs(); 194 let g = regs();
167 let num = self.ch.number(); 195 let num = self.ch.number();
@@ -170,9 +198,9 @@ impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> {
170 } 198 }
171} 199}
172 200
173impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { 201impl<'d> InputChannel<'d> {
174 /// Create a new GPIOTE input channel driver. 202 /// Create a new GPIOTE input channel driver.
175 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self { 203 pub fn new(ch: impl Peripheral<P = impl Channel> + 'd, pin: Input<'d>, polarity: InputChannelPolarity) -> Self {
176 into_ref!(ch); 204 into_ref!(ch);
177 205
178 let g = regs(); 206 let g = regs();
@@ -195,7 +223,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
195 223
196 g.events_in[num].reset(); 224 g.events_in[num].reset();
197 225
198 InputChannel { ch, pin } 226 InputChannel { ch: ch.map_into(), pin }
199 } 227 }
200 228
201 /// Asynchronously wait for an event in this channel. 229 /// Asynchronously wait for an event in this channel.
@@ -227,12 +255,12 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
227} 255}
228 256
229/// GPIOTE channel driver in output mode 257/// GPIOTE channel driver in output mode
230pub struct OutputChannel<'d, C: Channel, T: GpioPin> { 258pub struct OutputChannel<'d> {
231 ch: PeripheralRef<'d, C>, 259 ch: PeripheralRef<'d, AnyChannel>,
232 _pin: Output<'d, T>, 260 _pin: Output<'d>,
233} 261}
234 262
235impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { 263impl<'d> Drop for OutputChannel<'d> {
236 fn drop(&mut self) { 264 fn drop(&mut self) {
237 let g = regs(); 265 let g = regs();
238 let num = self.ch.number(); 266 let num = self.ch.number();
@@ -241,9 +269,9 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> {
241 } 269 }
242} 270}
243 271
244impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { 272impl<'d> OutputChannel<'d> {
245 /// Create a new GPIOTE output channel driver. 273 /// Create a new GPIOTE output channel driver.
246 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { 274 pub fn new(ch: impl Peripheral<P = impl Channel> + 'd, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self {
247 into_ref!(ch); 275 into_ref!(ch);
248 let g = regs(); 276 let g = regs();
249 let num = ch.number(); 277 let num = ch.number();
@@ -267,7 +295,10 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
267 unsafe { w.psel().bits(pin.pin.pin.pin()) } 295 unsafe { w.psel().bits(pin.pin.pin.pin()) }
268 }); 296 });
269 297
270 OutputChannel { ch, _pin: pin } 298 OutputChannel {
299 ch: ch.map_into(),
300 _pin: pin,
301 }
271 } 302 }
272 303
273 /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). 304 /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle).
@@ -348,7 +379,7 @@ impl<'a> Future for PortInputFuture<'a> {
348 } 379 }
349} 380}
350 381
351impl<'d, T: GpioPin> Input<'d, T> { 382impl<'d> Input<'d> {
352 /// Wait until the pin is high. If it is already high, return immediately. 383 /// Wait until the pin is high. If it is already high, return immediately.
353 pub async fn wait_for_high(&mut self) { 384 pub async fn wait_for_high(&mut self) {
354 self.pin.wait_for_high().await 385 self.pin.wait_for_high().await
@@ -375,7 +406,7 @@ impl<'d, T: GpioPin> Input<'d, T> {
375 } 406 }
376} 407}
377 408
378impl<'d, T: GpioPin> Flex<'d, T> { 409impl<'d> Flex<'d> {
379 /// Wait until the pin is high. If it is already high, return immediately. 410 /// Wait until the pin is high. If it is already high, return immediately.
380 pub async fn wait_for_high(&mut self) { 411 pub async fn wait_for_high(&mut self) {
381 self.pin.conf().modify(|_, w| w.sense().high()); 412 self.pin.conf().modify(|_, w| w.sense().high());
@@ -420,7 +451,7 @@ mod sealed {
420/// GPIOTE channel trait. 451/// GPIOTE channel trait.
421/// 452///
422/// Implemented by all GPIOTE channels. 453/// Implemented by all GPIOTE channels.
423pub trait Channel: sealed::Channel + Sized { 454pub trait Channel: sealed::Channel + Into<AnyChannel> + Sized + 'static {
424 /// Get the channel number. 455 /// Get the channel number.
425 fn number(&self) -> usize; 456 fn number(&self) -> usize;
426 457
@@ -460,6 +491,12 @@ macro_rules! impl_channel {
460 $number as usize 491 $number as usize
461 } 492 }
462 } 493 }
494
495 impl From<peripherals::$type> for AnyChannel {
496 fn from(val: peripherals::$type) -> Self {
497 Channel::degrade(val)
498 }
499 }
463 }; 500 };
464} 501}
465 502
@@ -467,9 +504,13 @@ impl_channel!(GPIOTE_CH0, 0);
467impl_channel!(GPIOTE_CH1, 1); 504impl_channel!(GPIOTE_CH1, 1);
468impl_channel!(GPIOTE_CH2, 2); 505impl_channel!(GPIOTE_CH2, 2);
469impl_channel!(GPIOTE_CH3, 3); 506impl_channel!(GPIOTE_CH3, 3);
507#[cfg(not(feature = "nrf51"))]
470impl_channel!(GPIOTE_CH4, 4); 508impl_channel!(GPIOTE_CH4, 4);
509#[cfg(not(feature = "nrf51"))]
471impl_channel!(GPIOTE_CH5, 5); 510impl_channel!(GPIOTE_CH5, 5);
511#[cfg(not(feature = "nrf51"))]
472impl_channel!(GPIOTE_CH6, 6); 512impl_channel!(GPIOTE_CH6, 6);
513#[cfg(not(feature = "nrf51"))]
473impl_channel!(GPIOTE_CH7, 7); 514impl_channel!(GPIOTE_CH7, 7);
474 515
475// ==================== 516// ====================
@@ -477,7 +518,7 @@ impl_channel!(GPIOTE_CH7, 7);
477mod eh02 { 518mod eh02 {
478 use super::*; 519 use super::*;
479 520
480 impl<'d, C: Channel, T: GpioPin> embedded_hal_02::digital::v2::InputPin for InputChannel<'d, C, T> { 521 impl<'d> embedded_hal_02::digital::v2::InputPin for InputChannel<'d> {
481 type Error = Infallible; 522 type Error = Infallible;
482 523
483 fn is_high(&self) -> Result<bool, Self::Error> { 524 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -490,11 +531,11 @@ mod eh02 {
490 } 531 }
491} 532}
492 533
493impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> { 534impl<'d> embedded_hal_1::digital::ErrorType for InputChannel<'d> {
494 type Error = Infallible; 535 type Error = Infallible;
495} 536}
496 537
497impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> { 538impl<'d> embedded_hal_1::digital::InputPin for InputChannel<'d> {
498 fn is_high(&mut self) -> Result<bool, Self::Error> { 539 fn is_high(&mut self) -> Result<bool, Self::Error> {
499 Ok(self.pin.is_high()) 540 Ok(self.pin.is_high())
500 } 541 }
@@ -504,7 +545,7 @@ impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChan
504 } 545 }
505} 546}
506 547
507impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { 548impl<'d> embedded_hal_async::digital::Wait for Input<'d> {
508 async fn wait_for_high(&mut self) -> Result<(), Self::Error> { 549 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
509 Ok(self.wait_for_high().await) 550 Ok(self.wait_for_high().await)
510 } 551 }
@@ -526,7 +567,7 @@ impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> {
526 } 567 }
527} 568}
528 569
529impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> { 570impl<'d> embedded_hal_async::digital::Wait for Flex<'d> {
530 async fn wait_for_high(&mut self) -> Result<(), Self::Error> { 571 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
531 Ok(self.wait_for_high().await) 572 Ok(self.wait_for_high().await)
532 } 573 }
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index d9c92a76d..718f229a3 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -40,10 +40,16 @@ pub(crate) mod util;
40#[cfg(feature = "_time-driver")] 40#[cfg(feature = "_time-driver")]
41mod time_driver; 41mod time_driver;
42 42
43#[cfg(not(feature = "nrf51"))]
43pub mod buffered_uarte; 44pub mod buffered_uarte;
44pub mod gpio; 45pub mod gpio;
45#[cfg(feature = "gpiote")] 46#[cfg(feature = "gpiote")]
46pub mod gpiote; 47pub mod gpiote;
48
49// TODO: tested on other chips
50#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340-app")))]
51pub mod radio;
52
47#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] 53#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
48pub mod i2s; 54pub mod i2s;
49pub mod nvmc; 55pub mod nvmc;
@@ -58,7 +64,12 @@ pub mod nvmc;
58))] 64))]
59pub mod pdm; 65pub mod pdm;
60pub mod ppi; 66pub mod ppi;
61#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] 67#[cfg(not(any(
68 feature = "nrf51",
69 feature = "nrf52805",
70 feature = "nrf52820",
71 feature = "_nrf5340-net"
72)))]
62pub mod pwm; 73pub mod pwm;
63#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] 74#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
64pub mod qdec; 75pub mod qdec;
@@ -66,15 +77,20 @@ pub mod qdec;
66pub mod qspi; 77pub mod qspi;
67#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))] 78#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
68pub mod rng; 79pub mod rng;
69#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] 80#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
70pub mod saadc; 81pub mod saadc;
82#[cfg(not(feature = "nrf51"))]
71pub mod spim; 83pub mod spim;
84#[cfg(not(feature = "nrf51"))]
72pub mod spis; 85pub mod spis;
73#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 86#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
74pub mod temp; 87pub mod temp;
75pub mod timer; 88pub mod timer;
89#[cfg(not(feature = "nrf51"))]
76pub mod twim; 90pub mod twim;
91#[cfg(not(feature = "nrf51"))]
77pub mod twis; 92pub mod twis;
93#[cfg(not(feature = "nrf51"))]
78pub mod uarte; 94pub mod uarte;
79#[cfg(any( 95#[cfg(any(
80 feature = "_nrf5340-app", 96 feature = "_nrf5340-app",
@@ -87,6 +103,7 @@ pub mod usb;
87pub mod wdt; 103pub mod wdt;
88 104
89// This mod MUST go last, so that it sees all the `impl_foo!` macros 105// This mod MUST go last, so that it sees all the `impl_foo!` macros
106#[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")]
90#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")] 107#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")]
91#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")] 108#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")]
92#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")] 109#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")]
@@ -324,6 +341,7 @@ mod consts {
324 pub const APPROTECT_DISABLED: u32 = 0x0000_005a; 341 pub const APPROTECT_DISABLED: u32 = 0x0000_005a;
325} 342}
326 343
344#[cfg(not(feature = "nrf51"))]
327#[derive(Debug, Copy, Clone, Eq, PartialEq)] 345#[derive(Debug, Copy, Clone, Eq, PartialEq)]
328#[cfg_attr(feature = "defmt", derive(defmt::Format))] 346#[cfg_attr(feature = "defmt", derive(defmt::Format))]
329enum WriteResult { 347enum WriteResult {
@@ -335,10 +353,12 @@ enum WriteResult {
335 Failed, 353 Failed,
336} 354}
337 355
356#[cfg(not(feature = "nrf51"))]
338unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { 357unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult {
339 uicr_write_masked(address, value, 0xFFFF_FFFF) 358 uicr_write_masked(address, value, 0xFFFF_FFFF)
340} 359}
341 360
361#[cfg(not(feature = "nrf51"))]
342unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult { 362unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult {
343 let curr_val = address.read_volatile(); 363 let curr_val = address.read_volatile();
344 if curr_val & mask == value & mask { 364 if curr_val & mask == value & mask {
@@ -371,9 +391,11 @@ pub fn init(config: config::Config) -> Peripherals {
371 // before doing anything important. 391 // before doing anything important.
372 let peripherals = Peripherals::take(); 392 let peripherals = Peripherals::take();
373 393
394 #[allow(unused_mut)]
374 let mut needs_reset = false; 395 let mut needs_reset = false;
375 396
376 // Setup debug protection. 397 // Setup debug protection.
398 #[cfg(not(feature = "nrf51"))]
377 match config.debug { 399 match config.debug {
378 config::Debug::Allowed => { 400 config::Debug::Allowed => {
379 #[cfg(feature = "_nrf52")] 401 #[cfg(feature = "_nrf52")]
@@ -489,7 +511,7 @@ pub fn init(config: config::Config) -> Peripherals {
489 } 511 }
490 512
491 // Configure LFCLK. 513 // Configure LFCLK.
492 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 514 #[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf9160")))]
493 match config.lfclk_source { 515 match config.lfclk_source {
494 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), 516 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
495 config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), 517 config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs
index de840b886..4f9eda167 100644
--- a/embassy-nrf/src/nvmc.rs
+++ b/embassy-nrf/src/nvmc.rs
@@ -160,7 +160,7 @@ impl<'d> NorFlash for Nvmc<'d> {
160 if offset as usize + bytes.len() > FLASH_SIZE { 160 if offset as usize + bytes.len() > FLASH_SIZE {
161 return Err(Error::OutOfBounds); 161 return Err(Error::OutOfBounds);
162 } 162 }
163 if offset as usize % 4 != 0 || bytes.len() as usize % 4 != 0 { 163 if offset as usize % 4 != 0 || bytes.len() % 4 != 0 {
164 return Err(Error::Unaligned); 164 return Err(Error::Unaligned);
165 } 165 }
166 166
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index 24fa29a4a..754d38310 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -1,4 +1,4 @@
1//! Pulse Density Modulation (PDM) mirophone driver. 1//! Pulse Density Modulation (PDM) mirophone driver
2 2
3#![macro_use] 3#![macro_use]
4 4
@@ -26,7 +26,7 @@ pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
26pub use crate::pac::pdm::ratio::RATIO_A as Ratio; 26pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
27use crate::{interrupt, Peripheral}; 27use crate::{interrupt, Peripheral};
28 28
29/// Interrupt handler. 29/// Interrupt handler
30pub struct InterruptHandler<T: Instance> { 30pub struct InterruptHandler<T: Instance> {
31 _phantom: PhantomData<T>, 31 _phantom: PhantomData<T>,
32} 32}
@@ -56,12 +56,12 @@ pub struct Pdm<'d, T: Instance> {
56 _peri: PeripheralRef<'d, T>, 56 _peri: PeripheralRef<'d, T>,
57} 57}
58 58
59/// PDM error. 59/// PDM error
60#[derive(Debug, Clone, Copy, PartialEq, Eq)] 60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))] 61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62#[non_exhaustive] 62#[non_exhaustive]
63pub enum Error { 63pub enum Error {
64 /// Buffer is too long. 64 /// Buffer is too long
65 BufferTooLong, 65 BufferTooLong,
66 /// Buffer is empty 66 /// Buffer is empty
67 BufferZeroLength, 67 BufferZeroLength,
@@ -75,13 +75,13 @@ static DUMMY_BUFFER: [i16; 1] = [0; 1];
75 75
76/// The state of a continuously running sampler. While it reflects 76/// The state of a continuously running sampler. While it reflects
77/// the progress of a sampler, it also signals what should be done 77/// the progress of a sampler, it also signals what should be done
78/// next. For example, if the sampler has stopped then the Pdm implementation 78/// next. For example, if the sampler has stopped then the PDM implementation
79/// can then tear down its infrastructure. 79/// can then tear down its infrastructure
80#[derive(PartialEq)] 80#[derive(PartialEq)]
81pub enum SamplerState { 81pub enum SamplerState {
82 /// The sampler processed the samples and is ready for more. 82 /// The sampler processed the samples and is ready for more
83 Sampled, 83 Sampled,
84 /// The sampler is done processing samples. 84 /// The sampler is done processing samples
85 Stopped, 85 Stopped,
86} 86}
87 87
@@ -145,15 +145,12 @@ impl<'d, T: Instance> Pdm<'d, T> {
145 } 145 }
146 146
147 fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { 147 fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) {
148 let gain_left = gain_left 148 let gain_to_bits = |gain: I7F1| -> u8 {
149 .saturating_add(I7F1::from_bits(40)) 149 let gain = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50);
150 .saturating_to_num::<u8>() 150 unsafe { core::mem::transmute(gain) }
151 .clamp(0, 0x50); 151 };
152 let gain_right = gain_right 152 let gain_left = gain_to_bits(gain_left);
153 .saturating_add(I7F1::from_bits(40)) 153 let gain_right = gain_to_bits(gain_right);
154 .saturating_to_num::<u8>()
155 .clamp(0, 0x50);
156
157 r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) }); 154 r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) });
158 r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) }); 155 r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) });
159 } 156 }
@@ -163,12 +160,12 @@ impl<'d, T: Instance> Pdm<'d, T> {
163 Self::_set_gain(T::regs(), gain_left, gain_right) 160 Self::_set_gain(T::regs(), gain_left, gain_right)
164 } 161 }
165 162
166 /// Start sampling microphon data into a dummy buffer 163 /// Start sampling microphone data into a dummy buffer.
167 /// Usefull to start the microphon and keep it active between recording samples 164 /// Useful to start the microphone and keep it active between recording samples.
168 pub async fn start(&mut self) { 165 pub async fn start(&mut self) {
169 let r = T::regs(); 166 let r = T::regs();
170 167
171 // start dummy sampling because microphon needs some setup time 168 // start dummy sampling because microphone needs some setup time
172 r.sample 169 r.sample
173 .ptr 170 .ptr
174 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); 171 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
@@ -179,16 +176,16 @@ impl<'d, T: Instance> Pdm<'d, T> {
179 r.tasks_start.write(|w| unsafe { w.bits(1) }); 176 r.tasks_start.write(|w| unsafe { w.bits(1) });
180 } 177 }
181 178
182 /// Stop sampling microphon data inta a dummy buffer 179 /// Stop sampling microphone data inta a dummy buffer
183 pub async fn stop(&mut self) { 180 pub async fn stop(&mut self) {
184 let r = T::regs(); 181 let r = T::regs();
185 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 182 r.tasks_stop.write(|w| unsafe { w.bits(1) });
186 r.events_started.reset(); 183 r.events_started.reset();
187 } 184 }
188 185
189 /// Sample data into the given buffer. 186 /// Sample data into the given buffer
190 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { 187 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> {
191 if buffer.len() == 0 { 188 if buffer.is_empty() {
192 return Err(Error::BufferZeroLength); 189 return Err(Error::BufferZeroLength);
193 } 190 }
194 if buffer.len() > EASY_DMA_SIZE { 191 if buffer.len() > EASY_DMA_SIZE {
@@ -303,7 +300,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
303 }); 300 });
304 301
305 // Don't reorder the start event before the previous writes. Hopefully self 302 // Don't reorder the start event before the previous writes. Hopefully self
306 // wouldn't happen anyway. 303 // wouldn't happen anyway
307 compiler_fence(Ordering::SeqCst); 304 compiler_fence(Ordering::SeqCst);
308 305
309 r.tasks_start.write(|w| unsafe { w.bits(1) }); 306 r.tasks_start.write(|w| unsafe { w.bits(1) });
@@ -314,11 +311,11 @@ impl<'d, T: Instance> Pdm<'d, T> {
314 311
315 let drop = OnDrop::new(|| { 312 let drop = OnDrop::new(|| {
316 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 313 r.tasks_stop.write(|w| unsafe { w.bits(1) });
317 // N.B. It would be better if this were async, but Drop only support sync code. 314 // N.B. It would be better if this were async, but Drop only support sync code
318 while r.events_stopped.read().bits() != 0 {} 315 while r.events_stopped.read().bits() != 0 {}
319 }); 316 });
320 317
321 // Wait for events and complete when the sampler indicates it has had enough. 318 // Wait for events and complete when the sampler indicates it has had enough
322 poll_fn(|cx| { 319 poll_fn(|cx| {
323 let r = T::regs(); 320 let r = T::regs();
324 321
@@ -331,7 +328,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
331 r.intenset.write(|w| w.end().set()); 328 r.intenset.write(|w| w.end().set());
332 329
333 if !done { 330 if !done {
334 // Discard the last buffer after the user requested a stop. 331 // Discard the last buffer after the user requested a stop
335 if sampler(&bufs[current_buffer]) == SamplerState::Sampled { 332 if sampler(&bufs[current_buffer]) == SamplerState::Sampled {
336 let next_buffer = 1 - current_buffer; 333 let next_buffer = 1 - current_buffer;
337 current_buffer = next_buffer; 334 current_buffer = next_buffer;
@@ -405,7 +402,7 @@ impl Default for Config {
405 } 402 }
406} 403}
407 404
408/// PDM operation mode. 405/// PDM operation mode
409#[derive(PartialEq)] 406#[derive(PartialEq)]
410pub enum OperationMode { 407pub enum OperationMode {
411 /// Mono (1 channel) 408 /// Mono (1 channel)
@@ -476,9 +473,9 @@ pub(crate) mod sealed {
476 } 473 }
477} 474}
478 475
479/// PDM peripheral instance. 476/// PDM peripheral instance
480pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 477pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
481 /// Interrupt for this peripheral. 478 /// Interrupt for this peripheral
482 type Interrupt: interrupt::typelevel::Interrupt; 479 type Interrupt: interrupt::typelevel::Interrupt;
483} 480}
484 481
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 5b4a64388..f5764b8b7 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -284,6 +284,7 @@ impl ConfigurableChannel for AnyConfigurableChannel {
284 } 284 }
285} 285}
286 286
287#[cfg(not(feature = "nrf51"))]
287macro_rules! impl_ppi_channel { 288macro_rules! impl_ppi_channel {
288 ($type:ident, $number:expr) => { 289 ($type:ident, $number:expr) => {
289 impl crate::ppi::sealed::Channel for peripherals::$type {} 290 impl crate::ppi::sealed::Channel for peripherals::$type {}
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index 3e9e9fc81..8ff52ece3 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -1,6 +1,6 @@
1use embassy_hal_internal::into_ref; 1use embassy_hal_internal::into_ref;
2 2
3use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task}; 3use super::{Channel, ConfigurableChannel, Event, Ppi, Task};
4use crate::{pac, Peripheral}; 4use crate::{pac, Peripheral};
5 5
6impl<'d> Task<'d> { 6impl<'d> Task<'d> {
@@ -19,7 +19,7 @@ pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
19} 19}
20 20
21#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task 21#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
22impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> { 22impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> {
23 /// Configure PPI channel to trigger `task`. 23 /// Configure PPI channel to trigger `task`.
24 pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self { 24 pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self {
25 into_ref!(ch); 25 into_ref!(ch);
@@ -84,6 +84,7 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for
84 let n = self.ch.number(); 84 let n = self.ch.number();
85 r.ch[n].eep.write(|w| unsafe { w.bits(0) }); 85 r.ch[n].eep.write(|w| unsafe { w.bits(0) });
86 r.ch[n].tep.write(|w| unsafe { w.bits(0) }); 86 r.ch[n].tep.write(|w| unsafe { w.bits(0) });
87 #[cfg(not(feature = "nrf51"))]
87 r.fork[n].tep.write(|w| unsafe { w.bits(0) }); 88 r.fork[n].tep.write(|w| unsafe { w.bits(0) });
88 } 89 }
89} 90}
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 2f0397632..833370d4b 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -47,6 +47,8 @@ pub enum Error {
47} 47}
48 48
49const MAX_SEQUENCE_LEN: usize = 32767; 49const MAX_SEQUENCE_LEN: usize = 32767;
50/// The used pwm clock frequency
51pub const PWM_CLK_HZ: u32 = 16_000_000;
50 52
51impl<'d, T: Instance> SequencePwm<'d, T> { 53impl<'d, T: Instance> SequencePwm<'d, T> {
52 /// Create a new 1-channel PWM 54 /// Create a new 1-channel PWM
@@ -442,7 +444,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> {
442 return Err(Error::SequenceTimesAtLeastOne); 444 return Err(Error::SequenceTimesAtLeastOne);
443 } 445 }
444 446
445 let _ = self.stop(); 447 self.stop();
446 448
447 let r = T::regs(); 449 let r = T::regs();
448 450
@@ -505,7 +507,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> {
505 507
506impl<'d, 's, T: Instance> Drop for Sequencer<'d, 's, T> { 508impl<'d, 's, T: Instance> Drop for Sequencer<'d, 's, T> {
507 fn drop(&mut self) { 509 fn drop(&mut self) {
508 let _ = self.stop(); 510 self.stop();
509 } 511 }
510} 512}
511 513
@@ -695,7 +697,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
695 // Enable 697 // Enable
696 r.enable.write(|w| w.enable().enabled()); 698 r.enable.write(|w| w.enable().enabled());
697 699
698 r.seq0.ptr.write(|w| unsafe { w.bits((&pwm.duty).as_ptr() as u32) }); 700 r.seq0.ptr.write(|w| unsafe { w.bits((pwm.duty).as_ptr() as u32) });
699 701
700 r.seq0.cnt.write(|w| unsafe { w.bits(4) }); 702 r.seq0.cnt.write(|w| unsafe { w.bits(4) });
701 r.seq0.refresh.write(|w| unsafe { w.bits(0) }); 703 r.seq0.refresh.write(|w| unsafe { w.bits(0) });
@@ -713,6 +715,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
713 pwm 715 pwm
714 } 716 }
715 717
718 /// Returns the enable state of the pwm counter
719 #[inline(always)]
720 pub fn is_enabled(&self) -> bool {
721 let r = T::regs();
722 r.enable.read().enable().bit_is_set()
723 }
724
716 /// Enables the PWM generator. 725 /// Enables the PWM generator.
717 #[inline(always)] 726 #[inline(always)]
718 pub fn enable(&self) { 727 pub fn enable(&self) {
@@ -727,6 +736,11 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
727 r.enable.write(|w| w.enable().disabled()); 736 r.enable.write(|w| w.enable().disabled());
728 } 737 }
729 738
739 /// Returns the current duty of the channel
740 pub fn duty(&self, channel: usize) -> u16 {
741 self.duty[channel]
742 }
743
730 /// Sets duty cycle (15 bit) for a PWM channel. 744 /// Sets duty cycle (15 bit) for a PWM channel.
731 pub fn set_duty(&mut self, channel: usize, duty: u16) { 745 pub fn set_duty(&mut self, channel: usize, duty: u16) {
732 let r = T::regs(); 746 let r = T::regs();
@@ -734,7 +748,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
734 self.duty[channel] = duty & 0x7FFF; 748 self.duty[channel] = duty & 0x7FFF;
735 749
736 // reload ptr in case self was moved 750 // reload ptr in case self was moved
737 r.seq0.ptr.write(|w| unsafe { w.bits((&self.duty).as_ptr() as u32) }); 751 r.seq0.ptr.write(|w| unsafe { w.bits((self.duty).as_ptr() as u32) });
738 752
739 // defensive before seqstart 753 // defensive before seqstart
740 compiler_fence(Ordering::SeqCst); 754 compiler_fence(Ordering::SeqCst);
@@ -746,7 +760,9 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
746 760
747 // defensive wait until waveform is loaded after seqstart so set_duty 761 // defensive wait until waveform is loaded after seqstart so set_duty
748 // can't be called again while dma is still reading 762 // can't be called again while dma is still reading
749 while r.events_seqend[0].read().bits() == 0 {} 763 if self.is_enabled() {
764 while r.events_seqend[0].read().bits() == 0 {}
765 }
750 } 766 }
751 767
752 /// Sets the PWM clock prescaler. 768 /// Sets the PWM clock prescaler.
@@ -788,7 +804,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
788 /// Sets the PWM output frequency. 804 /// Sets the PWM output frequency.
789 #[inline(always)] 805 #[inline(always)]
790 pub fn set_period(&self, freq: u32) { 806 pub fn set_period(&self, freq: u32) {
791 let clk = 16_000_000u32 >> (self.prescaler() as u8); 807 let clk = PWM_CLK_HZ >> (self.prescaler() as u8);
792 let duty = clk / freq; 808 let duty = clk / freq;
793 self.set_max_duty(duty.min(32767) as u16); 809 self.set_max_duty(duty.min(32767) as u16);
794 } 810 }
@@ -796,7 +812,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
796 /// Returns the PWM output frequency. 812 /// Returns the PWM output frequency.
797 #[inline(always)] 813 #[inline(always)]
798 pub fn period(&self) -> u32 { 814 pub fn period(&self) -> u32 {
799 let clk = 16_000_000u32 >> (self.prescaler() as u8); 815 let clk = PWM_CLK_HZ >> (self.prescaler() as u8);
800 let max_duty = self.max_duty() as u32; 816 let max_duty = self.max_duty() as u32;
801 clk / max_duty 817 clk / max_duty
802 } 818 }
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 2aa50a2ba..9455ec925 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -172,18 +172,17 @@ impl<'d, T: Instance> Qdec<'d, T> {
172 t.intenset.write(|w| w.reportrdy().set()); 172 t.intenset.write(|w| w.reportrdy().set());
173 unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; 173 unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
174 174
175 let value = poll_fn(|cx| { 175 poll_fn(|cx| {
176 T::state().waker.register(cx.waker()); 176 T::state().waker.register(cx.waker());
177 if t.events_reportrdy.read().bits() == 0 { 177 if t.events_reportrdy.read().bits() == 0 {
178 return Poll::Pending; 178 Poll::Pending
179 } else { 179 } else {
180 t.events_reportrdy.reset(); 180 t.events_reportrdy.reset();
181 let acc = t.accread.read().bits(); 181 let acc = t.accread.read().bits();
182 Poll::Ready(acc as i16) 182 Poll::Ready(acc as i16)
183 } 183 }
184 }) 184 })
185 .await; 185 .await
186 value
187 } 186 }
188} 187}
189 188
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 8eec09c96..4134a4c87 100755
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -402,7 +402,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
402 /// a raw bus, not with flash memory. 402 /// a raw bus, not with flash memory.
403 pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { 403 pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
404 // Avoid blocking_wait_ready() blocking forever on zero-length buffers. 404 // Avoid blocking_wait_ready() blocking forever on zero-length buffers.
405 if data.len() == 0 { 405 if data.is_empty() {
406 return Ok(()); 406 return Ok(());
407 } 407 }
408 408
@@ -423,7 +423,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
423 /// a raw bus, not with flash memory. 423 /// a raw bus, not with flash memory.
424 pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { 424 pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
425 // Avoid blocking_wait_ready() blocking forever on zero-length buffers. 425 // Avoid blocking_wait_ready() blocking forever on zero-length buffers.
426 if data.len() == 0 { 426 if data.is_empty() {
427 return Ok(()); 427 return Ok(());
428 } 428 }
429 429
@@ -444,7 +444,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
444 /// a raw bus, not with flash memory. 444 /// a raw bus, not with flash memory.
445 pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { 445 pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
446 // Avoid blocking_wait_ready() blocking forever on zero-length buffers. 446 // Avoid blocking_wait_ready() blocking forever on zero-length buffers.
447 if data.len() == 0 { 447 if data.is_empty() {
448 return Ok(()); 448 return Ok(());
449 } 449 }
450 450
@@ -460,7 +460,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
460 /// a raw bus, not with flash memory. 460 /// a raw bus, not with flash memory.
461 pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { 461 pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
462 // Avoid blocking_wait_ready() blocking forever on zero-length buffers. 462 // Avoid blocking_wait_ready() blocking forever on zero-length buffers.
463 if data.len() == 0 { 463 if data.is_empty() {
464 return Ok(()); 464 return Ok(());
465 } 465 }
466 466
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs
new file mode 100644
index 000000000..93003fb19
--- /dev/null
+++ b/embassy-nrf/src/radio/ble.rs
@@ -0,0 +1,417 @@
1//! Radio driver implementation focused on Bluetooth Low-Energy transmission.
2
3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll;
6
7use embassy_hal_internal::drop::OnDrop;
8use embassy_hal_internal::{into_ref, PeripheralRef};
9pub use pac::radio::mode::MODE_A as Mode;
10#[cfg(not(feature = "nrf51"))]
11use pac::radio::pcnf0::PLEN_A as PreambleLength;
12
13use crate::interrupt::typelevel::Interrupt;
14use crate::radio::*;
15pub use crate::radio::{Error, TxPower};
16use crate::util::slice_in_ram_or;
17
18/// Radio driver.
19pub struct Radio<'d, T: Instance> {
20 _p: PeripheralRef<'d, T>,
21}
22
23impl<'d, T: Instance> Radio<'d, T> {
24 /// Create a new radio driver.
25 pub fn new(
26 radio: impl Peripheral<P = T> + 'd,
27 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
28 ) -> Self {
29 into_ref!(radio);
30
31 let r = T::regs();
32
33 r.pcnf1.write(|w| unsafe {
34 // It is 0 bytes long in a standard BLE packet
35 w.statlen()
36 .bits(0)
37 // MaxLen configures the maximum packet payload plus add-on size in
38 // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
39 // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
40 // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
41 // packet larger than MAXLEN, the payload will be truncated at MAXLEN
42 //
43 // To simplify the implementation, It is setted as the maximum value
44 // and the length of the packet is controlled only by the LENGTH field in the packet
45 .maxlen()
46 .bits(255)
47 // Configure the length of the address field in the packet
48 // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
49 // The base address is truncated from the least significant byte if the BALEN is less than 4
50 //
51 // BLE address is always 4 bytes long
52 .balen()
53 .bits(3) // 3 bytes base address (+ 1 prefix);
54 // Configure the endianess
55 // For BLE is always little endian (LSB first)
56 .endian()
57 .little()
58 // Data whitening is used to avoid long sequences of zeros or
59 // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
60 // The whitener and de-whitener are defined the same way,
61 // using a 7-bit linear feedback shift register with the
62 // polynomial x7 + x4 + 1.
63 //
64 // In BLE Whitening shall be applied on the PDU and CRC of all
65 // Link Layer packets and is performed after the CRC generation
66 // in the transmitter. No other parts of the packets are whitened.
67 // De-whitening is performed before the CRC checking in the receiver
68 // Before whitening or de-whitening, the shift register should be
69 // initialized based on the channel index.
70 .whiteen()
71 .set_bit()
72 });
73
74 // Configure CRC
75 r.crccnf.write(|w| {
76 // In BLE the CRC shall be calculated on the PDU of all Link Layer
77 // packets (even if the packet is encrypted).
78 // It skips the address field
79 w.skipaddr()
80 .skip()
81 // In BLE 24-bit CRC = 3 bytes
82 .len()
83 .three()
84 });
85
86 // Ch map between 2400 MHZ .. 2500 MHz
87 // All modes use this range
88 #[cfg(not(feature = "nrf51"))]
89 r.frequency.write(|w| w.map().default());
90
91 // Configure shortcuts to simplify and speed up sending and receiving packets.
92 r.shorts.write(|w| {
93 // start transmission/recv immediately after ramp-up
94 // disable radio when transmission/recv is done
95 w.ready_start().enabled().end_disable().enabled()
96 });
97
98 // Enable NVIC interrupt
99 T::Interrupt::unpend();
100 unsafe { T::Interrupt::enable() };
101
102 Self { _p: radio }
103 }
104
105 fn state(&self) -> RadioState {
106 super::state(T::regs())
107 }
108
109 /// Set the radio mode
110 ///
111 /// The radio must be disabled before calling this function
112 pub fn set_mode(&mut self, mode: Mode) {
113 assert!(self.state() == RadioState::DISABLED);
114
115 let r = T::regs();
116 r.mode.write(|w| w.mode().variant(mode));
117
118 #[cfg(not(feature = "nrf51"))]
119 r.pcnf0.write(|w| {
120 w.plen().variant(match mode {
121 Mode::BLE_1MBIT => PreambleLength::_8BIT,
122 Mode::BLE_2MBIT => PreambleLength::_16BIT,
123 #[cfg(any(
124 feature = "nrf52811",
125 feature = "nrf52820",
126 feature = "nrf52833",
127 feature = "nrf52840",
128 feature = "_nrf5340-net"
129 ))]
130 Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE,
131 _ => unimplemented!(),
132 })
133 });
134 }
135
136 /// Set the header size changing the S1's len field
137 ///
138 /// The radio must be disabled before calling this function
139 pub fn set_header_expansion(&mut self, use_s1_field: bool) {
140 assert!(self.state() == RadioState::DISABLED);
141
142 let r = T::regs();
143
144 // s1 len in bits
145 let s1len: u8 = match use_s1_field {
146 false => 0,
147 true => 8,
148 };
149
150 r.pcnf0.write(|w| unsafe {
151 w
152 // Configure S0 to 1 byte length, this will represent the Data/Adv header flags
153 .s0len()
154 .set_bit()
155 // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
156 // and also be used to know how many bytes to read/write from/to the buffer
157 .lflen()
158 .bits(8)
159 // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
160 .s1len()
161 .bits(s1len)
162 });
163 }
164
165 /// Set initial data whitening value
166 /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream
167 /// On BLE the initial value is the channel index | 0x40
168 ///
169 /// The radio must be disabled before calling this function
170 pub fn set_whitening_init(&mut self, whitening_init: u8) {
171 assert!(self.state() == RadioState::DISABLED);
172
173 let r = T::regs();
174
175 r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) });
176 }
177
178 /// Set the central frequency to be used
179 /// It should be in the range 2400..2500
180 ///
181 /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change)
182 pub fn set_frequency(&mut self, frequency: u32) {
183 assert!(self.state() == RadioState::DISABLED);
184 assert!((2400..=2500).contains(&frequency));
185
186 let r = T::regs();
187
188 r.frequency
189 .write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) });
190 }
191
192 /// Set the acess address
193 /// This address is always constants for advertising
194 /// And a random value generate on each connection
195 /// It is used to filter the packages
196 ///
197 /// The radio must be disabled before calling this function
198 pub fn set_access_address(&mut self, access_address: u32) {
199 assert!(self.state() == RadioState::DISABLED);
200
201 let r = T::regs();
202
203 // Configure logical address
204 // The byte ordering on air is always least significant byte first for the address
205 // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA
206 // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA
207 r.prefix0
208 .write(|w| unsafe { w.ap0().bits((access_address >> 24) as u8) });
209
210 // The base address is truncated from the least significant byte (because the BALEN is less than 4)
211 // So it shifts the address to the right
212 r.base0.write(|w| unsafe { w.bits(access_address << 8) });
213
214 // Don't match tx address
215 r.txaddress.write(|w| unsafe { w.txaddress().bits(0) });
216
217 // Match on logical address
218 // This config only filter the packets by the address,
219 // so only packages send to the previous address
220 // will finish the reception (TODO: check the explanation)
221 r.rxaddresses.write(|w| {
222 w.addr0()
223 .enabled()
224 .addr1()
225 .enabled()
226 .addr2()
227 .enabled()
228 .addr3()
229 .enabled()
230 .addr4()
231 .enabled()
232 });
233 }
234
235 /// Set the CRC polynomial
236 /// It only uses the 24 least significant bits
237 ///
238 /// The radio must be disabled before calling this function
239 pub fn set_crc_poly(&mut self, crc_poly: u32) {
240 assert!(self.state() == RadioState::DISABLED);
241
242 let r = T::regs();
243
244 r.crcpoly.write(|w| unsafe {
245 // Configure the CRC polynomial
246 // Each term in the CRC polynomial is mapped to a bit in this
247 // register which index corresponds to the term's exponent.
248 // The least significant term/bit is hard-wired internally to
249 // 1, and bit number 0 of the register content is ignored by
250 // the hardware. The following example is for an 8 bit CRC
251 // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
252 w.crcpoly().bits(crc_poly & 0xFFFFFF)
253 });
254 }
255
256 /// Set the CRC init value
257 /// It only uses the 24 least significant bits
258 /// The CRC initial value varies depending of the PDU type
259 ///
260 /// The radio must be disabled before calling this function
261 pub fn set_crc_init(&mut self, crc_init: u32) {
262 assert!(self.state() == RadioState::DISABLED);
263
264 let r = T::regs();
265
266 r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) });
267 }
268
269 /// Set the radio tx power
270 ///
271 /// The radio must be disabled before calling this function
272 pub fn set_tx_power(&mut self, tx_power: TxPower) {
273 assert!(self.state() == RadioState::DISABLED);
274
275 let r = T::regs();
276
277 r.txpower.write(|w| w.txpower().variant(tx_power));
278 }
279
280 /// Set buffer to read/write
281 ///
282 /// This method is unsound. You should guarantee that the buffer will live
283 /// for the life time of the transmission or if the buffer will be modified.
284 /// Also if the buffer is smaller than the packet length, the radio will
285 /// read/write memory out of the buffer bounds.
286 fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
287 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
288
289 let r = T::regs();
290
291 // Here it consider that the length of the packet is
292 // correctly set in the buffer, otherwise it will send
293 // unowned regions of memory
294 let ptr = buffer.as_ptr();
295
296 // Configure the payload
297 r.packetptr.write(|w| unsafe { w.bits(ptr as u32) });
298
299 Ok(())
300 }
301
302 /// Send packet
303 /// If the length byte in the package is greater than the buffer length
304 /// the radio will read memory out of the buffer bounds
305 pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> {
306 self.set_buffer(buffer)?;
307
308 let r = T::regs();
309 self.trigger_and_wait_end(move || {
310 // Initialize the transmission
311 // trace!("txen");
312
313 r.tasks_txen.write(|w| unsafe { w.bits(1) });
314 })
315 .await;
316
317 Ok(())
318 }
319
320 /// Receive packet
321 /// If the length byte in the received package is greater than the buffer length
322 /// the radio will write memory out of the buffer bounds
323 pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
324 self.set_buffer(buffer)?;
325
326 let r = T::regs();
327 self.trigger_and_wait_end(move || {
328 // Initialize the transmission
329 // trace!("rxen");
330 r.tasks_rxen.write(|w| unsafe { w.bits(1) });
331 })
332 .await;
333
334 Ok(())
335 }
336
337 async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) {
338 //self.trace_state();
339
340 let r = T::regs();
341 let s = T::state();
342
343 // If the Future is dropped before the end of the transmission
344 // it disable the interrupt and stop the transmission
345 // to keep the state consistent
346 let drop = OnDrop::new(|| {
347 trace!("radio drop: stopping");
348
349 r.intenclr.write(|w| w.end().clear());
350 r.events_end.reset();
351
352 r.tasks_stop.write(|w| unsafe { w.bits(1) });
353
354 // The docs don't explicitly mention any event to acknowledge the stop task
355 while r.events_end.read().bits() == 0 {}
356
357 trace!("radio drop: stopped");
358 });
359
360 // trace!("radio:enable interrupt");
361 // Clear some remnant side-effects (TODO: check if this is necessary)
362 r.events_end.reset();
363
364 // Enable interrupt
365 r.intenset.write(|w| w.end().set());
366
367 compiler_fence(Ordering::SeqCst);
368
369 // Trigger the transmission
370 trigger();
371 // self.trace_state();
372
373 // On poll check if interrupt happen
374 poll_fn(|cx| {
375 s.event_waker.register(cx.waker());
376 if r.events_end.read().bits() == 1 {
377 // trace!("radio:end");
378 return core::task::Poll::Ready(());
379 }
380 Poll::Pending
381 })
382 .await;
383
384 compiler_fence(Ordering::SeqCst);
385 r.events_disabled.reset(); // ACK
386
387 // Everthing ends fine, so it disable the drop
388 drop.defuse();
389 }
390
391 /// Disable the radio
392 fn disable(&mut self) {
393 let r = T::regs();
394
395 compiler_fence(Ordering::SeqCst);
396 // If it is already disabled, do nothing
397 if self.state() != RadioState::DISABLED {
398 trace!("radio:disable");
399 // Trigger the disable task
400 r.tasks_disable.write(|w| unsafe { w.bits(1) });
401
402 // Wait until the radio is disabled
403 while r.events_disabled.read().bits() == 0 {}
404
405 compiler_fence(Ordering::SeqCst);
406
407 // Acknowledge it
408 r.events_disabled.reset();
409 }
410 }
411}
412
413impl<'d, T: Instance> Drop for Radio<'d, T> {
414 fn drop(&mut self) {
415 self.disable();
416 }
417}
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs
new file mode 100644
index 000000000..298f8a574
--- /dev/null
+++ b/embassy-nrf/src/radio/ieee802154.rs
@@ -0,0 +1,546 @@
1//! IEEE 802.15.4 radio driver
2
3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll;
5
6use embassy_hal_internal::drop::OnDrop;
7use embassy_hal_internal::{into_ref, PeripheralRef};
8
9use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower};
10use crate::interrupt::typelevel::Interrupt;
11use crate::interrupt::{self};
12use crate::Peripheral;
13
14/// Default (IEEE compliant) Start of Frame Delimiter
15pub const DEFAULT_SFD: u8 = 0xA7;
16
17// TODO expose the other variants in `pac::CCAMODE_A`
18/// Clear Channel Assessment method
19pub enum Cca {
20 /// Carrier sense
21 CarrierSense,
22 /// Energy Detection / Energy Above Threshold
23 EnergyDetection {
24 /// Energy measurements above this value mean that the channel is assumed to be busy.
25 /// Note the measurement range is 0..0xFF - where 0 means that the received power was
26 /// less than 10 dB above the selected receiver sensitivity. This value is not given in dBm,
27 /// but can be converted. See the nrf52840 Product Specification Section 6.20.12.4
28 /// for details.
29 ed_threshold: u8,
30 },
31}
32
33/// IEEE 802.15.4 radio driver.
34pub struct Radio<'d, T: Instance> {
35 _p: PeripheralRef<'d, T>,
36 needs_enable: bool,
37}
38
39impl<'d, T: Instance> Radio<'d, T> {
40 /// Create a new IEEE 802.15.4 radio driver.
41 pub fn new(
42 radio: impl Peripheral<P = T> + 'd,
43 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
44 ) -> Self {
45 into_ref!(radio);
46
47 let r = T::regs();
48
49 // Disable and enable to reset peripheral
50 r.power.write(|w| w.power().disabled());
51 r.power.write(|w| w.power().enabled());
52
53 // Enable 802.15.4 mode
54 r.mode.write(|w| w.mode().ieee802154_250kbit());
55 // Configure CRC skip address
56 r.crccnf.write(|w| w.len().two().skipaddr().ieee802154());
57 unsafe {
58 // Configure CRC polynomial and init
59 r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021));
60 r.crcinit.write(|w| w.crcinit().bits(0));
61 r.pcnf0.write(|w| {
62 // 8-bit on air length
63 w.lflen()
64 .bits(8)
65 // Zero bytes S0 field length
66 .s0len()
67 .clear_bit()
68 // Zero bytes S1 field length
69 .s1len()
70 .bits(0)
71 // Do not include S1 field in RAM if S1 length > 0
72 .s1incl()
73 .clear_bit()
74 // Zero code Indicator length
75 .cilen()
76 .bits(0)
77 // 32-bit zero preamble
78 .plen()
79 ._32bit_zero()
80 // Include CRC in length
81 .crcinc()
82 .include()
83 });
84 r.pcnf1.write(|w| {
85 // Maximum packet length
86 w.maxlen()
87 .bits(Packet::MAX_PSDU_LEN)
88 // Zero static length
89 .statlen()
90 .bits(0)
91 // Zero base address length
92 .balen()
93 .bits(0)
94 // Little-endian
95 .endian()
96 .clear_bit()
97 // Disable packet whitening
98 .whiteen()
99 .clear_bit()
100 });
101 }
102
103 // Enable NVIC interrupt
104 T::Interrupt::unpend();
105 unsafe { T::Interrupt::enable() };
106
107 let mut radio = Self {
108 _p: radio,
109 needs_enable: false,
110 };
111
112 radio.set_sfd(DEFAULT_SFD);
113 radio.set_transmission_power(0);
114 radio.set_channel(11);
115 radio.set_cca(Cca::CarrierSense);
116
117 radio
118 }
119
120 /// Changes the radio channel
121 pub fn set_channel(&mut self, channel: u8) {
122 let r = T::regs();
123 if channel < 11 || channel > 26 {
124 panic!("Bad 802.15.4 channel");
125 }
126 let frequency_offset = (channel - 10) * 5;
127 self.needs_enable = true;
128 r.frequency
129 .write(|w| unsafe { w.frequency().bits(frequency_offset).map().default() });
130 }
131
132 /// Changes the Clear Channel Assessment method
133 pub fn set_cca(&mut self, cca: Cca) {
134 let r = T::regs();
135 self.needs_enable = true;
136 match cca {
137 Cca::CarrierSense => r.ccactrl.write(|w| w.ccamode().carrier_mode()),
138 Cca::EnergyDetection { ed_threshold } => {
139 // "[ED] is enabled by first configuring the field CCAMODE=EdMode in CCACTRL
140 // and writing the CCAEDTHRES field to a chosen value."
141 r.ccactrl
142 .write(|w| unsafe { w.ccamode().ed_mode().ccaedthres().bits(ed_threshold) });
143 }
144 }
145 }
146
147 /// Changes the Start of Frame Delimiter (SFD)
148 pub fn set_sfd(&mut self, sfd: u8) {
149 let r = T::regs();
150 r.sfd.write(|w| unsafe { w.sfd().bits(sfd) });
151 }
152
153 /// Clear interrupts
154 pub fn clear_all_interrupts(&mut self) {
155 let r = T::regs();
156 r.intenclr.write(|w| unsafe { w.bits(0xffff_ffff) });
157 }
158
159 /// Changes the radio transmission power
160 pub fn set_transmission_power(&mut self, power: i8) {
161 let r = T::regs();
162 self.needs_enable = true;
163
164 let tx_power: TxPower = match power {
165 #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
166 8 => TxPower::POS8D_BM,
167 #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
168 7 => TxPower::POS7D_BM,
169 #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
170 6 => TxPower::POS6D_BM,
171 #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
172 5 => TxPower::POS5D_BM,
173 #[cfg(not(feature = "_nrf5340-net"))]
174 4 => TxPower::POS4D_BM,
175 #[cfg(not(feature = "_nrf5340-net"))]
176 3 => TxPower::POS3D_BM,
177 #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))]
178 2 => TxPower::POS2D_BM,
179 0 => TxPower::_0D_BM,
180 #[cfg(feature = "_nrf5340-net")]
181 -1 => TxPower::NEG1D_BM,
182 #[cfg(feature = "_nrf5340-net")]
183 -2 => TxPower::NEG2D_BM,
184 #[cfg(feature = "_nrf5340-net")]
185 -3 => TxPower::NEG3D_BM,
186 -4 => TxPower::NEG4D_BM,
187 #[cfg(feature = "_nrf5340-net")]
188 -5 => TxPower::NEG5D_BM,
189 #[cfg(feature = "_nrf5340-net")]
190 -6 => TxPower::NEG6D_BM,
191 #[cfg(feature = "_nrf5340-net")]
192 -7 => TxPower::NEG7D_BM,
193 -8 => TxPower::NEG8D_BM,
194 -12 => TxPower::NEG12D_BM,
195 -16 => TxPower::NEG16D_BM,
196 -20 => TxPower::NEG20D_BM,
197 -30 => TxPower::NEG30D_BM,
198 -40 => TxPower::NEG40D_BM,
199 _ => panic!("Invalid transmission power value"),
200 };
201
202 r.txpower.write(|w| w.txpower().variant(tx_power));
203 }
204
205 /// Waits until the radio state matches the given `state`
206 fn wait_for_radio_state(&self, state: RadioState) {
207 while self.state() != state {}
208 }
209
210 /// Get the current radio state
211 fn state(&self) -> RadioState {
212 state(T::regs())
213 }
214
215 /// Moves the radio from any state to the DISABLED state
216 fn disable(&mut self) {
217 let r = T::regs();
218 // See figure 110 in nRF52840-PS
219 loop {
220 match self.state() {
221 RadioState::DISABLED => return,
222 // idle or ramping up
223 RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => {
224 r.tasks_disable.write(|w| w.tasks_disable().set_bit());
225 self.wait_for_radio_state(RadioState::DISABLED);
226 return;
227 }
228 // ramping down
229 RadioState::RX_DISABLE | RadioState::TX_DISABLE => {
230 self.wait_for_radio_state(RadioState::DISABLED);
231 return;
232 }
233 // cancel ongoing transfer or ongoing CCA
234 RadioState::RX => {
235 r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit());
236 r.tasks_stop.write(|w| w.tasks_stop().set_bit());
237 self.wait_for_radio_state(RadioState::RX_IDLE);
238 }
239 RadioState::TX => {
240 r.tasks_stop.write(|w| w.tasks_stop().set_bit());
241 self.wait_for_radio_state(RadioState::TX_IDLE);
242 }
243 }
244 }
245 }
246
247 fn set_buffer(&mut self, buffer: &[u8]) {
248 let r = T::regs();
249 r.packetptr.write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
250 }
251
252 /// Moves the radio to the RXIDLE state
253 fn receive_prepare(&mut self) {
254 // clear related events
255 T::regs().events_ccabusy.reset();
256 T::regs().events_phyend.reset();
257 // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE
258 let disable = match self.state() {
259 RadioState::DISABLED => false,
260 RadioState::RX_IDLE => self.needs_enable,
261 _ => true,
262 };
263 if disable {
264 self.disable();
265 }
266 self.needs_enable = false;
267 }
268
269 /// Prepare radio for receiving a packet
270 fn receive_start(&mut self, packet: &mut Packet) {
271 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's
272 // allocated in RAM
273 let r = T::regs();
274
275 self.receive_prepare();
276
277 // Configure shortcuts
278 //
279 // The radio goes through following states when receiving a 802.15.4 packet
280 //
281 // enable RX → ramp up RX → RX idle → Receive → end (PHYEND)
282 r.shorts.write(|w| w.rxready_start().enabled());
283
284 // set up RX buffer
285 self.set_buffer(packet.buffer.as_mut());
286
287 // start transfer
288 dma_start_fence();
289
290 match self.state() {
291 // Re-start receiver
292 RadioState::RX_IDLE => r.tasks_start.write(|w| w.tasks_start().set_bit()),
293 // Enable receiver
294 _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()),
295 }
296 }
297
298 /// Cancel receiving packet
299 fn receive_cancel() {
300 let r = T::regs();
301 r.shorts.reset();
302 r.tasks_stop.write(|w| w.tasks_stop().set_bit());
303 loop {
304 match state(r) {
305 RadioState::DISABLED | RadioState::RX_IDLE => break,
306 _ => (),
307 }
308 }
309 // DMA transfer may have been in progress so synchronize with its memory operations
310 dma_end_fence();
311 }
312
313 /// Receives one radio packet and copies its contents into the given `packet` buffer
314 ///
315 /// This methods returns the `Ok` variant if the CRC included the packet was successfully
316 /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet`
317 /// will be updated with the received packet's data
318 pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), Error> {
319 let s = T::state();
320 let r = T::regs();
321
322 // Start the read
323 self.receive_start(packet);
324
325 let dropper = OnDrop::new(|| Self::receive_cancel());
326
327 self.clear_all_interrupts();
328 // wait until we have received something
329 core::future::poll_fn(|cx| {
330 s.event_waker.register(cx.waker());
331
332 if r.events_phyend.read().events_phyend().bit_is_set() {
333 r.events_phyend.reset();
334 trace!("RX done poll");
335 return Poll::Ready(());
336 } else {
337 r.intenset.write(|w| w.phyend().set());
338 };
339
340 Poll::Pending
341 })
342 .await;
343
344 dma_end_fence();
345 dropper.defuse();
346
347 let crc = r.rxcrc.read().rxcrc().bits() as u16;
348 if r.crcstatus.read().crcstatus().bit_is_set() {
349 Ok(())
350 } else {
351 Err(Error::CrcFailed(crc))
352 }
353 }
354
355 /// Tries to send the given `packet`
356 ///
357 /// This method performs Clear Channel Assessment (CCA) first and sends the `packet` only if the
358 /// channel is observed to be *clear* (no transmission is currently ongoing), otherwise no
359 /// packet is transmitted and the `Err` variant is returned
360 ///
361 /// NOTE this method will *not* modify the `packet` argument. The mutable reference is used to
362 /// ensure the `packet` buffer is allocated in RAM, which is required by the RADIO peripheral
363 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's
364 // allocated in RAM
365 pub async fn try_send(&mut self, packet: &mut Packet) -> Result<(), Error> {
366 let s = T::state();
367 let r = T::regs();
368
369 // enable radio to perform cca
370 self.receive_prepare();
371
372 /// transmit result
373 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
374 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
375 pub enum TransmitResult {
376 /// Success
377 Success,
378 /// Clear channel assessment reported channel in use
379 ChannelInUse,
380 }
381
382 // Configure shortcuts
383 //
384 // The radio goes through following states when sending a 802.15.4 packet
385 //
386 // enable RX → ramp up RX → clear channel assessment (CCA) → CCA result
387 // CCA idle → enable TX → start TX → TX → end (PHYEND) → disabled
388 //
389 // CCA might end up in the event CCABUSY in which there will be no transmission
390 r.shorts.write(|w| {
391 w.rxready_ccastart()
392 .enabled()
393 .ccaidle_txen()
394 .enabled()
395 .txready_start()
396 .enabled()
397 .ccabusy_disable()
398 .enabled()
399 .phyend_disable()
400 .enabled()
401 });
402
403 // Set transmission buffer
404 self.set_buffer(packet.buffer.as_mut());
405
406 // the DMA transfer will start at some point after the following write operation so
407 // we place the compiler fence here
408 dma_start_fence();
409 // start CCA. In case the channel is clear, the data at packetptr will be sent automatically
410
411 match self.state() {
412 // Re-start receiver
413 RadioState::RX_IDLE => r.tasks_ccastart.write(|w| w.tasks_ccastart().set_bit()),
414 // Enable receiver
415 _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()),
416 }
417
418 self.clear_all_interrupts();
419 let result = core::future::poll_fn(|cx| {
420 s.event_waker.register(cx.waker());
421
422 if r.events_phyend.read().events_phyend().bit_is_set() {
423 r.events_phyend.reset();
424 r.events_ccabusy.reset();
425 trace!("TX done poll");
426 return Poll::Ready(TransmitResult::Success);
427 } else if r.events_ccabusy.read().events_ccabusy().bit_is_set() {
428 r.events_ccabusy.reset();
429 trace!("TX no CCA");
430 return Poll::Ready(TransmitResult::ChannelInUse);
431 }
432
433 r.intenset.write(|w| w.phyend().set().ccabusy().set());
434
435 Poll::Pending
436 })
437 .await;
438
439 match result {
440 TransmitResult::Success => Ok(()),
441 TransmitResult::ChannelInUse => Err(Error::ChannelInUse),
442 }
443 }
444}
445
446/// An IEEE 802.15.4 packet
447///
448/// This `Packet` is a PHY layer packet. It's made up of the physical header (PHR) and the PSDU
449/// (PHY service data unit). The PSDU of this `Packet` will always include the MAC level CRC, AKA
450/// the FCS (Frame Control Sequence) -- the CRC is fully computed in hardware and automatically
451/// appended on transmission and verified on reception.
452///
453/// The API lets users modify the usable part (not the CRC) of the PSDU via the `deref` and
454/// `copy_from_slice` methods. These methods will automatically update the PHR.
455///
456/// See figure 119 in the Product Specification of the nRF52840 for more details
457pub struct Packet {
458 buffer: [u8; Self::SIZE],
459}
460
461// See figure 124 in nRF52840-PS
462impl Packet {
463 // for indexing purposes
464 const PHY_HDR: usize = 0;
465 const DATA: core::ops::RangeFrom<usize> = 1..;
466
467 /// Maximum amount of usable payload (CRC excluded) a single packet can contain, in bytes
468 pub const CAPACITY: u8 = 125;
469 const CRC: u8 = 2; // size of the CRC, which is *never* copied to / from RAM
470 const MAX_PSDU_LEN: u8 = Self::CAPACITY + Self::CRC;
471 const SIZE: usize = 1 /* PHR */ + Self::MAX_PSDU_LEN as usize;
472
473 /// Returns an empty packet (length = 0)
474 pub fn new() -> Self {
475 let mut packet = Self {
476 buffer: [0; Self::SIZE],
477 };
478 packet.set_len(0);
479 packet
480 }
481
482 /// Fills the packet payload with given `src` data
483 ///
484 /// # Panics
485 ///
486 /// This function panics if `src` is larger than `Self::CAPACITY`
487 pub fn copy_from_slice(&mut self, src: &[u8]) {
488 assert!(src.len() <= Self::CAPACITY as usize);
489 let len = src.len() as u8;
490 self.buffer[Self::DATA][..len as usize].copy_from_slice(&src[..len.into()]);
491 self.set_len(len);
492 }
493
494 /// Returns the size of this packet's payload
495 pub fn len(&self) -> u8 {
496 self.buffer[Self::PHY_HDR] - Self::CRC
497 }
498
499 /// Changes the size of the packet's payload
500 ///
501 /// # Panics
502 ///
503 /// This function panics if `len` is larger than `Self::CAPACITY`
504 pub fn set_len(&mut self, len: u8) {
505 assert!(len <= Self::CAPACITY);
506 self.buffer[Self::PHY_HDR] = len + Self::CRC;
507 }
508
509 /// Returns the LQI (Link Quality Indicator) of the received packet
510 ///
511 /// Note that the LQI is stored in the `Packet`'s internal buffer by the hardware so the value
512 /// returned by this method is only valid after a `Radio.recv` operation. Operations that
513 /// modify the `Packet`, like `copy_from_slice` or `set_len`+`deref_mut`, will overwrite the
514 /// stored LQI value.
515 ///
516 /// Also note that the hardware will *not* compute a LQI for packets smaller than 3 bytes so
517 /// this method will return an invalid value for those packets.
518 pub fn lqi(&self) -> u8 {
519 self.buffer[1 /* PHY_HDR */ + self.len() as usize /* data */]
520 }
521}
522
523impl core::ops::Deref for Packet {
524 type Target = [u8];
525
526 fn deref(&self) -> &[u8] {
527 &self.buffer[Self::DATA][..self.len() as usize]
528 }
529}
530
531impl core::ops::DerefMut for Packet {
532 fn deref_mut(&mut self) -> &mut [u8] {
533 let len = self.len();
534 &mut self.buffer[Self::DATA][..len as usize]
535 }
536}
537
538/// NOTE must be followed by a volatile write operation
539fn dma_start_fence() {
540 compiler_fence(Ordering::Release);
541}
542
543/// NOTE must be preceded by a volatile read operation
544fn dma_end_fence() {
545 compiler_fence(Ordering::Acquire);
546}
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs
new file mode 100644
index 000000000..4c0cc3280
--- /dev/null
+++ b/embassy-nrf/src/radio/mod.rs
@@ -0,0 +1,110 @@
1//! Integrated 2.4 GHz Radio
2//!
3//! The 2.4 GHz radio transceiver is compatible with multiple radio standards
4//! such as 1Mbps, 2Mbps and Long Range Bluetooth Low Energy.
5
6#![macro_use]
7
8/// Bluetooth Low Energy Radio driver.
9pub mod ble;
10#[cfg(any(
11 feature = "nrf52811",
12 feature = "nrf52820",
13 feature = "nrf52833",
14 feature = "nrf52840",
15 feature = "_nrf5340-net"
16))]
17/// IEEE 802.15.4
18pub mod ieee802154;
19
20use core::marker::PhantomData;
21
22use pac::radio::state::STATE_A as RadioState;
23pub use pac::radio::txpower::TXPOWER_A as TxPower;
24
25use crate::{interrupt, pac, Peripheral};
26
27/// RADIO error.
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30#[non_exhaustive]
31pub enum Error {
32 /// Buffer was too long.
33 BufferTooLong,
34 /// Buffer was too short.
35 BufferTooShort,
36 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
37 BufferNotInRAM,
38 /// Clear channel assessment reported channel in use
39 ChannelInUse,
40 /// CRC check failed
41 CrcFailed(u16),
42}
43
44/// Interrupt handler
45pub struct InterruptHandler<T: Instance> {
46 _phantom: PhantomData<T>,
47}
48
49impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
50 unsafe fn on_interrupt() {
51 let r = T::regs();
52 let s = T::state();
53 // clear all interrupts
54 r.intenclr.write(|w| w.bits(0xffff_ffff));
55 s.event_waker.wake();
56 }
57}
58
59pub(crate) mod sealed {
60 use embassy_sync::waitqueue::AtomicWaker;
61
62 pub struct State {
63 /// end packet transmission or reception
64 pub event_waker: AtomicWaker,
65 }
66 impl State {
67 pub const fn new() -> Self {
68 Self {
69 event_waker: AtomicWaker::new(),
70 }
71 }
72 }
73
74 pub trait Instance {
75 fn regs() -> &'static crate::pac::radio::RegisterBlock;
76 fn state() -> &'static State;
77 }
78}
79
80macro_rules! impl_radio {
81 ($type:ident, $pac_type:ident, $irq:ident) => {
82 impl crate::radio::sealed::Instance for peripherals::$type {
83 fn regs() -> &'static pac::radio::RegisterBlock {
84 unsafe { &*pac::$pac_type::ptr() }
85 }
86
87 fn state() -> &'static crate::radio::sealed::State {
88 static STATE: crate::radio::sealed::State = crate::radio::sealed::State::new();
89 &STATE
90 }
91 }
92 impl crate::radio::Instance for peripherals::$type {
93 type Interrupt = crate::interrupt::typelevel::$irq;
94 }
95 };
96}
97
98/// Radio peripheral instance.
99pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
100 /// Interrupt for this peripheral.
101 type Interrupt: interrupt::typelevel::Interrupt;
102}
103
104/// Get the state of the radio
105pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState {
106 match radio.state.read().state().variant() {
107 Some(state) => state,
108 None => unreachable!(),
109 }
110}
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index e2803f0d3..1c463fb7c 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -5,12 +5,10 @@
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::ptr; 7use core::ptr;
8use core::sync::atomic::{AtomicPtr, Ordering};
9use core::task::Poll; 8use core::task::Poll;
10 9
11use embassy_hal_internal::drop::OnDrop; 10use embassy_hal_internal::drop::OnDrop;
12use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::{into_ref, PeripheralRef};
13use embassy_sync::waitqueue::AtomicWaker;
14 12
15use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
16use crate::{interrupt, Peripheral}; 14use crate::{interrupt, Peripheral};
@@ -22,7 +20,6 @@ pub struct InterruptHandler<T: Instance> {
22 20
23impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 21impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
24 unsafe fn on_interrupt() { 22 unsafe fn on_interrupt() {
25 let s = T::state();
26 let r = T::regs(); 23 let r = T::regs();
27 24
28 // Clear the event. 25 // Clear the event.
@@ -30,46 +27,25 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
30 27
31 // Mutate the slice within a critical section, 28 // Mutate the slice within a critical section,
32 // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. 29 // so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
33 let (ptr, end) = critical_section::with(|_| { 30 critical_section::with(|cs| {
34 let ptr = s.ptr.load(Ordering::Relaxed); 31 let mut state = T::state().borrow_mut(cs);
35 // We need to make sure we haven't already filled the whole slice, 32 // We need to make sure we haven't already filled the whole slice,
36 // in case the interrupt fired again before the executor got back to the future. 33 // in case the interrupt fired again before the executor got back to the future.
37 let end = s.end.load(Ordering::Relaxed); 34 if !state.ptr.is_null() && state.ptr != state.end {
38 if !ptr.is_null() && ptr != end {
39 // If the future was dropped, the pointer would have been set to null, 35 // If the future was dropped, the pointer would have been set to null,
40 // so we're still good to mutate the slice. 36 // so we're still good to mutate the slice.
41 // The safety contract of `Rng::new` means that the future can't have been dropped 37 // The safety contract of `Rng::new` means that the future can't have been dropped
42 // without calling its destructor. 38 // without calling its destructor.
43 unsafe { 39 unsafe {
44 *ptr = r.value.read().value().bits(); 40 *state.ptr = r.value.read().value().bits();
41 state.ptr = state.ptr.add(1);
45 } 42 }
46 }
47 (ptr, end)
48 });
49
50 if ptr.is_null() || ptr == end {
51 // If the future was dropped, there's nothing to do.
52 // If `ptr == end`, we were called by mistake, so return.
53 return;
54 }
55 43
56 let new_ptr = unsafe { ptr.add(1) }; 44 if state.ptr == state.end {
57 match s 45 state.waker.wake();
58 .ptr
59 .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
60 {
61 Ok(_) => {
62 let end = s.end.load(Ordering::Relaxed);
63 // It doesn't matter if `end` was changed under our feet, because then this will just be false.
64 if new_ptr == end {
65 s.waker.wake();
66 } 46 }
67 } 47 }
68 Err(_) => { 48 });
69 // If the future was dropped or finished, there's no point trying to wake it.
70 // It will have already stopped the RNG, so there's no need to do that either.
71 }
72 }
73 } 49 }
74} 50}
75 51
@@ -132,17 +108,18 @@ impl<'d, T: Instance> Rng<'d, T> {
132 108
133 /// Fill the buffer with random bytes. 109 /// Fill the buffer with random bytes.
134 pub async fn fill_bytes(&mut self, dest: &mut [u8]) { 110 pub async fn fill_bytes(&mut self, dest: &mut [u8]) {
135 if dest.len() == 0 { 111 if dest.is_empty() {
136 return; // Nothing to fill 112 return; // Nothing to fill
137 } 113 }
138 114
139 let s = T::state();
140
141 let range = dest.as_mut_ptr_range(); 115 let range = dest.as_mut_ptr_range();
142 // Even if we've preempted the interrupt, it can't preempt us again, 116 // Even if we've preempted the interrupt, it can't preempt us again,
143 // so we don't need to worry about the order we write these in. 117 // so we don't need to worry about the order we write these in.
144 s.ptr.store(range.start, Ordering::Relaxed); 118 critical_section::with(|cs| {
145 s.end.store(range.end, Ordering::Relaxed); 119 let mut state = T::state().borrow_mut(cs);
120 state.ptr = range.start;
121 state.end = range.end;
122 });
146 123
147 self.enable_irq(); 124 self.enable_irq();
148 self.start(); 125 self.start();
@@ -151,24 +128,24 @@ impl<'d, T: Instance> Rng<'d, T> {
151 self.stop(); 128 self.stop();
152 self.disable_irq(); 129 self.disable_irq();
153 130
154 // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. 131 critical_section::with(|cs| {
155 s.ptr.store(ptr::null_mut(), Ordering::Relaxed); 132 let mut state = T::state().borrow_mut(cs);
156 s.end.store(ptr::null_mut(), Ordering::Relaxed); 133 state.ptr = ptr::null_mut();
134 state.end = ptr::null_mut();
135 });
157 }); 136 });
158 137
159 poll_fn(|cx| { 138 poll_fn(|cx| {
160 s.waker.register(cx.waker()); 139 critical_section::with(|cs| {
161 140 let mut s = T::state().borrow_mut(cs);
162 // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. 141 s.waker.register(cx.waker());
163 let end = s.end.load(Ordering::Relaxed); 142 if s.ptr == s.end {
164 let ptr = s.ptr.load(Ordering::Relaxed); 143 // We're done.
165 144 Poll::Ready(())
166 if ptr == end { 145 } else {
167 // We're done. 146 Poll::Pending
168 Poll::Ready(()) 147 }
169 } else { 148 })
170 Poll::Pending
171 }
172 }) 149 })
173 .await; 150 .await;
174 151
@@ -194,9 +171,11 @@ impl<'d, T: Instance> Rng<'d, T> {
194impl<'d, T: Instance> Drop for Rng<'d, T> { 171impl<'d, T: Instance> Drop for Rng<'d, T> {
195 fn drop(&mut self) { 172 fn drop(&mut self) {
196 self.stop(); 173 self.stop();
197 let s = T::state(); 174 critical_section::with(|cs| {
198 s.ptr.store(ptr::null_mut(), Ordering::Relaxed); 175 let mut state = T::state().borrow_mut(cs);
199 s.end.store(ptr::null_mut(), Ordering::Relaxed); 176 state.ptr = ptr::null_mut();
177 state.end = ptr::null_mut();
178 });
200 } 179 }
201} 180}
202 181
@@ -227,21 +206,48 @@ impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> {
227impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} 206impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {}
228 207
229pub(crate) mod sealed { 208pub(crate) mod sealed {
209 use core::cell::{Ref, RefCell, RefMut};
210
211 use critical_section::{CriticalSection, Mutex};
212 use embassy_sync::waitqueue::WakerRegistration;
213
230 use super::*; 214 use super::*;
231 215
232 /// Peripheral static state 216 /// Peripheral static state
233 pub struct State { 217 pub struct State {
234 pub ptr: AtomicPtr<u8>, 218 inner: Mutex<RefCell<InnerState>>,
235 pub end: AtomicPtr<u8>, 219 }
236 pub waker: AtomicWaker, 220
221 pub struct InnerState {
222 pub ptr: *mut u8,
223 pub end: *mut u8,
224 pub waker: WakerRegistration,
237 } 225 }
238 226
227 unsafe impl Send for InnerState {}
228
239 impl State { 229 impl State {
240 pub const fn new() -> Self { 230 pub const fn new() -> Self {
241 Self { 231 Self {
242 ptr: AtomicPtr::new(ptr::null_mut()), 232 inner: Mutex::new(RefCell::new(InnerState::new())),
243 end: AtomicPtr::new(ptr::null_mut()), 233 }
244 waker: AtomicWaker::new(), 234 }
235
236 pub fn borrow<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, InnerState> {
237 self.inner.borrow(cs).borrow()
238 }
239
240 pub fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> {
241 self.inner.borrow(cs).borrow_mut()
242 }
243 }
244
245 impl InnerState {
246 pub const fn new() -> Self {
247 Self {
248 ptr: ptr::null_mut(),
249 end: ptr::null_mut(),
250 waker: WakerRegistration::new(),
245 } 251 }
246 } 252 }
247 } 253 }
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index b0723d495..c45d45e68 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -10,13 +10,14 @@ use core::task::Poll;
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::{into_ref, PeripheralRef};
12pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 12pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
13pub use pac::spim0::config::ORDER_A as BitOrder;
13pub use pac::spim0::frequency::FREQUENCY_A as Frequency; 14pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
14 15
15use crate::chip::FORCE_COPY_BUFFER_SIZE; 16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
16use crate::gpio::sealed::Pin as _; 17use crate::gpio::sealed::Pin as _;
17use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 18use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits};
18use crate::interrupt::typelevel::Interrupt; 19use crate::interrupt::typelevel::Interrupt;
19use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 20use crate::util::{slice_in_ram_or, slice_ptr_len, slice_ptr_parts, slice_ptr_parts_mut};
20use crate::{interrupt, pac, Peripheral}; 21use crate::{interrupt, pac, Peripheral};
21 22
22/// SPIM error 23/// SPIM error
@@ -24,10 +25,6 @@ use crate::{interrupt, pac, Peripheral};
24#[cfg_attr(feature = "defmt", derive(defmt::Format))] 25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[non_exhaustive] 26#[non_exhaustive]
26pub enum Error { 27pub enum Error {
27 /// TX buffer was too long.
28 TxBufferTooLong,
29 /// RX buffer was too long.
30 RxBufferTooLong,
31 /// EasyDMA can only read from data memory, read only buffers in flash will fail. 28 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
32 BufferNotInRAM, 29 BufferNotInRAM,
33} 30}
@@ -41,11 +38,23 @@ pub struct Config {
41 /// SPI mode 38 /// SPI mode
42 pub mode: Mode, 39 pub mode: Mode,
43 40
41 /// Bit order
42 pub bit_order: BitOrder,
43
44 /// Overread character. 44 /// Overread character.
45 /// 45 ///
46 /// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer, 46 /// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer,
47 /// this byte will be transmitted in the MOSI line for the left-over bytes. 47 /// this byte will be transmitted in the MOSI line for the left-over bytes.
48 pub orc: u8, 48 pub orc: u8,
49
50 /// Drive strength for the SCK line.
51 pub sck_drive: OutputDrive,
52
53 /// Drive strength for the MOSI line.
54 pub mosi_drive: OutputDrive,
55
56 /// Drive strength for the MISO line.
57 pub miso_drive: OutputDrive,
49} 58}
50 59
51impl Default for Config { 60impl Default for Config {
@@ -53,7 +62,11 @@ impl Default for Config {
53 Self { 62 Self {
54 frequency: Frequency::M1, 63 frequency: Frequency::M1,
55 mode: MODE_0, 64 mode: MODE_0,
65 bit_order: BitOrder::MSB_FIRST,
56 orc: 0x00, 66 orc: 0x00,
67 sck_drive: OutputDrive::HighDrive,
68 mosi_drive: OutputDrive::HighDrive,
69 miso_drive: OutputDrive::HighDrive,
57 } 70 }
58 } 71 }
59} 72}
@@ -69,9 +82,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
69 let s = T::state(); 82 let s = T::state();
70 83
71 #[cfg(feature = "_nrf52832_anomaly_109")] 84 #[cfg(feature = "_nrf52832_anomaly_109")]
72 if r.events_started.read().bits() != 0 { 85 {
73 s.waker.wake(); 86 // Ideally we should call this only during the first chunk transfer,
74 r.intenclr.write(|w| w.started().clear()); 87 // but so far calling this every time doesn't seem to be causing any issues.
88 if r.events_started.read().bits() != 0 {
89 s.waker.wake();
90 r.intenclr.write(|w| w.started().clear());
91 }
75 } 92 }
76 93
77 if r.events_end.read().bits() != 0 { 94 if r.events_end.read().bits() != 0 {
@@ -154,13 +171,16 @@ impl<'d, T: Instance> Spim<'d, T> {
154 171
155 // Configure pins 172 // Configure pins
156 if let Some(sck) = &sck { 173 if let Some(sck) = &sck {
157 sck.conf().write(|w| w.dir().output().drive().h0h1()); 174 sck.conf()
175 .write(|w| w.dir().output().drive().variant(convert_drive(config.sck_drive)));
158 } 176 }
159 if let Some(mosi) = &mosi { 177 if let Some(mosi) = &mosi {
160 mosi.conf().write(|w| w.dir().output().drive().h0h1()); 178 mosi.conf()
179 .write(|w| w.dir().output().drive().variant(convert_drive(config.mosi_drive)));
161 } 180 }
162 if let Some(miso) = &miso { 181 if let Some(miso) = &miso {
163 miso.conf().write(|w| w.input().connect().drive().h0h1()); 182 miso.conf()
183 .write(|w| w.input().connect().drive().variant(convert_drive(config.miso_drive)));
164 } 184 }
165 185
166 match config.mode.polarity { 186 match config.mode.polarity {
@@ -204,27 +224,39 @@ impl<'d, T: Instance> Spim<'d, T> {
204 spim 224 spim
205 } 225 }
206 226
207 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 227 fn prepare_dma_transfer(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
208 slice_in_ram_or(tx, Error::BufferNotInRAM)?;
209 // NOTE: RAM slice check for rx is not necessary, as a mutable
210 // slice can only be built from data located in RAM.
211
212 compiler_fence(Ordering::SeqCst); 228 compiler_fence(Ordering::SeqCst);
213 229
214 let r = T::regs(); 230 let r = T::regs();
215 231
216 // Set up the DMA write. 232 fn xfer_params(ptr: u32, total: usize, offset: usize, length: usize) -> (u32, usize) {
217 let (ptr, tx_len) = slice_ptr_parts(tx); 233 if total > offset {
218 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 234 (ptr.wrapping_add(offset as _), core::cmp::min(total - offset, length))
219 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); 235 } else {
236 (ptr, 0)
237 }
238 }
220 239
221 // Set up the DMA read. 240 // Set up the DMA read.
222 let (ptr, rx_len) = slice_ptr_parts_mut(rx); 241 let (ptr, len) = slice_ptr_parts_mut(rx);
223 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 242 let (rx_ptr, rx_len) = xfer_params(ptr as _, len as _, offset, length);
243 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(rx_ptr) });
224 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); 244 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
225 245
246 // Set up the DMA write.
247 let (ptr, len) = slice_ptr_parts(tx);
248 let (tx_ptr, tx_len) = xfer_params(ptr as _, len as _, offset, length);
249 r.txd.ptr.write(|w| unsafe { w.ptr().bits(tx_ptr) });
250 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) });
251
252 /*
253 trace!("XFER: offset: {}, length: {}", offset, length);
254 trace!("RX(len: {}, ptr: {=u32:02x})", rx_len, rx_ptr as u32);
255 trace!("TX(len: {}, ptr: {=u32:02x})", tx_len, tx_ptr as u32);
256 */
257
226 #[cfg(feature = "_nrf52832_anomaly_109")] 258 #[cfg(feature = "_nrf52832_anomaly_109")]
227 { 259 if offset == 0 {
228 let s = T::state(); 260 let s = T::state();
229 261
230 r.events_started.reset(); 262 r.events_started.reset();
@@ -247,21 +279,32 @@ impl<'d, T: Instance> Spim<'d, T> {
247 279
248 // Start SPI transaction. 280 // Start SPI transaction.
249 r.tasks_start.write(|w| unsafe { w.bits(1) }); 281 r.tasks_start.write(|w| unsafe { w.bits(1) });
250
251 Ok(())
252 } 282 }
253 283
254 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 284 fn blocking_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
255 self.prepare(rx, tx)?; 285 self.prepare_dma_transfer(rx, tx, offset, length);
256 286
257 #[cfg(feature = "_nrf52832_anomaly_109")] 287 #[cfg(feature = "_nrf52832_anomaly_109")]
258 while let Poll::Pending = self.nrf52832_dma_workaround_status() {} 288 if offset == 0 {
289 while self.nrf52832_dma_workaround_status().is_pending() {}
290 }
259 291
260 // Wait for 'end' event. 292 // Wait for 'end' event.
261 while T::regs().events_end.read().bits() == 0 {} 293 while T::regs().events_end.read().bits() == 0 {}
262 294
263 compiler_fence(Ordering::SeqCst); 295 compiler_fence(Ordering::SeqCst);
296 }
264 297
298 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
299 slice_in_ram_or(tx, Error::BufferNotInRAM)?;
300 // NOTE: RAM slice check for rx is not necessary, as a mutable
301 // slice can only be built from data located in RAM.
302
303 let xfer_len = core::cmp::max(slice_ptr_len(rx), slice_ptr_len(tx));
304 for offset in (0..xfer_len).step_by(EASY_DMA_SIZE) {
305 let length = core::cmp::min(xfer_len - offset, EASY_DMA_SIZE);
306 self.blocking_inner_from_ram_chunk(rx, tx, offset, length);
307 }
265 Ok(()) 308 Ok(())
266 } 309 }
267 310
@@ -269,27 +312,28 @@ impl<'d, T: Instance> Spim<'d, T> {
269 match self.blocking_inner_from_ram(rx, tx) { 312 match self.blocking_inner_from_ram(rx, tx) {
270 Ok(_) => Ok(()), 313 Ok(_) => Ok(()),
271 Err(Error::BufferNotInRAM) => { 314 Err(Error::BufferNotInRAM) => {
272 trace!("Copying SPIM tx buffer into RAM for DMA"); 315 // trace!("Copying SPIM tx buffer into RAM for DMA");
273 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 316 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
274 tx_ram_buf.copy_from_slice(tx); 317 tx_ram_buf.copy_from_slice(tx);
275 self.blocking_inner_from_ram(rx, tx_ram_buf) 318 self.blocking_inner_from_ram(rx, tx_ram_buf)
276 } 319 }
277 Err(error) => Err(error),
278 } 320 }
279 } 321 }
280 322
281 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 323 async fn async_inner_from_ram_chunk(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
282 self.prepare(rx, tx)?; 324 self.prepare_dma_transfer(rx, tx, offset, length);
283 325
284 #[cfg(feature = "_nrf52832_anomaly_109")] 326 #[cfg(feature = "_nrf52832_anomaly_109")]
285 poll_fn(|cx| { 327 if offset == 0 {
286 let s = T::state(); 328 poll_fn(|cx| {
329 let s = T::state();
287 330
288 s.waker.register(cx.waker()); 331 s.waker.register(cx.waker());
289 332
290 self.nrf52832_dma_workaround_status() 333 self.nrf52832_dma_workaround_status()
291 }) 334 })
292 .await; 335 .await;
336 }
293 337
294 // Wait for 'end' event. 338 // Wait for 'end' event.
295 poll_fn(|cx| { 339 poll_fn(|cx| {
@@ -303,7 +347,18 @@ impl<'d, T: Instance> Spim<'d, T> {
303 .await; 347 .await;
304 348
305 compiler_fence(Ordering::SeqCst); 349 compiler_fence(Ordering::SeqCst);
350 }
306 351
352 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
353 slice_in_ram_or(tx, Error::BufferNotInRAM)?;
354 // NOTE: RAM slice check for rx is not necessary, as a mutable
355 // slice can only be built from data located in RAM.
356
357 let xfer_len = core::cmp::max(slice_ptr_len(rx), slice_ptr_len(tx));
358 for offset in (0..xfer_len).step_by(EASY_DMA_SIZE) {
359 let length = core::cmp::min(xfer_len - offset, EASY_DMA_SIZE);
360 self.async_inner_from_ram_chunk(rx, tx, offset, length).await;
361 }
307 Ok(()) 362 Ok(())
308 } 363 }
309 364
@@ -311,12 +366,11 @@ impl<'d, T: Instance> Spim<'d, T> {
311 match self.async_inner_from_ram(rx, tx).await { 366 match self.async_inner_from_ram(rx, tx).await {
312 Ok(_) => Ok(()), 367 Ok(_) => Ok(()),
313 Err(Error::BufferNotInRAM) => { 368 Err(Error::BufferNotInRAM) => {
314 trace!("Copying SPIM tx buffer into RAM for DMA"); 369 // trace!("Copying SPIM tx buffer into RAM for DMA");
315 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 370 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
316 tx_ram_buf.copy_from_slice(tx); 371 tx_ram_buf.copy_from_slice(tx);
317 self.async_inner_from_ram(rx, tx_ram_buf).await 372 self.async_inner_from_ram(rx, tx_ram_buf).await
318 } 373 }
319 Err(error) => Err(error),
320 } 374 }
321 } 375 }
322 376
@@ -515,8 +569,6 @@ mod eh02 {
515impl embedded_hal_1::spi::Error for Error { 569impl embedded_hal_1::spi::Error for Error {
516 fn kind(&self) -> embedded_hal_1::spi::ErrorKind { 570 fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
517 match *self { 571 match *self {
518 Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
519 Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
520 Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other, 572 Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other,
521 } 573 }
522 } 574 }
@@ -580,22 +632,22 @@ impl<'d, T: Instance> SetConfig for Spim<'d, T> {
580 r.config.write(|w| { 632 r.config.write(|w| {
581 match mode { 633 match mode {
582 MODE_0 => { 634 MODE_0 => {
583 w.order().msb_first(); 635 w.order().variant(config.bit_order);
584 w.cpol().active_high(); 636 w.cpol().active_high();
585 w.cpha().leading(); 637 w.cpha().leading();
586 } 638 }
587 MODE_1 => { 639 MODE_1 => {
588 w.order().msb_first(); 640 w.order().variant(config.bit_order);
589 w.cpol().active_high(); 641 w.cpol().active_high();
590 w.cpha().trailing(); 642 w.cpha().trailing();
591 } 643 }
592 MODE_2 => { 644 MODE_2 => {
593 w.order().msb_first(); 645 w.order().variant(config.bit_order);
594 w.cpol().active_low(); 646 w.cpol().active_low();
595 w.cpha().leading(); 647 w.cpha().leading();
596 } 648 }
597 MODE_3 => { 649 MODE_3 => {
598 w.order().msb_first(); 650 w.order().variant(config.bit_order);
599 w.cpol().active_low(); 651 w.cpol().active_low();
600 w.cpha().trailing(); 652 w.cpha().trailing();
601 } 653 }
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 3aad25298..772ca40cc 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -9,8 +9,9 @@ use core::task::Poll;
9use embassy_embedded_hal::SetConfig; 9use embassy_embedded_hal::SetConfig;
10use embassy_hal_internal::{into_ref, PeripheralRef}; 10use embassy_hal_internal::{into_ref, PeripheralRef};
11pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 11pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
12pub use pac::spis0::config::ORDER_A as BitOrder;
12 13
13use crate::chip::FORCE_COPY_BUFFER_SIZE; 14use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
14use crate::gpio::sealed::Pin as _; 15use crate::gpio::sealed::Pin as _;
15use crate::gpio::{self, AnyPin, Pin as GpioPin}; 16use crate::gpio::{self, AnyPin, Pin as GpioPin};
16use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
@@ -36,6 +37,9 @@ pub struct Config {
36 /// SPI mode 37 /// SPI mode
37 pub mode: Mode, 38 pub mode: Mode,
38 39
40 /// Bit order
41 pub bit_order: BitOrder,
42
39 /// Overread character. 43 /// Overread character.
40 /// 44 ///
41 /// If the master keeps clocking the bus after all the bytes in the TX buffer have 45 /// If the master keeps clocking the bus after all the bytes in the TX buffer have
@@ -56,6 +60,7 @@ impl Default for Config {
56 fn default() -> Self { 60 fn default() -> Self {
57 Self { 61 Self {
58 mode: MODE_0, 62 mode: MODE_0,
63 bit_order: BitOrder::MSB_FIRST,
59 orc: 0x00, 64 orc: 0x00,
60 def: 0x00, 65 def: 0x00,
61 auto_acquire: true, 66 auto_acquire: true,
@@ -222,11 +227,17 @@ impl<'d, T: Instance> Spis<'d, T> {
222 227
223 // Set up the DMA write. 228 // Set up the DMA write.
224 let (ptr, len) = slice_ptr_parts(tx); 229 let (ptr, len) = slice_ptr_parts(tx);
230 if len > EASY_DMA_SIZE {
231 return Err(Error::TxBufferTooLong);
232 }
225 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 233 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
226 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 234 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
227 235
228 // Set up the DMA read. 236 // Set up the DMA read.
229 let (ptr, len) = slice_ptr_parts_mut(rx); 237 let (ptr, len) = slice_ptr_parts_mut(rx);
238 if len > EASY_DMA_SIZE {
239 return Err(Error::RxBufferTooLong);
240 }
230 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 241 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
231 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 242 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
232 243
@@ -503,22 +514,22 @@ impl<'d, T: Instance> SetConfig for Spis<'d, T> {
503 r.config.write(|w| { 514 r.config.write(|w| {
504 match mode { 515 match mode {
505 MODE_0 => { 516 MODE_0 => {
506 w.order().msb_first(); 517 w.order().variant(config.bit_order);
507 w.cpol().active_high(); 518 w.cpol().active_high();
508 w.cpha().leading(); 519 w.cpha().leading();
509 } 520 }
510 MODE_1 => { 521 MODE_1 => {
511 w.order().msb_first(); 522 w.order().variant(config.bit_order);
512 w.cpol().active_high(); 523 w.cpol().active_high();
513 w.cpha().trailing(); 524 w.cpha().trailing();
514 } 525 }
515 MODE_2 => { 526 MODE_2 => {
516 w.order().msb_first(); 527 w.order().variant(config.bit_order);
517 w.cpol().active_low(); 528 w.cpol().active_low();
518 w.cpha().leading(); 529 w.cpha().leading();
519 } 530 }
520 MODE_3 => { 531 MODE_3 => {
521 w.order().msb_first(); 532 w.order().variant(config.bit_order);
522 w.cpol().active_low(); 533 w.cpol().active_low();
523 w.cpha().trailing(); 534 w.cpha().trailing();
524 } 535 }
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index 5e2998b10..ed4a47713 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -83,7 +83,7 @@ impl<'d> Temp<'d> {
83 let value = poll_fn(|cx| { 83 let value = poll_fn(|cx| {
84 WAKER.register(cx.waker()); 84 WAKER.register(cx.waker());
85 if t.events_datardy.read().bits() == 0 { 85 if t.events_datardy.read().bits() == 0 {
86 return Poll::Pending; 86 Poll::Pending
87 } else { 87 } else {
88 t.events_datardy.reset(); 88 t.events_datardy.reset();
89 let raw = t.temp.read().bits(); 89 let raw = t.temp.read().bits();
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 042f7c5f7..3407c9504 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -171,7 +171,8 @@ impl RtcDriver {
171 fn next_period(&self) { 171 fn next_period(&self) {
172 critical_section::with(|cs| { 172 critical_section::with(|cs| {
173 let r = rtc(); 173 let r = rtc();
174 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; 174 let period = self.period.load(Ordering::Relaxed) + 1;
175 self.period.store(period, Ordering::Relaxed);
175 let t = (period as u64) << 23; 176 let t = (period as u64) << 23;
176 177
177 for n in 0..ALARM_COUNT { 178 for n in 0..ALARM_COUNT {
@@ -219,18 +220,15 @@ impl Driver for RtcDriver {
219 } 220 }
220 221
221 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 222 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
222 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 223 critical_section::with(|_| {
223 if x < ALARM_COUNT as u8 { 224 let id = self.alarm_count.load(Ordering::Relaxed);
224 Some(x + 1) 225 if id < ALARM_COUNT as u8 {
226 self.alarm_count.store(id + 1, Ordering::Relaxed);
227 Some(AlarmHandle::new(id))
225 } else { 228 } else {
226 None 229 None
227 } 230 }
228 }); 231 })
229
230 match id {
231 Ok(id) => Some(AlarmHandle::new(id)),
232 Err(_) => None,
233 }
234 } 232 }
235 233
236 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 234 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 3dbfdac42..3c35baee5 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -111,7 +111,7 @@ impl<'d, T: Instance> Timer<'d, T> {
111 Self::new_inner(timer, true) 111 Self::new_inner(timer, true)
112 } 112 }
113 113
114 fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self { 114 fn new_inner(timer: impl Peripheral<P = T> + 'd, _is_counter: bool) -> Self {
115 into_ref!(timer); 115 into_ref!(timer);
116 116
117 let regs = T::regs(); 117 let regs = T::regs();
@@ -122,12 +122,16 @@ impl<'d, T: Instance> Timer<'d, T> {
122 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. 122 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
123 this.stop(); 123 this.stop();
124 124
125 if is_counter { 125 #[cfg(not(feature = "nrf51"))]
126 if _is_counter {
126 regs.mode.write(|w| w.mode().low_power_counter()); 127 regs.mode.write(|w| w.mode().low_power_counter());
127 } else { 128 } else {
128 regs.mode.write(|w| w.mode().timer()); 129 regs.mode.write(|w| w.mode().timer());
129 } 130 }
130 131
132 #[cfg(feature = "nrf51")]
133 regs.mode.write(|w| w.mode().timer());
134
131 // Make the counter's max value as high as possible. 135 // Make the counter's max value as high as possible.
132 // TODO: is there a reason someone would want to set this lower? 136 // TODO: is there a reason someone would want to set this lower?
133 regs.bitmode.write(|w| w.bitmode()._32bit()); 137 regs.bitmode.write(|w| w.bitmode()._32bit());
@@ -238,7 +242,11 @@ pub struct Cc<'d, T: Instance> {
238impl<'d, T: Instance> Cc<'d, T> { 242impl<'d, T: Instance> Cc<'d, T> {
239 /// Get the current value stored in the register. 243 /// Get the current value stored in the register.
240 pub fn read(&self) -> u32 { 244 pub fn read(&self) -> u32 {
241 T::regs().cc[self.n].read().cc().bits() 245 #[cfg(not(feature = "nrf51"))]
246 return T::regs().cc[self.n].read().cc().bits();
247
248 #[cfg(feature = "nrf51")]
249 return T::regs().cc[self.n].read().bits();
242 } 250 }
243 251
244 /// Set the value stored in the register. 252 /// Set the value stored in the register.
@@ -246,7 +254,11 @@ impl<'d, T: Instance> Cc<'d, T> {
246 /// `event_compare` will fire when the timer's counter reaches this value. 254 /// `event_compare` will fire when the timer's counter reaches this value.
247 pub fn write(&self, value: u32) { 255 pub fn write(&self, value: u32) {
248 // SAFETY: there are no invalid values for the CC register. 256 // SAFETY: there are no invalid values for the CC register.
249 T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }) 257 #[cfg(not(feature = "nrf51"))]
258 T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) });
259
260 #[cfg(feature = "nrf51")]
261 T::regs().cc[self.n].write(|w| unsafe { w.bits(value) });
250 } 262 }
251 263
252 /// Capture the current value of the timer's counter in this register, and return it. 264 /// Capture the current value of the timer's counter in this register, and return it.
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index da8e15d02..24810a08c 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -372,7 +372,7 @@ impl<'d, T: Instance> Twim<'d, T> {
372 // Start write operation. 372 // Start write operation.
373 r.shorts.write(|w| w.lasttx_stop().enabled()); 373 r.shorts.write(|w| w.lasttx_stop().enabled());
374 r.tasks_starttx.write(|w| unsafe { w.bits(1) }); 374 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
375 if buffer.len() == 0 { 375 if buffer.is_empty() {
376 // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. 376 // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves.
377 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 377 r.tasks_stop.write(|w| unsafe { w.bits(1) });
378 } 378 }
@@ -403,7 +403,7 @@ impl<'d, T: Instance> Twim<'d, T> {
403 // Start read operation. 403 // Start read operation.
404 r.shorts.write(|w| w.lastrx_stop().enabled()); 404 r.shorts.write(|w| w.lastrx_stop().enabled());
405 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 405 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
406 if buffer.len() == 0 { 406 if buffer.is_empty() {
407 // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. 407 // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves.
408 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 408 r.tasks_stop.write(|w| unsafe { w.bits(1) });
409 } 409 }
@@ -447,7 +447,7 @@ impl<'d, T: Instance> Twim<'d, T> {
447 w 447 w
448 }); 448 });
449 r.tasks_starttx.write(|w| unsafe { w.bits(1) }); 449 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
450 if wr_buffer.len() == 0 && rd_buffer.len() == 0 { 450 if wr_buffer.is_empty() && rd_buffer.is_empty() {
451 // With a zero-length buffer, LASTRX/LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. 451 // With a zero-length buffer, LASTRX/LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves.
452 // TODO handle when only one of the buffers is zero length 452 // TODO handle when only one of the buffers is zero length
453 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 453 r.tasks_stop.write(|w| unsafe { w.bits(1) });
@@ -469,7 +469,7 @@ impl<'d, T: Instance> Twim<'d, T> {
469 trace!("Copying TWIM tx buffer into RAM for DMA"); 469 trace!("Copying TWIM tx buffer into RAM for DMA");
470 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; 470 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
471 tx_ram_buf.copy_from_slice(wr_buffer); 471 tx_ram_buf.copy_from_slice(wr_buffer);
472 self.setup_write_read_from_ram(address, &tx_ram_buf, rd_buffer, inten) 472 self.setup_write_read_from_ram(address, tx_ram_buf, rd_buffer, inten)
473 } 473 }
474 Err(error) => Err(error), 474 Err(error) => Err(error),
475 } 475 }
@@ -482,7 +482,7 @@ impl<'d, T: Instance> Twim<'d, T> {
482 trace!("Copying TWIM tx buffer into RAM for DMA"); 482 trace!("Copying TWIM tx buffer into RAM for DMA");
483 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; 483 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
484 tx_ram_buf.copy_from_slice(wr_buffer); 484 tx_ram_buf.copy_from_slice(wr_buffer);
485 self.setup_write_from_ram(address, &tx_ram_buf, inten) 485 self.setup_write_from_ram(address, tx_ram_buf, inten)
486 } 486 }
487 Err(error) => Err(error), 487 Err(error) => Err(error),
488 } 488 }
@@ -779,7 +779,7 @@ mod eh02 {
779 impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Write for Twim<'a, T> { 779 impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Write for Twim<'a, T> {
780 type Error = Error; 780 type Error = Error;
781 781
782 fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { 782 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
783 if slice_in_ram(bytes) { 783 if slice_in_ram(bytes) {
784 self.blocking_write(addr, bytes) 784 self.blocking_write(addr, bytes)
785 } else { 785 } else {
@@ -796,7 +796,7 @@ mod eh02 {
796 impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Read for Twim<'a, T> { 796 impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Read for Twim<'a, T> {
797 type Error = Error; 797 type Error = Error;
798 798
799 fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { 799 fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> {
800 self.blocking_read(addr, bytes) 800 self.blocking_read(addr, bytes)
801 } 801 }
802 } 802 }
@@ -847,10 +847,10 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> {
847 self.blocking_write_read(address, wr_buffer, rd_buffer) 847 self.blocking_write_read(address, wr_buffer, rd_buffer)
848 } 848 }
849 849
850 fn transaction<'a>( 850 fn transaction(
851 &mut self, 851 &mut self,
852 _address: u8, 852 _address: u8,
853 _operations: &mut [embedded_hal_1::i2c::Operation<'a>], 853 _operations: &mut [embedded_hal_1::i2c::Operation<'_>],
854 ) -> Result<(), Self::Error> { 854 ) -> Result<(), Self::Error> {
855 todo!(); 855 todo!();
856 } 856 }
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
index c6c020557..415150447 100644
--- a/embassy-nrf/src/twis.rs
+++ b/embassy-nrf/src/twis.rs
@@ -577,7 +577,7 @@ impl<'d, T: Instance> Twis<'d, T> {
577 trace!("Copying TWIS tx buffer into RAM for DMA"); 577 trace!("Copying TWIS tx buffer into RAM for DMA");
578 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; 578 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
579 tx_ram_buf.copy_from_slice(wr_buffer); 579 tx_ram_buf.copy_from_slice(wr_buffer);
580 self.setup_respond_from_ram(&tx_ram_buf, inten) 580 self.setup_respond_from_ram(tx_ram_buf, inten)
581 } 581 }
582 Err(error) => Err(error), 582 Err(error) => Err(error),
583 } 583 }
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 95434e7a7..cbd5dccbc 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -52,6 +52,37 @@ impl Default for Config {
52 } 52 }
53} 53}
54 54
55bitflags::bitflags! {
56 /// Error source flags
57 pub struct ErrorSource: u32 {
58 /// Buffer overrun
59 const OVERRUN = 0x01;
60 /// Parity error
61 const PARITY = 0x02;
62 /// Framing error
63 const FRAMING = 0x04;
64 /// Break condition
65 const BREAK = 0x08;
66 }
67}
68
69impl ErrorSource {
70 #[inline]
71 fn check(self) -> Result<(), Error> {
72 if self.contains(ErrorSource::OVERRUN) {
73 Err(Error::Overrun)
74 } else if self.contains(ErrorSource::PARITY) {
75 Err(Error::Parity)
76 } else if self.contains(ErrorSource::FRAMING) {
77 Err(Error::Framing)
78 } else if self.contains(ErrorSource::BREAK) {
79 Err(Error::Break)
80 } else {
81 Ok(())
82 }
83 }
84}
85
55/// UART error. 86/// UART error.
56#[derive(Debug, Clone, Copy, PartialEq, Eq)] 87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))] 88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -61,6 +92,14 @@ pub enum Error {
61 BufferTooLong, 92 BufferTooLong,
62 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. 93 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
63 BufferNotInRAM, 94 BufferNotInRAM,
95 /// Framing Error
96 Framing,
97 /// Parity Error
98 Parity,
99 /// Buffer Overrun
100 Overrun,
101 /// Break condition
102 Break,
64} 103}
65 104
66/// Interrupt handler. 105/// Interrupt handler.
@@ -73,12 +112,19 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
73 let r = T::regs(); 112 let r = T::regs();
74 let s = T::state(); 113 let s = T::state();
75 114
76 if r.events_endrx.read().bits() != 0 { 115 let endrx = r.events_endrx.read().bits();
77 s.endrx_waker.wake(); 116 let error = r.events_error.read().bits();
78 r.intenclr.write(|w| w.endrx().clear()); 117 if endrx != 0 || error != 0 {
118 s.rx_waker.wake();
119 if endrx != 0 {
120 r.intenclr.write(|w| w.endrx().clear());
121 }
122 if error != 0 {
123 r.intenclr.write(|w| w.error().clear());
124 }
79 } 125 }
80 if r.events_endtx.read().bits() != 0 { 126 if r.events_endtx.read().bits() != 0 {
81 s.endtx_waker.wake(); 127 s.tx_waker.wake();
82 r.intenclr.write(|w| w.endtx().clear()); 128 r.intenclr.write(|w| w.endtx().clear());
83 } 129 }
84 } 130 }
@@ -113,7 +159,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
113 txd: impl Peripheral<P = impl GpioPin> + 'd, 159 txd: impl Peripheral<P = impl GpioPin> + 'd,
114 config: Config, 160 config: Config,
115 ) -> Self { 161 ) -> Self {
116 into_ref!(rxd, txd); 162 into_ref!(uarte, rxd, txd);
117 Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config) 163 Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config)
118 } 164 }
119 165
@@ -127,7 +173,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
127 rts: impl Peripheral<P = impl GpioPin> + 'd, 173 rts: impl Peripheral<P = impl GpioPin> + 'd,
128 config: Config, 174 config: Config,
129 ) -> Self { 175 ) -> Self {
130 into_ref!(rxd, txd, cts, rts); 176 into_ref!(uarte, rxd, txd, cts, rts);
131 Self::new_inner( 177 Self::new_inner(
132 uarte, 178 uarte,
133 rxd.map_into(), 179 rxd.map_into(),
@@ -139,17 +185,22 @@ impl<'d, T: Instance> Uarte<'d, T> {
139 } 185 }
140 186
141 fn new_inner( 187 fn new_inner(
142 uarte: impl Peripheral<P = T> + 'd, 188 uarte: PeripheralRef<'d, T>,
143 rxd: PeripheralRef<'d, AnyPin>, 189 rxd: PeripheralRef<'d, AnyPin>,
144 txd: PeripheralRef<'d, AnyPin>, 190 txd: PeripheralRef<'d, AnyPin>,
145 cts: Option<PeripheralRef<'d, AnyPin>>, 191 cts: Option<PeripheralRef<'d, AnyPin>>,
146 rts: Option<PeripheralRef<'d, AnyPin>>, 192 rts: Option<PeripheralRef<'d, AnyPin>>,
147 config: Config, 193 config: Config,
148 ) -> Self { 194 ) -> Self {
149 into_ref!(uarte);
150
151 let r = T::regs(); 195 let r = T::regs();
152 196
197 let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
198 (false, false) => false,
199 (true, true) => true,
200 _ => panic!("RTS and CTS pins must be either both set or none set."),
201 };
202 configure(r, config, hardware_flow_control);
203
153 rxd.conf().write(|w| w.input().connect().drive().h0h1()); 204 rxd.conf().write(|w| w.input().connect().drive().h0h1());
154 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); 205 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
155 206
@@ -171,13 +222,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
171 T::Interrupt::unpend(); 222 T::Interrupt::unpend();
172 unsafe { T::Interrupt::enable() }; 223 unsafe { T::Interrupt::enable() };
173 224
174 let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
175 (false, false) => false,
176 (true, true) => true,
177 _ => panic!("RTS and CTS pins must be either both set or none set."),
178 };
179 configure(r, config, hardware_flow_control);
180
181 let s = T::state(); 225 let s = T::state();
182 s.tx_rx_refcount.store(2, Ordering::Relaxed); 226 s.tx_rx_refcount.store(2, Ordering::Relaxed);
183 227
@@ -196,6 +240,14 @@ impl<'d, T: Instance> Uarte<'d, T> {
196 (self.tx, self.rx) 240 (self.tx, self.rx)
197 } 241 }
198 242
243 /// Split the UART in reader and writer parts, by reference.
244 ///
245 /// The returned halves borrow from `self`, so you can drop them and go back to using
246 /// the "un-split" `self`. This allows temporarily splitting the UART.
247 pub fn split_by_ref(&mut self) -> (&mut UarteTx<'d, T>, &mut UarteRx<'d, T>) {
248 (&mut self.tx, &mut self.rx)
249 }
250
199 /// Split the Uarte into the transmitter and receiver with idle support parts. 251 /// Split the Uarte into the transmitter and receiver with idle support parts.
200 /// 252 ///
201 /// This is useful to concurrently transmit and receive from independent tasks. 253 /// This is useful to concurrently transmit and receive from independent tasks.
@@ -245,7 +297,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
245 } 297 }
246} 298}
247 299
248fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) { 300pub(crate) fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) {
249 r.config.write(|w| { 301 r.config.write(|w| {
250 w.hwfc().bit(hardware_flow_control); 302 w.hwfc().bit(hardware_flow_control);
251 w.parity().variant(config.parity); 303 w.parity().variant(config.parity);
@@ -261,8 +313,14 @@ fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) {
261 r.events_rxstarted.reset(); 313 r.events_rxstarted.reset();
262 r.events_txstarted.reset(); 314 r.events_txstarted.reset();
263 315
316 // reset all pins
317 r.psel.txd.write(|w| w.connect().disconnected());
318 r.psel.rxd.write(|w| w.connect().disconnected());
319 r.psel.cts.write(|w| w.connect().disconnected());
320 r.psel.rts.write(|w| w.connect().disconnected());
321
264 // Enable 322 // Enable
265 apply_workaround_for_enable_anomaly(&r); 323 apply_workaround_for_enable_anomaly(r);
266 r.enable.write(|w| w.enable().enabled()); 324 r.enable.write(|w| w.enable().enabled());
267} 325}
268 326
@@ -274,7 +332,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
274 txd: impl Peripheral<P = impl GpioPin> + 'd, 332 txd: impl Peripheral<P = impl GpioPin> + 'd,
275 config: Config, 333 config: Config,
276 ) -> Self { 334 ) -> Self {
277 into_ref!(txd); 335 into_ref!(uarte, txd);
278 Self::new_inner(uarte, txd.map_into(), None, config) 336 Self::new_inner(uarte, txd.map_into(), None, config)
279 } 337 }
280 338
@@ -286,20 +344,20 @@ impl<'d, T: Instance> UarteTx<'d, T> {
286 cts: impl Peripheral<P = impl GpioPin> + 'd, 344 cts: impl Peripheral<P = impl GpioPin> + 'd,
287 config: Config, 345 config: Config,
288 ) -> Self { 346 ) -> Self {
289 into_ref!(txd, cts); 347 into_ref!(uarte, txd, cts);
290 Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config) 348 Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config)
291 } 349 }
292 350
293 fn new_inner( 351 fn new_inner(
294 uarte: impl Peripheral<P = T> + 'd, 352 uarte: PeripheralRef<'d, T>,
295 txd: PeripheralRef<'d, AnyPin>, 353 txd: PeripheralRef<'d, AnyPin>,
296 cts: Option<PeripheralRef<'d, AnyPin>>, 354 cts: Option<PeripheralRef<'d, AnyPin>>,
297 config: Config, 355 config: Config,
298 ) -> Self { 356 ) -> Self {
299 into_ref!(uarte);
300
301 let r = T::regs(); 357 let r = T::regs();
302 358
359 configure(r, config, cts.is_some());
360
303 txd.set_high(); 361 txd.set_high();
304 txd.conf().write(|w| w.dir().output().drive().s0s1()); 362 txd.conf().write(|w| w.dir().output().drive().s0s1());
305 r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); 363 r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
@@ -309,12 +367,6 @@ impl<'d, T: Instance> UarteTx<'d, T> {
309 } 367 }
310 r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); 368 r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
311 369
312 r.psel.rxd.write(|w| w.connect().disconnected());
313 r.psel.rts.write(|w| w.connect().disconnected());
314
315 let hardware_flow_control = cts.is_some();
316 configure(r, config, hardware_flow_control);
317
318 T::Interrupt::unpend(); 370 T::Interrupt::unpend();
319 unsafe { T::Interrupt::enable() }; 371 unsafe { T::Interrupt::enable() };
320 372
@@ -332,7 +384,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
332 trace!("Copying UARTE tx buffer into RAM for DMA"); 384 trace!("Copying UARTE tx buffer into RAM for DMA");
333 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; 385 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()];
334 ram_buf.copy_from_slice(buffer); 386 ram_buf.copy_from_slice(buffer);
335 self.write_from_ram(&ram_buf).await 387 self.write_from_ram(ram_buf).await
336 } 388 }
337 Err(error) => Err(error), 389 Err(error) => Err(error),
338 } 390 }
@@ -340,7 +392,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
340 392
341 /// Same as [`write`](Self::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. 393 /// Same as [`write`](Self::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
342 pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { 394 pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
343 if buffer.len() == 0 { 395 if buffer.is_empty() {
344 return Ok(()); 396 return Ok(());
345 } 397 }
346 398
@@ -379,7 +431,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
379 r.tasks_starttx.write(|w| unsafe { w.bits(1) }); 431 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
380 432
381 poll_fn(|cx| { 433 poll_fn(|cx| {
382 s.endtx_waker.register(cx.waker()); 434 s.tx_waker.register(cx.waker());
383 if r.events_endtx.read().bits() != 0 { 435 if r.events_endtx.read().bits() != 0 {
384 return Poll::Ready(()); 436 return Poll::Ready(());
385 } 437 }
@@ -402,7 +454,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
402 trace!("Copying UARTE tx buffer into RAM for DMA"); 454 trace!("Copying UARTE tx buffer into RAM for DMA");
403 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; 455 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()];
404 ram_buf.copy_from_slice(buffer); 456 ram_buf.copy_from_slice(buffer);
405 self.blocking_write_from_ram(&ram_buf) 457 self.blocking_write_from_ram(ram_buf)
406 } 458 }
407 Err(error) => Err(error), 459 Err(error) => Err(error),
408 } 460 }
@@ -410,7 +462,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
410 462
411 /// Same as [`write_from_ram`](Self::write_from_ram) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. 463 /// Same as [`write_from_ram`](Self::write_from_ram) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
412 pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { 464 pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
413 if buffer.len() == 0 { 465 if buffer.is_empty() {
414 return Ok(()); 466 return Ok(());
415 } 467 }
416 468
@@ -458,7 +510,7 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> {
458 510
459 let s = T::state(); 511 let s = T::state();
460 512
461 drop_tx_rx(&r, &s); 513 drop_tx_rx(r, s);
462 } 514 }
463} 515}
464 516
@@ -470,7 +522,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
470 rxd: impl Peripheral<P = impl GpioPin> + 'd, 522 rxd: impl Peripheral<P = impl GpioPin> + 'd,
471 config: Config, 523 config: Config,
472 ) -> Self { 524 ) -> Self {
473 into_ref!(rxd); 525 into_ref!(uarte, rxd);
474 Self::new_inner(uarte, rxd.map_into(), None, config) 526 Self::new_inner(uarte, rxd.map_into(), None, config)
475 } 527 }
476 528
@@ -482,20 +534,28 @@ impl<'d, T: Instance> UarteRx<'d, T> {
482 rts: impl Peripheral<P = impl GpioPin> + 'd, 534 rts: impl Peripheral<P = impl GpioPin> + 'd,
483 config: Config, 535 config: Config,
484 ) -> Self { 536 ) -> Self {
485 into_ref!(rxd, rts); 537 into_ref!(uarte, rxd, rts);
486 Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) 538 Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config)
487 } 539 }
488 540
541 /// Check for errors and clear the error register if an error occured.
542 fn check_and_clear_errors(&mut self) -> Result<(), Error> {
543 let r = T::regs();
544 let err_bits = r.errorsrc.read().bits();
545 r.errorsrc.write(|w| unsafe { w.bits(err_bits) });
546 ErrorSource::from_bits_truncate(err_bits).check()
547 }
548
489 fn new_inner( 549 fn new_inner(
490 uarte: impl Peripheral<P = T> + 'd, 550 uarte: PeripheralRef<'d, T>,
491 rxd: PeripheralRef<'d, AnyPin>, 551 rxd: PeripheralRef<'d, AnyPin>,
492 rts: Option<PeripheralRef<'d, AnyPin>>, 552 rts: Option<PeripheralRef<'d, AnyPin>>,
493 config: Config, 553 config: Config,
494 ) -> Self { 554 ) -> Self {
495 into_ref!(uarte);
496
497 let r = T::regs(); 555 let r = T::regs();
498 556
557 configure(r, config, rts.is_some());
558
499 rxd.conf().write(|w| w.input().connect().drive().h0h1()); 559 rxd.conf().write(|w| w.input().connect().drive().h0h1());
500 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); 560 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
501 561
@@ -505,15 +565,9 @@ impl<'d, T: Instance> UarteRx<'d, T> {
505 } 565 }
506 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); 566 r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
507 567
508 r.psel.txd.write(|w| w.connect().disconnected());
509 r.psel.cts.write(|w| w.connect().disconnected());
510
511 T::Interrupt::unpend(); 568 T::Interrupt::unpend();
512 unsafe { T::Interrupt::enable() }; 569 unsafe { T::Interrupt::enable() };
513 570
514 let hardware_flow_control = rts.is_some();
515 configure(r, config, hardware_flow_control);
516
517 let s = T::state(); 571 let s = T::state();
518 s.tx_rx_refcount.store(1, Ordering::Relaxed); 572 s.tx_rx_refcount.store(1, Ordering::Relaxed);
519 573
@@ -565,14 +619,14 @@ impl<'d, T: Instance> UarteRx<'d, T> {
565 UarteRxWithIdle { 619 UarteRxWithIdle {
566 rx: self, 620 rx: self,
567 timer, 621 timer,
568 ppi_ch1: ppi_ch1, 622 ppi_ch1,
569 _ppi_ch2: ppi_ch2, 623 _ppi_ch2: ppi_ch2,
570 } 624 }
571 } 625 }
572 626
573 /// Read bytes until the buffer is filled. 627 /// Read bytes until the buffer is filled.
574 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 628 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
575 if buffer.len() == 0 { 629 if buffer.is_empty() {
576 return Ok(()); 630 return Ok(());
577 } 631 }
578 if buffer.len() > EASY_DMA_SIZE { 632 if buffer.len() > EASY_DMA_SIZE {
@@ -588,8 +642,13 @@ impl<'d, T: Instance> UarteRx<'d, T> {
588 let drop = OnDrop::new(move || { 642 let drop = OnDrop::new(move || {
589 trace!("read drop: stopping"); 643 trace!("read drop: stopping");
590 644
591 r.intenclr.write(|w| w.endrx().clear()); 645 r.intenclr.write(|w| {
646 w.endrx().clear();
647 w.error().clear()
648 });
592 r.events_rxto.reset(); 649 r.events_rxto.reset();
650 r.events_error.reset();
651 r.errorsrc.reset();
593 r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); 652 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
594 653
595 while r.events_endrx.read().bits() == 0 {} 654 while r.events_endrx.read().bits() == 0 {}
@@ -601,17 +660,26 @@ impl<'d, T: Instance> UarteRx<'d, T> {
601 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 660 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
602 661
603 r.events_endrx.reset(); 662 r.events_endrx.reset();
604 r.intenset.write(|w| w.endrx().set()); 663 r.events_error.reset();
664 r.intenset.write(|w| {
665 w.endrx().set();
666 w.error().set()
667 });
605 668
606 compiler_fence(Ordering::SeqCst); 669 compiler_fence(Ordering::SeqCst);
607 670
608 trace!("startrx"); 671 trace!("startrx");
609 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 672 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
610 673
611 poll_fn(|cx| { 674 let result = poll_fn(|cx| {
612 s.endrx_waker.register(cx.waker()); 675 s.rx_waker.register(cx.waker());
676
677 if let Err(e) = self.check_and_clear_errors() {
678 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
679 return Poll::Ready(Err(e));
680 }
613 if r.events_endrx.read().bits() != 0 { 681 if r.events_endrx.read().bits() != 0 {
614 return Poll::Ready(()); 682 return Poll::Ready(Ok(()));
615 } 683 }
616 Poll::Pending 684 Poll::Pending
617 }) 685 })
@@ -621,12 +689,12 @@ impl<'d, T: Instance> UarteRx<'d, T> {
621 r.events_rxstarted.reset(); 689 r.events_rxstarted.reset();
622 drop.defuse(); 690 drop.defuse();
623 691
624 Ok(()) 692 result
625 } 693 }
626 694
627 /// Read bytes until the buffer is filled. 695 /// Read bytes until the buffer is filled.
628 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 696 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
629 if buffer.len() == 0 { 697 if buffer.is_empty() {
630 return Ok(()); 698 return Ok(());
631 } 699 }
632 if buffer.len() > EASY_DMA_SIZE { 700 if buffer.len() > EASY_DMA_SIZE {
@@ -642,19 +710,23 @@ impl<'d, T: Instance> UarteRx<'d, T> {
642 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 710 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
643 711
644 r.events_endrx.reset(); 712 r.events_endrx.reset();
645 r.intenclr.write(|w| w.endrx().clear()); 713 r.events_error.reset();
714 r.intenclr.write(|w| {
715 w.endrx().clear();
716 w.error().clear()
717 });
646 718
647 compiler_fence(Ordering::SeqCst); 719 compiler_fence(Ordering::SeqCst);
648 720
649 trace!("startrx"); 721 trace!("startrx");
650 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 722 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
651 723
652 while r.events_endrx.read().bits() == 0 {} 724 while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {}
653 725
654 compiler_fence(Ordering::SeqCst); 726 compiler_fence(Ordering::SeqCst);
655 r.events_rxstarted.reset(); 727 r.events_rxstarted.reset();
656 728
657 Ok(()) 729 self.check_and_clear_errors()
658 } 730 }
659} 731}
660 732
@@ -672,7 +744,7 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> {
672 744
673 let s = T::state(); 745 let s = T::state();
674 746
675 drop_tx_rx(&r, &s); 747 drop_tx_rx(r, s);
676 } 748 }
677} 749}
678 750
@@ -703,7 +775,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
703 /// 775 ///
704 /// Returns the amount of bytes read. 776 /// Returns the amount of bytes read.
705 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 777 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
706 if buffer.len() == 0 { 778 if buffer.is_empty() {
707 return Ok(0); 779 return Ok(0);
708 } 780 }
709 if buffer.len() > EASY_DMA_SIZE { 781 if buffer.len() > EASY_DMA_SIZE {
@@ -721,8 +793,12 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
721 let drop = OnDrop::new(|| { 793 let drop = OnDrop::new(|| {
722 self.timer.stop(); 794 self.timer.stop();
723 795
724 r.intenclr.write(|w| w.endrx().clear()); 796 r.intenclr.write(|w| {
797 w.endrx().clear();
798 w.error().clear()
799 });
725 r.events_rxto.reset(); 800 r.events_rxto.reset();
801 r.events_error.reset();
726 r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); 802 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
727 803
728 while r.events_endrx.read().bits() == 0 {} 804 while r.events_endrx.read().bits() == 0 {}
@@ -732,17 +808,27 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
732 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 808 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
733 809
734 r.events_endrx.reset(); 810 r.events_endrx.reset();
735 r.intenset.write(|w| w.endrx().set()); 811 r.events_error.reset();
812 r.intenset.write(|w| {
813 w.endrx().set();
814 w.error().set()
815 });
736 816
737 compiler_fence(Ordering::SeqCst); 817 compiler_fence(Ordering::SeqCst);
738 818
739 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 819 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
740 820
741 poll_fn(|cx| { 821 let result = poll_fn(|cx| {
742 s.endrx_waker.register(cx.waker()); 822 s.rx_waker.register(cx.waker());
823
824 if let Err(e) = self.rx.check_and_clear_errors() {
825 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
826 return Poll::Ready(Err(e));
827 }
743 if r.events_endrx.read().bits() != 0 { 828 if r.events_endrx.read().bits() != 0 {
744 return Poll::Ready(()); 829 return Poll::Ready(Ok(()));
745 } 830 }
831
746 Poll::Pending 832 Poll::Pending
747 }) 833 })
748 .await; 834 .await;
@@ -755,14 +841,14 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
755 841
756 drop.defuse(); 842 drop.defuse();
757 843
758 Ok(n) 844 result.map(|_| n)
759 } 845 }
760 846
761 /// Read bytes until the buffer is filled, or the line becomes idle. 847 /// Read bytes until the buffer is filled, or the line becomes idle.
762 /// 848 ///
763 /// Returns the amount of bytes read. 849 /// Returns the amount of bytes read.
764 pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 850 pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
765 if buffer.len() == 0 { 851 if buffer.is_empty() {
766 return Ok(0); 852 return Ok(0);
767 } 853 }
768 if buffer.len() > EASY_DMA_SIZE { 854 if buffer.len() > EASY_DMA_SIZE {
@@ -780,13 +866,17 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
780 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 866 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
781 867
782 r.events_endrx.reset(); 868 r.events_endrx.reset();
783 r.intenclr.write(|w| w.endrx().clear()); 869 r.events_error.reset();
870 r.intenclr.write(|w| {
871 w.endrx().clear();
872 w.error().clear()
873 });
784 874
785 compiler_fence(Ordering::SeqCst); 875 compiler_fence(Ordering::SeqCst);
786 876
787 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 877 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
788 878
789 while r.events_endrx.read().bits() == 0 {} 879 while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {}
790 880
791 compiler_fence(Ordering::SeqCst); 881 compiler_fence(Ordering::SeqCst);
792 let n = r.rxd.amount.read().amount().bits() as usize; 882 let n = r.rxd.amount.read().amount().bits() as usize;
@@ -794,7 +884,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
794 self.timer.stop(); 884 self.timer.stop();
795 r.events_rxstarted.reset(); 885 r.events_rxstarted.reset();
796 886
797 Ok(n) 887 self.rx.check_and_clear_errors().map(|_| n)
798 } 888 }
799} 889}
800 890
@@ -872,15 +962,15 @@ pub(crate) mod sealed {
872 use super::*; 962 use super::*;
873 963
874 pub struct State { 964 pub struct State {
875 pub endrx_waker: AtomicWaker, 965 pub rx_waker: AtomicWaker,
876 pub endtx_waker: AtomicWaker, 966 pub tx_waker: AtomicWaker,
877 pub tx_rx_refcount: AtomicU8, 967 pub tx_rx_refcount: AtomicU8,
878 } 968 }
879 impl State { 969 impl State {
880 pub const fn new() -> Self { 970 pub const fn new() -> Self {
881 Self { 971 Self {
882 endrx_waker: AtomicWaker::new(), 972 rx_waker: AtomicWaker::new(),
883 endtx_waker: AtomicWaker::new(), 973 tx_waker: AtomicWaker::new(),
884 tx_rx_refcount: AtomicU8::new(0), 974 tx_rx_refcount: AtomicU8::new(0),
885 } 975 }
886 } 976 }
diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs
index cd0f59490..13aba7dec 100644
--- a/embassy-nrf/src/util.rs
+++ b/embassy-nrf/src/util.rs
@@ -1,8 +1,22 @@
1#![allow(dead_code)]
1use core::mem; 2use core::mem;
2 3
3const SRAM_LOWER: usize = 0x2000_0000; 4const SRAM_LOWER: usize = 0x2000_0000;
4const SRAM_UPPER: usize = 0x3000_0000; 5const SRAM_UPPER: usize = 0x3000_0000;
5 6
7// #![feature(const_slice_ptr_len)]
8// https://github.com/rust-lang/rust/issues/71146
9pub(crate) fn slice_ptr_len<T>(ptr: *const [T]) -> usize {
10 use core::ptr::NonNull;
11 let ptr = ptr.cast_mut();
12 if let Some(ptr) = NonNull::new(ptr) {
13 ptr.len()
14 } else {
15 // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null.
16 NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len()
17 }
18}
19
6// TODO: replace transmutes with core::ptr::metadata once it's stable 20// TODO: replace transmutes with core::ptr::metadata once it's stable
7pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (*const T, usize) { 21pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (*const T, usize) {
8 unsafe { mem::transmute(slice) } 22 unsafe { mem::transmute(slice) }
@@ -20,7 +34,6 @@ pub(crate) fn slice_in_ram<T>(slice: *const [T]) -> bool {
20} 34}
21 35
22/// Return an error if slice is not in RAM. Skips check if slice is zero-length. 36/// Return an error if slice is not in RAM. Skips check if slice is zero-length.
23#[cfg(not(feature = "nrf51"))]
24pub(crate) fn slice_in_ram_or<T, E>(slice: *const [T], err: E) -> Result<(), E> { 37pub(crate) fn slice_in_ram_or<T, E>(slice: *const [T], err: E) -> Result<(), E> {
25 let (_, len) = slice_ptr_parts(slice); 38 let (_, len) = slice_ptr_parts(slice);
26 if len == 0 || slice_in_ram(slice) { 39 if len == 0 || slice_in_ram(slice) {
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index 7eb57bbe6..62eeb4cf6 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -8,6 +8,7 @@ use core::task::{Context, Poll};
8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use self::sealed::Pin as _;
11use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
12use crate::pac::common::{Reg, RW}; 13use crate::pac::common::{Reg, RW};
13use crate::pac::SIO; 14use crate::pac::SIO;
@@ -105,14 +106,14 @@ pub struct DormantWakeConfig {
105} 106}
106 107
107/// GPIO input driver. 108/// GPIO input driver.
108pub struct Input<'d, T: Pin> { 109pub struct Input<'d> {
109 pin: Flex<'d, T>, 110 pin: Flex<'d>,
110} 111}
111 112
112impl<'d, T: Pin> Input<'d, T> { 113impl<'d> Input<'d> {
113 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. 114 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
114 #[inline] 115 #[inline]
115 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { 116 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self {
116 let mut pin = Flex::new(pin); 117 let mut pin = Flex::new(pin);
117 pin.set_as_input(); 118 pin.set_as_input();
118 pin.set_pull(pull); 119 pin.set_pull(pull);
@@ -175,7 +176,7 @@ impl<'d, T: Pin> Input<'d, T> {
175 176
176 /// Configure dormant wake. 177 /// Configure dormant wake.
177 #[inline] 178 #[inline]
178 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { 179 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> {
179 self.pin.dormant_wake(cfg) 180 self.pin.dormant_wake(cfg)
180 } 181 }
181} 182}
@@ -255,14 +256,12 @@ fn IO_IRQ_QSPI() {
255} 256}
256 257
257#[must_use = "futures do nothing unless you `.await` or poll them"] 258#[must_use = "futures do nothing unless you `.await` or poll them"]
258struct InputFuture<'a, T: Pin> { 259struct InputFuture<'d> {
259 pin: PeripheralRef<'a, T>, 260 pin: PeripheralRef<'d, AnyPin>,
260} 261}
261 262
262impl<'d, T: Pin> InputFuture<'d, T> { 263impl<'d> InputFuture<'d> {
263 /// Create a new future wiating for input trigger. 264 fn new(pin: PeripheralRef<'d, AnyPin>, level: InterruptTrigger) -> Self {
264 pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
265 into_ref!(pin);
266 let pin_group = (pin.pin() % 8) as usize; 265 let pin_group = (pin.pin() % 8) as usize;
267 // first, clear the INTR register bits. without this INTR will still 266 // first, clear the INTR register bits. without this INTR will still
268 // contain reports of previous edges, causing the IRQ to fire early 267 // contain reports of previous edges, causing the IRQ to fire early
@@ -305,7 +304,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
305 } 304 }
306} 305}
307 306
308impl<'d, T: Pin> Future for InputFuture<'d, T> { 307impl<'d> Future for InputFuture<'d> {
309 type Output = (); 308 type Output = ();
310 309
311 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 310 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
@@ -344,14 +343,14 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
344} 343}
345 344
346/// GPIO output driver. 345/// GPIO output driver.
347pub struct Output<'d, T: Pin> { 346pub struct Output<'d> {
348 pin: Flex<'d, T>, 347 pin: Flex<'d>,
349} 348}
350 349
351impl<'d, T: Pin> Output<'d, T> { 350impl<'d> Output<'d> {
352 /// Create GPIO output driver for a [Pin] with the provided [Level]. 351 /// Create GPIO output driver for a [Pin] with the provided [Level].
353 #[inline] 352 #[inline]
354 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { 353 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self {
355 let mut pin = Flex::new(pin); 354 let mut pin = Flex::new(pin);
356 match initial_output { 355 match initial_output {
357 Level::High => pin.set_high(), 356 Level::High => pin.set_high(),
@@ -418,14 +417,14 @@ impl<'d, T: Pin> Output<'d, T> {
418} 417}
419 418
420/// GPIO output open-drain. 419/// GPIO output open-drain.
421pub struct OutputOpenDrain<'d, T: Pin> { 420pub struct OutputOpenDrain<'d> {
422 pin: Flex<'d, T>, 421 pin: Flex<'d>,
423} 422}
424 423
425impl<'d, T: Pin> OutputOpenDrain<'d, T> { 424impl<'d> OutputOpenDrain<'d> {
426 /// Create GPIO output driver for a [Pin] in open drain mode with the provided [Level]. 425 /// Create GPIO output driver for a [Pin] in open drain mode with the provided [Level].
427 #[inline] 426 #[inline]
428 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { 427 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self {
429 let mut pin = Flex::new(pin); 428 let mut pin = Flex::new(pin);
430 pin.set_low(); 429 pin.set_low();
431 match initial_output { 430 match initial_output {
@@ -548,17 +547,17 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
548/// This pin can be either an input or output pin. The output level register bit will remain 547/// This pin can be either an input or output pin. The output level register bit will remain
549/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output 548/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
550/// mode. 549/// mode.
551pub struct Flex<'d, T: Pin> { 550pub struct Flex<'d> {
552 pin: PeripheralRef<'d, T>, 551 pin: PeripheralRef<'d, AnyPin>,
553} 552}
554 553
555impl<'d, T: Pin> Flex<'d, T> { 554impl<'d> Flex<'d> {
556 /// Wrap the pin in a `Flex`. 555 /// Wrap the pin in a `Flex`.
557 /// 556 ///
558 /// The pin remains disconnected. The initial output level is unspecified, but can be changed 557 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
559 /// before the pin is put into output mode. 558 /// before the pin is put into output mode.
560 #[inline] 559 #[inline]
561 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { 560 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self {
562 into_ref!(pin); 561 into_ref!(pin);
563 562
564 pin.pad_ctrl().write(|w| { 563 pin.pad_ctrl().write(|w| {
@@ -569,7 +568,7 @@ impl<'d, T: Pin> Flex<'d, T> {
569 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _); 568 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _);
570 }); 569 });
571 570
572 Self { pin } 571 Self { pin: pin.map_into() }
573 } 572 }
574 573
575 #[inline] 574 #[inline]
@@ -716,36 +715,36 @@ impl<'d, T: Pin> Flex<'d, T> {
716 /// Wait until the pin is high. If it is already high, return immediately. 715 /// Wait until the pin is high. If it is already high, return immediately.
717 #[inline] 716 #[inline]
718 pub async fn wait_for_high(&mut self) { 717 pub async fn wait_for_high(&mut self) {
719 InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await; 718 InputFuture::new(self.pin.reborrow(), InterruptTrigger::LevelHigh).await;
720 } 719 }
721 720
722 /// Wait until the pin is low. If it is already low, return immediately. 721 /// Wait until the pin is low. If it is already low, return immediately.
723 #[inline] 722 #[inline]
724 pub async fn wait_for_low(&mut self) { 723 pub async fn wait_for_low(&mut self) {
725 InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await; 724 InputFuture::new(self.pin.reborrow(), InterruptTrigger::LevelLow).await;
726 } 725 }
727 726
728 /// Wait for the pin to undergo a transition from low to high. 727 /// Wait for the pin to undergo a transition from low to high.
729 #[inline] 728 #[inline]
730 pub async fn wait_for_rising_edge(&mut self) { 729 pub async fn wait_for_rising_edge(&mut self) {
731 InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await; 730 InputFuture::new(self.pin.reborrow(), InterruptTrigger::EdgeHigh).await;
732 } 731 }
733 732
734 /// Wait for the pin to undergo a transition from high to low. 733 /// Wait for the pin to undergo a transition from high to low.
735 #[inline] 734 #[inline]
736 pub async fn wait_for_falling_edge(&mut self) { 735 pub async fn wait_for_falling_edge(&mut self) {
737 InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await; 736 InputFuture::new(self.pin.reborrow(), InterruptTrigger::EdgeLow).await;
738 } 737 }
739 738
740 /// Wait for the pin to undergo any transition, i.e low to high OR high to low. 739 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
741 #[inline] 740 #[inline]
742 pub async fn wait_for_any_edge(&mut self) { 741 pub async fn wait_for_any_edge(&mut self) {
743 InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await; 742 InputFuture::new(self.pin.reborrow(), InterruptTrigger::AnyEdge).await;
744 } 743 }
745 744
746 /// Configure dormant wake. 745 /// Configure dormant wake.
747 #[inline] 746 #[inline]
748 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { 747 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> {
749 let idx = self.pin._pin() as usize; 748 let idx = self.pin._pin() as usize;
750 self.pin.io().intr(idx / 8).write(|w| { 749 self.pin.io().intr(idx / 8).write(|w| {
751 w.set_edge_high(idx % 8, cfg.edge_high); 750 w.set_edge_high(idx % 8, cfg.edge_high);
@@ -764,7 +763,7 @@ impl<'d, T: Pin> Flex<'d, T> {
764 } 763 }
765} 764}
766 765
767impl<'d, T: Pin> Drop for Flex<'d, T> { 766impl<'d> Drop for Flex<'d> {
768 #[inline] 767 #[inline]
769 fn drop(&mut self) { 768 fn drop(&mut self) {
770 let idx = self.pin._pin() as usize; 769 let idx = self.pin._pin() as usize;
@@ -782,12 +781,12 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
782} 781}
783 782
784/// Dormant wake driver. 783/// Dormant wake driver.
785pub struct DormantWake<'w, T: Pin> { 784pub struct DormantWake<'w> {
786 pin: PeripheralRef<'w, T>, 785 pin: PeripheralRef<'w, AnyPin>,
787 cfg: DormantWakeConfig, 786 cfg: DormantWakeConfig,
788} 787}
789 788
790impl<'w, T: Pin> Drop for DormantWake<'w, T> { 789impl<'w> Drop for DormantWake<'w> {
791 fn drop(&mut self) { 790 fn drop(&mut self) {
792 let idx = self.pin._pin() as usize; 791 let idx = self.pin._pin() as usize;
793 self.pin.io().intr(idx / 8).write(|w| { 792 self.pin.io().intr(idx / 8).write(|w| {
@@ -816,7 +815,7 @@ pub(crate) mod sealed {
816 815
817 #[inline] 816 #[inline]
818 fn _bank(&self) -> Bank { 817 fn _bank(&self) -> Bank {
819 match self.pin_bank() & 0x20 { 818 match self.pin_bank() >> 5 {
820 #[cfg(feature = "qspi-as-gpio")] 819 #[cfg(feature = "qspi-as-gpio")]
821 1 => Bank::Qspi, 820 1 => Bank::Qspi,
822 _ => Bank::Bank0, 821 _ => Bank::Bank0,
@@ -890,6 +889,17 @@ pub struct AnyPin {
890 pin_bank: u8, 889 pin_bank: u8,
891} 890}
892 891
892impl AnyPin {
893 /// Unsafely create a new type-erased pin.
894 ///
895 /// # Safety
896 ///
897 /// You must ensure that you’re only using one instance of this type at a time.
898 pub unsafe fn steal(pin_bank: u8) -> Self {
899 Self { pin_bank }
900 }
901}
902
893impl_peripheral!(AnyPin); 903impl_peripheral!(AnyPin);
894 904
895impl Pin for AnyPin {} 905impl Pin for AnyPin {}
@@ -970,7 +980,7 @@ mod eh02 {
970 980
971 use super::*; 981 use super::*;
972 982
973 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { 983 impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> {
974 type Error = Infallible; 984 type Error = Infallible;
975 985
976 fn is_high(&self) -> Result<bool, Self::Error> { 986 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -982,7 +992,7 @@ mod eh02 {
982 } 992 }
983 } 993 }
984 994
985 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { 995 impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> {
986 type Error = Infallible; 996 type Error = Infallible;
987 997
988 fn set_high(&mut self) -> Result<(), Self::Error> { 998 fn set_high(&mut self) -> Result<(), Self::Error> {
@@ -994,7 +1004,7 @@ mod eh02 {
994 } 1004 }
995 } 1005 }
996 1006
997 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { 1007 impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> {
998 fn is_set_high(&self) -> Result<bool, Self::Error> { 1008 fn is_set_high(&self) -> Result<bool, Self::Error> {
999 Ok(self.is_set_high()) 1009 Ok(self.is_set_high())
1000 } 1010 }
@@ -1004,7 +1014,7 @@ mod eh02 {
1004 } 1014 }
1005 } 1015 }
1006 1016
1007 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> { 1017 impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> {
1008 type Error = Infallible; 1018 type Error = Infallible;
1009 #[inline] 1019 #[inline]
1010 fn toggle(&mut self) -> Result<(), Self::Error> { 1020 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -1012,7 +1022,7 @@ mod eh02 {
1012 } 1022 }
1013 } 1023 }
1014 1024
1015 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d, T> { 1025 impl<'d> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d> {
1016 type Error = Infallible; 1026 type Error = Infallible;
1017 1027
1018 fn is_high(&self) -> Result<bool, Self::Error> { 1028 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -1024,7 +1034,7 @@ mod eh02 {
1024 } 1034 }
1025 } 1035 }
1026 1036
1027 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, T> { 1037 impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> {
1028 type Error = Infallible; 1038 type Error = Infallible;
1029 1039
1030 #[inline] 1040 #[inline]
@@ -1038,7 +1048,7 @@ mod eh02 {
1038 } 1048 }
1039 } 1049 }
1040 1050
1041 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { 1051 impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d> {
1042 fn is_set_high(&self) -> Result<bool, Self::Error> { 1052 fn is_set_high(&self) -> Result<bool, Self::Error> {
1043 Ok(self.is_set_high()) 1053 Ok(self.is_set_high())
1044 } 1054 }
@@ -1048,7 +1058,7 @@ mod eh02 {
1048 } 1058 }
1049 } 1059 }
1050 1060
1051 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d, T> { 1061 impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d> {
1052 type Error = Infallible; 1062 type Error = Infallible;
1053 #[inline] 1063 #[inline]
1054 fn toggle(&mut self) -> Result<(), Self::Error> { 1064 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -1056,7 +1066,7 @@ mod eh02 {
1056 } 1066 }
1057 } 1067 }
1058 1068
1059 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { 1069 impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> {
1060 type Error = Infallible; 1070 type Error = Infallible;
1061 1071
1062 fn is_high(&self) -> Result<bool, Self::Error> { 1072 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -1068,7 +1078,7 @@ mod eh02 {
1068 } 1078 }
1069 } 1079 }
1070 1080
1071 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { 1081 impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> {
1072 type Error = Infallible; 1082 type Error = Infallible;
1073 1083
1074 fn set_high(&mut self) -> Result<(), Self::Error> { 1084 fn set_high(&mut self) -> Result<(), Self::Error> {
@@ -1080,7 +1090,7 @@ mod eh02 {
1080 } 1090 }
1081 } 1091 }
1082 1092
1083 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { 1093 impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> {
1084 fn is_set_high(&self) -> Result<bool, Self::Error> { 1094 fn is_set_high(&self) -> Result<bool, Self::Error> {
1085 Ok(self.is_set_high()) 1095 Ok(self.is_set_high())
1086 } 1096 }
@@ -1090,7 +1100,7 @@ mod eh02 {
1090 } 1100 }
1091 } 1101 }
1092 1102
1093 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> { 1103 impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> {
1094 type Error = Infallible; 1104 type Error = Infallible;
1095 #[inline] 1105 #[inline]
1096 fn toggle(&mut self) -> Result<(), Self::Error> { 1106 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -1099,11 +1109,11 @@ mod eh02 {
1099 } 1109 }
1100} 1110}
1101 1111
1102impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { 1112impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> {
1103 type Error = Infallible; 1113 type Error = Infallible;
1104} 1114}
1105 1115
1106impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { 1116impl<'d> embedded_hal_1::digital::InputPin for Input<'d> {
1107 fn is_high(&mut self) -> Result<bool, Self::Error> { 1117 fn is_high(&mut self) -> Result<bool, Self::Error> {
1108 Ok((*self).is_high()) 1118 Ok((*self).is_high())
1109 } 1119 }
@@ -1113,11 +1123,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
1113 } 1123 }
1114} 1124}
1115 1125
1116impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> { 1126impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
1117 type Error = Infallible; 1127 type Error = Infallible;
1118} 1128}
1119 1129
1120impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { 1130impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
1121 fn set_high(&mut self) -> Result<(), Self::Error> { 1131 fn set_high(&mut self) -> Result<(), Self::Error> {
1122 Ok(self.set_high()) 1132 Ok(self.set_high())
1123 } 1133 }
@@ -1127,7 +1137,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
1127 } 1137 }
1128} 1138}
1129 1139
1130impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { 1140impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> {
1131 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 1141 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1132 Ok((*self).is_set_high()) 1142 Ok((*self).is_set_high())
1133 } 1143 }
@@ -1137,11 +1147,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
1137 } 1147 }
1138} 1148}
1139 1149
1140impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { 1150impl<'d> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d> {
1141 type Error = Infallible; 1151 type Error = Infallible;
1142} 1152}
1143 1153
1144impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { 1154impl<'d> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d> {
1145 fn set_high(&mut self) -> Result<(), Self::Error> { 1155 fn set_high(&mut self) -> Result<(), Self::Error> {
1146 Ok(self.set_high()) 1156 Ok(self.set_high())
1147 } 1157 }
@@ -1151,7 +1161,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> {
1151 } 1161 }
1152} 1162}
1153 1163
1154impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { 1164impl<'d> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d> {
1155 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 1165 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1156 Ok((*self).is_set_high()) 1166 Ok((*self).is_set_high())
1157 } 1167 }
@@ -1161,7 +1171,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<
1161 } 1171 }
1162} 1172}
1163 1173
1164impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { 1174impl<'d> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d> {
1165 fn is_high(&mut self) -> Result<bool, Self::Error> { 1175 fn is_high(&mut self) -> Result<bool, Self::Error> {
1166 Ok((*self).is_high()) 1176 Ok((*self).is_high())
1167 } 1177 }
@@ -1171,11 +1181,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> {
1171 } 1181 }
1172} 1182}
1173 1183
1174impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { 1184impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> {
1175 type Error = Infallible; 1185 type Error = Infallible;
1176} 1186}
1177 1187
1178impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { 1188impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
1179 fn is_high(&mut self) -> Result<bool, Self::Error> { 1189 fn is_high(&mut self) -> Result<bool, Self::Error> {
1180 Ok((*self).is_high()) 1190 Ok((*self).is_high())
1181 } 1191 }
@@ -1185,7 +1195,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
1185 } 1195 }
1186} 1196}
1187 1197
1188impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { 1198impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
1189 fn set_high(&mut self) -> Result<(), Self::Error> { 1199 fn set_high(&mut self) -> Result<(), Self::Error> {
1190 Ok(self.set_high()) 1200 Ok(self.set_high())
1191 } 1201 }
@@ -1195,7 +1205,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
1195 } 1205 }
1196} 1206}
1197 1207
1198impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { 1208impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> {
1199 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 1209 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1200 Ok((*self).is_set_high()) 1210 Ok((*self).is_set_high())
1201 } 1211 }
@@ -1205,7 +1215,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
1205 } 1215 }
1206} 1216}
1207 1217
1208impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> { 1218impl<'d> embedded_hal_async::digital::Wait for Flex<'d> {
1209 async fn wait_for_high(&mut self) -> Result<(), Self::Error> { 1219 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
1210 self.wait_for_high().await; 1220 self.wait_for_high().await;
1211 Ok(()) 1221 Ok(())
@@ -1232,7 +1242,7 @@ impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> {
1232 } 1242 }
1233} 1243}
1234 1244
1235impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> { 1245impl<'d> embedded_hal_async::digital::Wait for Input<'d> {
1236 async fn wait_for_high(&mut self) -> Result<(), Self::Error> { 1246 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
1237 self.wait_for_high().await; 1247 self.wait_for_high().await;
1238 Ok(()) 1248 Ok(())
@@ -1259,7 +1269,7 @@ impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> {
1259 } 1269 }
1260} 1270}
1261 1271
1262impl<'d, T: Pin> embedded_hal_async::digital::Wait for OutputOpenDrain<'d, T> { 1272impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> {
1263 async fn wait_for_high(&mut self) -> Result<(), Self::Error> { 1273 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
1264 self.wait_for_high().await; 1274 self.wait_for_high().await;
1265 Ok(()) 1275 Ok(())
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 74d015792..ac0eac96d 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -43,6 +43,18 @@ pub enum Error {
43 AddressReserved(u16), 43 AddressReserved(u16),
44} 44}
45 45
46/// I2C Config error
47#[derive(Debug, PartialEq, Eq)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub enum ConfigError {
50 /// Max i2c speed is 1MHz
51 FrequencyTooHigh,
52 /// The sys clock is too slow to support given frequency
53 ClockTooSlow,
54 /// The sys clock is too fast to support given frequency
55 ClockTooFast,
56}
57
46/// I2C config. 58/// I2C config.
47#[non_exhaustive] 59#[non_exhaustive]
48#[derive(Copy, Clone)] 60#[derive(Copy, Clone)]
@@ -365,37 +377,32 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
365 ) -> Self { 377 ) -> Self {
366 into_ref!(_peri); 378 into_ref!(_peri);
367 379
368 assert!(config.frequency <= 1_000_000);
369 assert!(config.frequency > 0);
370
371 let p = T::regs();
372
373 let reset = T::reset(); 380 let reset = T::reset();
374 crate::reset::reset(reset); 381 crate::reset::reset(reset);
375 crate::reset::unreset_wait(reset); 382 crate::reset::unreset_wait(reset);
376 383
377 p.ic_enable().write(|w| w.set_enable(false));
378
379 // Select controller mode & speed
380 p.ic_con().modify(|w| {
381 // Always use "fast" mode (<= 400 kHz, works fine for standard
382 // mode too)
383 w.set_speed(i2c::vals::Speed::FAST);
384 w.set_master_mode(true);
385 w.set_ic_slave_disable(true);
386 w.set_ic_restart_en(true);
387 w.set_tx_empty_ctrl(true);
388 });
389
390 // Set FIFO watermarks to 1 to make things simpler. This is encoded
391 // by a register value of 0.
392 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
393 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
394
395 // Configure SCL & SDA pins 384 // Configure SCL & SDA pins
396 set_up_i2c_pin(&scl); 385 set_up_i2c_pin(&scl);
397 set_up_i2c_pin(&sda); 386 set_up_i2c_pin(&sda);
398 387
388 let mut me = Self { phantom: PhantomData };
389
390 if let Err(e) = me.set_config_inner(&config) {
391 panic!("Error configuring i2c: {:?}", e);
392 }
393
394 me
395 }
396
397 fn set_config_inner(&mut self, config: &Config) -> Result<(), ConfigError> {
398 if config.frequency > 1_000_000 {
399 return Err(ConfigError::FrequencyTooHigh);
400 }
401
402 let p = T::regs();
403
404 p.ic_enable().write(|w| w.set_enable(false));
405
399 // Configure baudrate 406 // Configure baudrate
400 407
401 // There are some subtleties to I2C timing which we are completely 408 // There are some subtleties to I2C timing which we are completely
@@ -408,10 +415,12 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
408 let hcnt = period - lcnt; // and 2/5 (40%) of the period high 415 let hcnt = period - lcnt; // and 2/5 (40%) of the period high
409 416
410 // Check for out-of-range divisors: 417 // Check for out-of-range divisors:
411 assert!(hcnt <= 0xffff); 418 if hcnt > 0xffff || lcnt > 0xffff {
412 assert!(lcnt <= 0xffff); 419 return Err(ConfigError::ClockTooFast);
413 assert!(hcnt >= 8); 420 }
414 assert!(lcnt >= 8); 421 if hcnt < 8 || lcnt < 8 {
422 return Err(ConfigError::ClockTooSlow);
423 }
415 424
416 // Per I2C-bus specification a device in standard or fast mode must 425 // Per I2C-bus specification a device in standard or fast mode must
417 // internally provide a hold time of at least 300ns for the SDA 426 // internally provide a hold time of at least 300ns for the SDA
@@ -424,14 +433,19 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
424 ((clk_base * 3) / 10_000_000) + 1 433 ((clk_base * 3) / 10_000_000) + 1
425 } else { 434 } else {
426 // fast mode plus requires a clk_base > 32MHz 435 // fast mode plus requires a clk_base > 32MHz
427 assert!(clk_base >= 32_000_000); 436 if clk_base <= 32_000_000 {
437 return Err(ConfigError::ClockTooSlow);
438 }
428 439
429 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / 440 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
430 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't 441 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
431 // fit in uint. Add 1 to avoid division truncation. 442 // fit in uint. Add 1 to avoid division truncation.
432 ((clk_base * 3) / 25_000_000) + 1 443 ((clk_base * 3) / 25_000_000) + 1
433 }; 444 };
434 assert!(sda_tx_hold_count <= lcnt - 2); 445
446 if sda_tx_hold_count > lcnt - 2 {
447 return Err(ConfigError::ClockTooSlow);
448 }
435 449
436 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); 450 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16));
437 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); 451 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16));
@@ -440,10 +454,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
440 p.ic_sda_hold() 454 p.ic_sda_hold()
441 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); 455 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
442 456
443 // Enable I2C block
444 p.ic_enable().write(|w| w.set_enable(true)); 457 p.ic_enable().write(|w| w.set_enable(true));
445 458
446 Self { phantom: PhantomData } 459 Ok(())
447 } 460 }
448 461
449 fn setup(addr: u16) -> Result<(), Error> { 462 fn setup(addr: u16) -> Result<(), Error> {
@@ -757,6 +770,15 @@ where
757 } 770 }
758} 771}
759 772
773impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> {
774 type Config = Config;
775 type ConfigError = ConfigError;
776
777 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
778 self.set_config_inner(config)
779 }
780}
781
760/// Check if address is reserved. 782/// Check if address is reserved.
761pub fn i2c_reserved_addr(addr: u16) -> bool { 783pub fn i2c_reserved_addr(addr: u16) -> bool {
762 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 784 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs
index 721b7a1f6..97ca17295 100644
--- a/embassy-rp/src/i2c_slave.rs
+++ b/embassy-rp/src/i2c_slave.rs
@@ -21,6 +21,16 @@ pub enum Error {
21 Abort(AbortReason), 21 Abort(AbortReason),
22 /// User passed in a response buffer that was 0 length 22 /// User passed in a response buffer that was 0 length
23 InvalidResponseBufferLength, 23 InvalidResponseBufferLength,
24 /// The response buffer length was too short to contain the message
25 ///
26 /// The length parameter will always be the length of the buffer, and is
27 /// provided as a convenience for matching alongside `Command::Write`.
28 PartialWrite(usize),
29 /// The response buffer length was too short to contain the message
30 ///
31 /// The length parameter will always be the length of the buffer, and is
32 /// provided as a convenience for matching alongside `Command::GeneralCall`.
33 PartialGeneralCall(usize),
24} 34}
25 35
26/// Received command 36/// Received command
@@ -56,17 +66,24 @@ pub enum ReadStatus {
56pub struct Config { 66pub struct Config {
57 /// Target Address 67 /// Target Address
58 pub addr: u16, 68 pub addr: u16,
69 /// Control if the peripheral should ack to and report general calls.
70 pub general_call: bool,
59} 71}
60 72
61impl Default for Config { 73impl Default for Config {
62 fn default() -> Self { 74 fn default() -> Self {
63 Self { addr: 0x55 } 75 Self {
76 addr: 0x55,
77 general_call: true,
78 }
64 } 79 }
65} 80}
66 81
67/// I2CSlave driver. 82/// I2CSlave driver.
68pub struct I2cSlave<'d, T: Instance> { 83pub struct I2cSlave<'d, T: Instance> {
69 phantom: PhantomData<&'d mut T>, 84 phantom: PhantomData<&'d mut T>,
85 pending_byte: Option<u8>,
86 config: Config,
70} 87}
71 88
72impl<'d, T: Instance> I2cSlave<'d, T> { 89impl<'d, T: Instance> I2cSlave<'d, T> {
@@ -83,6 +100,25 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
83 assert!(!i2c_reserved_addr(config.addr)); 100 assert!(!i2c_reserved_addr(config.addr));
84 assert!(config.addr != 0); 101 assert!(config.addr != 0);
85 102
103 // Configure SCL & SDA pins
104 set_up_i2c_pin(&scl);
105 set_up_i2c_pin(&sda);
106
107 let mut ret = Self {
108 phantom: PhantomData,
109 pending_byte: None,
110 config,
111 };
112
113 ret.reset();
114
115 ret
116 }
117
118 /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus.
119 /// You can recover the bus by calling this function, but doing so will almost certainly cause
120 /// an i/o error in the master.
121 pub fn reset(&mut self) {
86 let p = T::regs(); 122 let p = T::regs();
87 123
88 let reset = T::reset(); 124 let reset = T::reset();
@@ -91,12 +127,24 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
91 127
92 p.ic_enable().write(|w| w.set_enable(false)); 128 p.ic_enable().write(|w| w.set_enable(false));
93 129
94 p.ic_sar().write(|w| w.set_ic_sar(config.addr)); 130 p.ic_sar().write(|w| w.set_ic_sar(self.config.addr));
95 p.ic_con().modify(|w| { 131 p.ic_con().modify(|w| {
96 w.set_master_mode(false); 132 w.set_master_mode(false);
97 w.set_ic_slave_disable(false); 133 w.set_ic_slave_disable(false);
98 w.set_tx_empty_ctrl(true); 134 w.set_tx_empty_ctrl(true);
135 w.set_rx_fifo_full_hld_ctrl(true);
136
137 // This typically makes no sense for a slave, but it is used to
138 // tune spike suppression, according to the datasheet.
139 w.set_speed(pac::i2c::vals::Speed::FAST);
140
141 // Generate stop interrupts for general calls
142 // This also causes stop interrupts for other devices on the bus but those will not be
143 // propagated up to the application.
144 w.set_stop_det_ifaddressed(!self.config.general_call);
99 }); 145 });
146 p.ic_ack_general_call()
147 .write(|w| w.set_ack_gen_call(self.config.general_call));
100 148
101 // Set FIFO watermarks to 1 to make things simpler. This is encoded 149 // Set FIFO watermarks to 1 to make things simpler. This is encoded
102 // by a register value of 0. Rx watermark should never change, but Tx watermark will be 150 // by a register value of 0. Rx watermark should never change, but Tx watermark will be
@@ -104,10 +152,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
104 p.ic_tx_tl().write(|w| w.set_tx_tl(0)); 152 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
105 p.ic_rx_tl().write(|w| w.set_rx_tl(0)); 153 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
106 154
107 // Configure SCL & SDA pins
108 set_up_i2c_pin(&scl);
109 set_up_i2c_pin(&sda);
110
111 // Clear interrupts 155 // Clear interrupts
112 p.ic_clr_intr().read(); 156 p.ic_clr_intr().read();
113 157
@@ -118,8 +162,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
118 p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); 162 p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
119 T::Interrupt::unpend(); 163 T::Interrupt::unpend();
120 unsafe { T::Interrupt::enable() }; 164 unsafe { T::Interrupt::enable() };
121
122 Self { phantom: PhantomData }
123 } 165 }
124 166
125 /// Calls `f` to check if we are ready or not. 167 /// Calls `f` to check if we are ready or not.
@@ -133,8 +175,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
133 future::poll_fn(|cx| { 175 future::poll_fn(|cx| {
134 let r = f(self); 176 let r = f(self);
135 177
136 trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0);
137
138 if r.is_pending() { 178 if r.is_pending() {
139 T::waker().register(cx.waker()); 179 T::waker().register(cx.waker());
140 g(self); 180 g(self);
@@ -146,71 +186,103 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
146 } 186 }
147 187
148 #[inline(always)] 188 #[inline(always)]
149 fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize { 189 fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) {
150 let p = T::regs(); 190 let p = T::regs();
151 let len = p.ic_rxflr().read().rxflr() as usize; 191
152 let end = offset + len; 192 if let Some(pending) = self.pending_byte.take() {
153 for i in offset..end { 193 buffer[*offset] = pending;
154 buffer[i] = p.ic_data_cmd().read().dat(); 194 *offset += 1;
155 } 195 }
156 end
157 }
158 196
159 #[inline(always)] 197 for b in &mut buffer[*offset..] {
160 fn write_to_fifo(&mut self, buffer: &[u8]) { 198 if !p.ic_status().read().rfne() {
161 let p = T::regs(); 199 break;
162 for byte in buffer { 200 }
163 p.ic_data_cmd().write(|w| w.set_dat(*byte)); 201
202 let dat = p.ic_data_cmd().read();
203 if *offset != 0 && dat.first_data_byte() {
204 // The RP2040 state machine will keep placing bytes into the
205 // FIFO, even if they are part of a subsequent write transaction.
206 //
207 // Unfortunately merely reading ic_data_cmd will consume that
208 // byte, the first byte of the next transaction, so we need
209 // to store it elsewhere
210 self.pending_byte = Some(dat.dat());
211 break;
212 }
213
214 *b = dat.dat();
215 *offset += 1;
164 } 216 }
165 } 217 }
166 218
167 /// Wait asynchronously for commands from an I2C master. 219 /// Wait asynchronously for commands from an I2C master.
168 /// `buffer` is provided in case master does a 'write' and is unused for 'read'. 220 /// `buffer` is provided in case master does a 'write', 'write read', or 'general call' and is unused for 'read'.
169 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> { 221 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
170 let p = T::regs(); 222 let p = T::regs();
171 223
172 p.ic_clr_intr().read();
173 // set rx fifo watermark to 1 byte 224 // set rx fifo watermark to 1 byte
174 p.ic_rx_tl().write(|w| w.set_rx_tl(0)); 225 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
175 226
176 let mut len = 0; 227 let mut len = 0;
177 let ret = self 228 self.wait_on(
178 .wait_on( 229 |me| {
179 |me| { 230 let stat = p.ic_raw_intr_stat().read();
180 let stat = p.ic_raw_intr_stat().read(); 231 trace!("ls:{:013b} len:{}", stat.0, len);
181 if p.ic_rxflr().read().rxflr() > 0 { 232
182 len = me.drain_fifo(buffer, len); 233 if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() {
183 // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise 234 me.drain_fifo(buffer, &mut len);
184 p.ic_rx_tl().write(|w| w.set_rx_tl(11)); 235 // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise
185 } 236 p.ic_rx_tl().write(|w| w.set_rx_tl(11));
186 237 }
187 if stat.restart_det() && stat.rd_req() { 238
188 Poll::Ready(Ok(Command::WriteRead(len))) 239 if buffer.len() == len {
189 } else if stat.gen_call() && stat.stop_det() && len > 0 { 240 if stat.gen_call() {
190 Poll::Ready(Ok(Command::GeneralCall(len))) 241 return Poll::Ready(Err(Error::PartialGeneralCall(buffer.len())));
191 } else if stat.stop_det() {
192 Poll::Ready(Ok(Command::Write(len)))
193 } else if stat.rd_req() {
194 Poll::Ready(Ok(Command::Read))
195 } else { 242 } else {
196 Poll::Pending 243 return Poll::Ready(Err(Error::PartialWrite(buffer.len())));
197 } 244 }
198 }, 245 }
199 |_me| { 246 trace!("len:{}, pend:{:?}", len, me.pending_byte);
200 p.ic_intr_mask().modify(|w| { 247 if me.pending_byte.is_some() {
201 w.set_m_stop_det(true); 248 warn!("pending")
202 w.set_m_restart_det(true); 249 }
203 w.set_m_gen_call(true); 250
204 w.set_m_rd_req(true); 251 if stat.restart_det() && stat.rd_req() {
205 w.set_m_rx_full(true); 252 p.ic_clr_restart_det().read();
206 }); 253 Poll::Ready(Ok(Command::WriteRead(len)))
207 }, 254 } else if stat.gen_call() && stat.stop_det() && len > 0 {
208 ) 255 p.ic_clr_gen_call().read();
209 .await; 256 p.ic_clr_stop_det().read();
210 257 Poll::Ready(Ok(Command::GeneralCall(len)))
211 p.ic_clr_intr().read(); 258 } else if stat.stop_det() && len > 0 {
212 259 p.ic_clr_stop_det().read();
213 ret 260 Poll::Ready(Ok(Command::Write(len)))
261 } else if stat.rd_req() {
262 p.ic_clr_stop_det().read();
263 p.ic_clr_restart_det().read();
264 p.ic_clr_gen_call().read();
265 Poll::Ready(Ok(Command::Read))
266 } else if stat.stop_det() {
267 // clear stuck stop bit
268 // This can happen if the SDA/SCL pullups are enabled after calling this func
269 p.ic_clr_stop_det().read();
270 Poll::Pending
271 } else {
272 Poll::Pending
273 }
274 },
275 |_me| {
276 p.ic_intr_mask().write(|w| {
277 w.set_m_stop_det(true);
278 w.set_m_restart_det(true);
279 w.set_m_gen_call(true);
280 w.set_m_rd_req(true);
281 w.set_m_rx_full(true);
282 });
283 },
284 )
285 .await
214 } 286 }
215 287
216 /// Respond to an I2C master READ command, asynchronously. 288 /// Respond to an I2C master READ command, asynchronously.
@@ -223,54 +295,61 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
223 295
224 let mut chunks = buffer.chunks(FIFO_SIZE as usize); 296 let mut chunks = buffer.chunks(FIFO_SIZE as usize);
225 297
226 let ret = self 298 self.wait_on(
227 .wait_on( 299 |me| {
228 |me| { 300 let stat = p.ic_raw_intr_stat().read();
301 trace!("rs:{:013b}", stat.0);
302
303 if stat.tx_abrt() {
229 if let Err(abort_reason) = me.read_and_clear_abort_reason() { 304 if let Err(abort_reason) = me.read_and_clear_abort_reason() {
230 if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { 305 if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason {
306 p.ic_clr_intr().read();
231 return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); 307 return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes)));
232 } else { 308 } else {
233 return Poll::Ready(Err(abort_reason)); 309 return Poll::Ready(Err(abort_reason));
234 } 310 }
235 } 311 }
312 }
236 313
237 if let Some(chunk) = chunks.next() { 314 if let Some(chunk) = chunks.next() {
238 me.write_to_fifo(chunk); 315 for byte in chunk {
316 p.ic_clr_rd_req().read();
317 p.ic_data_cmd().write(|w| w.set_dat(*byte));
318 }
239 319
240 Poll::Pending 320 Poll::Pending
321 } else {
322 if stat.rx_done() {
323 p.ic_clr_rx_done().read();
324 Poll::Ready(Ok(ReadStatus::Done))
325 } else if stat.rd_req() && stat.tx_empty() {
326 Poll::Ready(Ok(ReadStatus::NeedMoreBytes))
241 } else { 327 } else {
242 let stat = p.ic_raw_intr_stat().read(); 328 Poll::Pending
243
244 if stat.rx_done() && stat.stop_det() {
245 Poll::Ready(Ok(ReadStatus::Done))
246 } else if stat.rd_req() {
247 Poll::Ready(Ok(ReadStatus::NeedMoreBytes))
248 } else {
249 Poll::Pending
250 }
251 } 329 }
252 }, 330 }
253 |_me| { 331 },
254 p.ic_intr_mask().modify(|w| { 332 |_me| {
255 w.set_m_stop_det(true); 333 p.ic_intr_mask().write(|w| {
256 w.set_m_rx_done(true); 334 w.set_m_rx_done(true);
257 w.set_m_tx_empty(true); 335 w.set_m_tx_empty(true);
258 w.set_m_tx_abrt(true); 336 w.set_m_tx_abrt(true);
259 }) 337 })
260 }, 338 },
261 ) 339 )
262 .await; 340 .await
263
264 p.ic_clr_intr().read();
265
266 ret
267 } 341 }
268 342
269 /// Respond to reads with the fill byte until the controller stops asking 343 /// Respond to reads with the fill byte until the controller stops asking
270 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { 344 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> {
345 // Send fill bytes a full fifo at a time, to reduce interrupt noise.
346 // This does mean we'll almost certainly abort the write, but since these are fill bytes,
347 // we don't care.
348 let buff = [fill; FIFO_SIZE as usize];
271 loop { 349 loop {
272 match self.respond_to_read(&[fill]).await { 350 match self.respond_to_read(&buff).await {
273 Ok(ReadStatus::NeedMoreBytes) => (), 351 Ok(ReadStatus::NeedMoreBytes) => (),
352 Ok(ReadStatus::LeftoverBytes(_)) => break Ok(()),
274 Ok(_) => break Ok(()), 353 Ok(_) => break Ok(()),
275 Err(e) => break Err(e), 354 Err(e) => break Err(e),
276 } 355 }
@@ -292,14 +371,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
292 #[inline(always)] 371 #[inline(always)]
293 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { 372 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
294 let p = T::regs(); 373 let p = T::regs();
295 let mut abort_reason = p.ic_tx_abrt_source().read(); 374 let abort_reason = p.ic_tx_abrt_source().read();
296
297 // Mask off fifo flush count
298 let tx_flush_cnt = abort_reason.tx_flush_cnt();
299 abort_reason.set_tx_flush_cnt(0);
300
301 // Mask off master_dis
302 abort_reason.set_abrt_master_dis(false);
303 375
304 if abort_reason.0 != 0 { 376 if abort_reason.0 != 0 {
305 // Note clearing the abort flag also clears the reason, and this 377 // Note clearing the abort flag also clears the reason, and this
@@ -314,8 +386,8 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
314 AbortReason::NoAcknowledge 386 AbortReason::NoAcknowledge
315 } else if abort_reason.arb_lost() { 387 } else if abort_reason.arb_lost() {
316 AbortReason::ArbitrationLoss 388 AbortReason::ArbitrationLoss
317 } else if abort_reason.abrt_slvflush_txfifo() { 389 } else if abort_reason.tx_flush_cnt() > 0 {
318 AbortReason::TxNotEmpty(tx_flush_cnt) 390 AbortReason::TxNotEmpty(abort_reason.tx_flush_cnt())
319 } else { 391 } else {
320 AbortReason::Other(abort_reason.0) 392 AbortReason::Other(abort_reason.0)
321 }; 393 };
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 99fce0fc9..f372cb640 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -118,6 +118,17 @@ pub enum Error {
118 Framing, 118 Framing,
119} 119}
120 120
121/// Read To Break error
122#[derive(Debug, Eq, PartialEq, Copy, Clone)]
123#[cfg_attr(feature = "defmt", derive(defmt::Format))]
124#[non_exhaustive]
125pub enum ReadToBreakError {
126 /// Read this many bytes, but never received a line break.
127 MissingBreak(usize),
128 /// Other, standard issue with the serial request
129 Other(Error),
130}
131
121/// Internal DMA state of UART RX. 132/// Internal DMA state of UART RX.
122pub struct DmaState { 133pub struct DmaState {
123 rx_err_waker: AtomicWaker, 134 rx_err_waker: AtomicWaker,
@@ -274,14 +285,17 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
274 285
275 /// Read from UART RX blocking execution until done. 286 /// Read from UART RX blocking execution until done.
276 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 287 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
277 while buffer.len() > 0 { 288 while !buffer.is_empty() {
278 let received = self.drain_fifo(buffer)?; 289 let received = self.drain_fifo(buffer).map_err(|(_i, e)| e)?;
279 buffer = &mut buffer[received..]; 290 buffer = &mut buffer[received..];
280 } 291 }
281 Ok(()) 292 Ok(())
282 } 293 }
283 294
284 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 295 /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was
296 /// encountered. in both cases, `len` is the number of *good* bytes copied into
297 /// `buffer`.
298 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
285 let r = T::regs(); 299 let r = T::regs();
286 for (i, b) in buffer.iter_mut().enumerate() { 300 for (i, b) in buffer.iter_mut().enumerate() {
287 if r.uartfr().read().rxfe() { 301 if r.uartfr().read().rxfe() {
@@ -291,13 +305,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
291 let dr = r.uartdr().read(); 305 let dr = r.uartdr().read();
292 306
293 if dr.oe() { 307 if dr.oe() {
294 return Err(Error::Overrun); 308 return Err((i, Error::Overrun));
295 } else if dr.be() { 309 } else if dr.be() {
296 return Err(Error::Break); 310 return Err((i, Error::Break));
297 } else if dr.pe() { 311 } else if dr.pe() {
298 return Err(Error::Parity); 312 return Err((i, Error::Parity));
299 } else if dr.fe() { 313 } else if dr.fe() {
300 return Err(Error::Framing); 314 return Err((i, Error::Framing));
301 } else { 315 } else {
302 *b = dr.data(); 316 *b = dr.data();
303 } 317 }
@@ -389,7 +403,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
389 } { 403 } {
390 Ok(len) if len < buffer.len() => &mut buffer[len..], 404 Ok(len) if len < buffer.len() => &mut buffer[len..],
391 Ok(_) => return Ok(()), 405 Ok(_) => return Ok(()),
392 Err(e) => return Err(e), 406 Err((_i, e)) => return Err(e),
393 }; 407 };
394 408
395 // start a dma transfer. if errors have happened in the interim some error 409 // start a dma transfer. if errors have happened in the interim some error
@@ -426,13 +440,25 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
426 .await; 440 .await;
427 441
428 let errors = match transfer_result { 442 let errors = match transfer_result {
429 Either::First(()) => return Ok(()), 443 Either::First(()) => {
430 Either::Second(e) => e, 444 // We're here because the DMA finished, BUT if an error occurred on the LAST
445 // byte, then we may still need to grab the error state!
446 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
447 }
448 Either::Second(e) => {
449 // We're here because we errored, which means this is the error that
450 // was problematic.
451 e
452 }
431 }; 453 };
432 454
455 // If we got no error, just return at this point
433 if errors.0 == 0 { 456 if errors.0 == 0 {
434 return Ok(()); 457 return Ok(());
435 } else if errors.oeris() { 458 }
459
460 // If we DID get an error, we need to figure out which one it was.
461 if errors.oeris() {
436 return Err(Error::Overrun); 462 return Err(Error::Overrun);
437 } else if errors.beris() { 463 } else if errors.beris() {
438 return Err(Error::Break); 464 return Err(Error::Break);
@@ -443,6 +469,173 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
443 } 469 }
444 unreachable!("unrecognized rx error"); 470 unreachable!("unrecognized rx error");
445 } 471 }
472
473 /// Read from the UART, waiting for a line break.
474 ///
475 /// We read until one of the following occurs:
476 ///
477 /// * We read `buffer.len()` bytes without a line break
478 /// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))`
479 /// * We read `n` bytes then a line break occurs
480 /// * returns `Ok(n)`
481 /// * We encounter some error OTHER than a line break
482 /// * returns `Err(ReadToBreakError::Other(error))`
483 ///
484 /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected
485 /// message to reliably detect the framing on one single call to `read_to_break()`.
486 ///
487 /// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer:
488 /// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))`
489 /// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break
490 /// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer:
491 /// * The first call to `read_to_break()` will return `Ok(20)`.
492 /// * The next call to `read_to_break()` will work as expected
493 pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> {
494 // clear error flags before we drain the fifo. errors that have accumulated
495 // in the flags will also be present in the fifo.
496 T::dma_state().rx_errs.store(0, Ordering::Relaxed);
497 T::regs().uarticr().write(|w| {
498 w.set_oeic(true);
499 w.set_beic(true);
500 w.set_peic(true);
501 w.set_feic(true);
502 });
503
504 // then drain the fifo. we need to read at most 32 bytes. errors that apply
505 // to fifo bytes will be reported directly.
506 let sbuffer = match {
507 let limit = buffer.len().min(32);
508 self.drain_fifo(&mut buffer[0..limit])
509 } {
510 // Drained fifo, still some room left!
511 Ok(len) if len < buffer.len() => &mut buffer[len..],
512 // Drained (some/all of the fifo), no room left
513 Ok(len) => return Err(ReadToBreakError::MissingBreak(len)),
514 // We got a break WHILE draining the FIFO, return what we did get before the break
515 Err((i, Error::Break)) => return Ok(i),
516 // Some other error, just return the error
517 Err((_i, e)) => return Err(ReadToBreakError::Other(e)),
518 };
519
520 // start a dma transfer. if errors have happened in the interim some error
521 // interrupt flags will have been raised, and those will be picked up immediately
522 // by the interrupt handler.
523 let mut ch = self.rx_dma.as_mut().unwrap();
524 T::regs().uartimsc().write_set(|w| {
525 w.set_oeim(true);
526 w.set_beim(true);
527 w.set_peim(true);
528 w.set_feim(true);
529 });
530 T::regs().uartdmacr().write_set(|reg| {
531 reg.set_rxdmae(true);
532 reg.set_dmaonerr(true);
533 });
534 let transfer = unsafe {
535 // If we don't assign future to a variable, the data register pointer
536 // is held across an await and makes the future non-Send.
537 crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ)
538 };
539
540 // wait for either the transfer to complete or an error to happen.
541 let transfer_result = select(
542 transfer,
543 poll_fn(|cx| {
544 T::dma_state().rx_err_waker.register(cx.waker());
545 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
546 0 => Poll::Pending,
547 e => Poll::Ready(Uartris(e as u32)),
548 }
549 }),
550 )
551 .await;
552
553 // Figure out our error state
554 let errors = match transfer_result {
555 Either::First(()) => {
556 // We're here because the DMA finished, BUT if an error occurred on the LAST
557 // byte, then we may still need to grab the error state!
558 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
559 }
560 Either::Second(e) => {
561 // We're here because we errored, which means this is the error that
562 // was problematic.
563 e
564 }
565 };
566
567 if errors.0 == 0 {
568 // No errors? That means we filled the buffer without a line break.
569 // For THIS function, that's a problem.
570 return Err(ReadToBreakError::MissingBreak(buffer.len()));
571 } else if errors.beris() {
572 // We got a Line Break! By this point, we've finished/aborted the DMA
573 // transaction, which means that we need to figure out where it left off
574 // by looking at the write_addr.
575 //
576 // First, we do a sanity check to make sure the write value is within the
577 // range of DMA we just did.
578 let sval = buffer.as_ptr() as usize;
579 let eval = sval + buffer.len();
580
581 // This is the address where the DMA would write to next
582 let next_addr = ch.regs().write_addr().read() as usize;
583
584 // If we DON'T end up inside the range, something has gone really wrong.
585 // Note that it's okay that `eval` is one past the end of the slice, as
586 // this is where the write pointer will end up at the end of a full
587 // transfer.
588 if (next_addr < sval) || (next_addr > eval) {
589 unreachable!("UART DMA reported invalid `write_addr`");
590 }
591
592 let regs = T::regs();
593 let all_full = next_addr == eval;
594
595 // NOTE: This is off label usage of RSR! See the issue below for
596 // why I am not checking if there is an "extra" FIFO byte, and why
597 // I am checking RSR directly (it seems to report the status of the LAST
598 // POPPED value, rather than the NEXT TO POP value like the datasheet
599 // suggests!)
600 //
601 // issue: https://github.com/raspberrypi/pico-feedback/issues/367
602 let last_was_break = regs.uartrsr().read().be();
603
604 return match (all_full, last_was_break) {
605 (true, true) | (false, _) => {
606 // We got less than the full amount + a break, or the full amount
607 // and the last byte was a break. Subtract the break off by adding one to sval.
608 Ok(next_addr.saturating_sub(1 + sval))
609 }
610 (true, false) => {
611 // We finished the whole DMA, and the last DMA'd byte was NOT a break
612 // character. This is an error.
613 //
614 // NOTE: we COULD potentially return Ok(buffer.len()) here, since we
615 // know a line break occured at SOME POINT after the DMA completed.
616 //
617 // However, we have no way of knowing if there was extra data BEFORE
618 // that line break, so instead return an Err to signal to the caller
619 // that there are "leftovers", and they'll catch the actual line break
620 // on the next call.
621 //
622 // Doing it like this also avoids racyness: now whether you finished
623 // the full read BEFORE the line break occurred or AFTER the line break
624 // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
625 // getting `Ok(buffer.len())` if you were "late enough" to observe the
626 // line break.
627 Err(ReadToBreakError::MissingBreak(buffer.len()))
628 }
629 };
630 } else if errors.oeris() {
631 return Err(ReadToBreakError::Other(Error::Overrun));
632 } else if errors.peris() {
633 return Err(ReadToBreakError::Other(Error::Parity));
634 } else if errors.feris() {
635 return Err(ReadToBreakError::Other(Error::Framing));
636 }
637 unreachable!("unrecognized rx error");
638 }
446} 639}
447 640
448impl<'d, T: Instance> Uart<'d, T, Blocking> { 641impl<'d, T: Instance> Uart<'d, T, Blocking> {
@@ -743,6 +936,13 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
743 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 936 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
744 self.rx.read(buffer).await 937 self.rx.read(buffer).await
745 } 938 }
939
940 /// Read until the buffer is full or a line break occurs.
941 ///
942 /// See [`UartRx::read_to_break()`] for more details
943 pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> {
944 self.rx.read_to_break(buf).await
945 }
746} 946}
747 947
748impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> { 948impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 4f53a400a..360ca5f4b 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -44,6 +44,8 @@ defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embas
44ble = ["dep:stm32wb-hci"] 44ble = ["dep:stm32wb-hci"]
45mac = ["dep:bitflags", "dep:embassy-net-driver" ] 45mac = ["dep:bitflags", "dep:embassy-net-driver" ]
46 46
47extended = []
48
47stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] 49stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
48stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] 50stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
49stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ] 51stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs
index 94aac070d..7ab458bf2 100644
--- a/embassy-stm32-wpan/build.rs
+++ b/embassy-stm32-wpan/build.rs
@@ -18,9 +18,22 @@ fn main() {
18 // stm32wb tl_mbox link sections 18 // stm32wb tl_mbox link sections
19 19
20 let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string(); 20 let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string();
21 fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap(); 21 let in_file;
22 if env::var_os("CARGO_FEATURE_EXTENDED").is_some() {
23 if env::vars()
24 .map(|(a, _)| a)
25 .any(|x| x.starts_with("CARGO_FEATURE_STM32WB1"))
26 {
27 in_file = "tl_mbox_extended_wb1.x.in";
28 } else {
29 in_file = "tl_mbox_extended_wbx5.x.in";
30 }
31 } else {
32 in_file = "tl_mbox.x.in";
33 }
34 fs::write(out_file, fs::read_to_string(in_file).unwrap()).unwrap();
22 println!("cargo:rustc-link-search={}", out_dir.display()); 35 println!("cargo:rustc-link-search={}", out_dir.display());
23 println!("cargo:rerun-if-changed=tl_mbox.x.in"); 36 println!("cargo:rerun-if-changed={}", in_file);
24} 37}
25 38
26enum GetOneError { 39enum GetOneError {
diff --git a/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in b/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in
new file mode 100644
index 000000000..4cffdaddd
--- /dev/null
+++ b/embassy-stm32-wpan/tl_mbox_extended_wb1.x.in
@@ -0,0 +1,16 @@
1MEMORY
2{
3 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 4K
4 RAMB_SHARED (xrw) : ORIGIN = 0x20030028, LENGTH = 4K
5}
6
7/*
8 * Scatter the mailbox interface memory sections in shared memory
9 */
10SECTIONS
11{
12 TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
13
14 MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED
15 MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED
16}
diff --git a/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in b/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in
new file mode 100644
index 000000000..281d637a9
--- /dev/null
+++ b/embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in
@@ -0,0 +1,16 @@
1MEMORY
2{
3 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 2K
4 RAMB_SHARED (xrw) : ORIGIN = 0x20038000, LENGTH = 10K
5}
6
7/*
8 * Scatter the mailbox interface memory sections in shared memory
9 */
10SECTIONS
11{
12 TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
13
14 MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED
15 MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED
16}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index b80509098..89c17cb3d 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -55,10 +55,12 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un
55embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 55embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
56embedded-hal-async = { version = "1.0" } 56embedded-hal-async = { version = "1.0" }
57embedded-hal-nb = { version = "1.0" } 57embedded-hal-nb = { version = "1.0" }
58embedded-can = "0.4"
58 59
59embedded-storage = "0.3.1" 60embedded-storage = "0.3.1"
60embedded-storage-async = { version = "0.4.1" } 61embedded-storage-async = { version = "0.4.1" }
61 62
63
62defmt = { version = "0.3", optional = true } 64defmt = { version = "0.3", optional = true }
63log = { version = "0.4.14", optional = true } 65log = { version = "0.4.14", optional = true }
64cortex-m-rt = ">=0.6.15,<0.8" 66cortex-m-rt = ">=0.6.15,<0.8"
@@ -67,8 +69,8 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
67rand_core = "0.6.3" 69rand_core = "0.6.3"
68sdio-host = "0.5.0" 70sdio-host = "0.5.0"
69critical-section = "1.1" 71critical-section = "1.1"
70# stm32-metapac = { version = "15" } 72#stm32-metapac = { version = "15" }
71stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2d51fbe7363a376606cb670cc2cec0f634251022" } 73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e7f91751fbbf856e0cb30e50ae6db79f0409b085" }
72vcell = "0.1.3" 74vcell = "0.1.3"
73bxcan = "0.7.0" 75bxcan = "0.7.0"
74nb = "1.0.0" 76nb = "1.0.0"
@@ -80,14 +82,20 @@ chrono = { version = "^0.4", default-features = false, optional = true}
80bit_field = "0.10.2" 82bit_field = "0.10.2"
81document-features = "0.2.7" 83document-features = "0.2.7"
82 84
85static_assertions = { version = "1.1" }
86volatile-register = { version = "0.2.1" }
87
88
89
83[dev-dependencies] 90[dev-dependencies]
84critical-section = { version = "1.1", features = ["std"] } 91critical-section = { version = "1.1", features = ["std"] }
85 92
86[build-dependencies] 93[build-dependencies]
87proc-macro2 = "1.0.36" 94proc-macro2 = "1.0.36"
88quote = "1.0.15" 95quote = "1.0.15"
89# stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 96
90stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2d51fbe7363a376606cb670cc2cec0f634251022", default-features = false, features = ["metadata"]} 97#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
98stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e7f91751fbbf856e0cb30e50ae6db79f0409b085", default-features = false, features = ["metadata"]}
91 99
92 100
93[features] 101[features]
@@ -123,6 +131,8 @@ _time-driver = ["dep:embassy-time-driver", "time"]
123 131
124## Use any time driver 132## Use any time driver
125time-driver-any = ["_time-driver"] 133time-driver-any = ["_time-driver"]
134## Use TIM1 as time driver
135time-driver-tim1 = ["_time-driver"]
126## Use TIM2 as time driver 136## Use TIM2 as time driver
127time-driver-tim2 = ["_time-driver"] 137time-driver-tim2 = ["_time-driver"]
128## Use TIM3 as time driver 138## Use TIM3 as time driver
@@ -131,18 +141,24 @@ time-driver-tim3 = ["_time-driver"]
131time-driver-tim4 = ["_time-driver"] 141time-driver-tim4 = ["_time-driver"]
132## Use TIM5 as time driver 142## Use TIM5 as time driver
133time-driver-tim5 = ["_time-driver"] 143time-driver-tim5 = ["_time-driver"]
144## Use TIM8 as time driver
145time-driver-tim8 = ["_time-driver"]
134## Use TIM9 as time driver 146## Use TIM9 as time driver
135time-driver-tim9 = ["_time-driver"] 147time-driver-tim9 = ["_time-driver"]
136## Use TIM11 as time driver
137time-driver-tim11 = ["_time-driver"]
138## Use TIM12 as time driver 148## Use TIM12 as time driver
139time-driver-tim12 = ["_time-driver"] 149time-driver-tim12 = ["_time-driver"]
140## Use TIM15 as time driver 150## Use TIM15 as time driver
141time-driver-tim15 = ["_time-driver"] 151time-driver-tim15 = ["_time-driver"]
152## Use TIM20 as time driver
153time-driver-tim20 = ["_time-driver"]
142## Use TIM21 as time driver 154## Use TIM21 as time driver
143time-driver-tim21 = ["_time-driver"] 155time-driver-tim21 = ["_time-driver"]
144## Use TIM22 as time driver 156## Use TIM22 as time driver
145time-driver-tim22 = ["_time-driver"] 157time-driver-tim22 = ["_time-driver"]
158## Use TIM23 as time driver
159time-driver-tim23 = ["_time-driver"]
160## Use TIM24 as time driver
161time-driver-tim24 = ["_time-driver"]
146 162
147 163
148#! ## Analog Switch Pins (Pxy_C) on STM32H7 series 164#! ## Analog Switch Pins (Pxy_C) on STM32H7 series
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index f1ead6d46..3a30ba2fd 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -5,8 +5,9 @@ use std::{env, fs};
5 5
6use proc_macro2::{Ident, TokenStream}; 6use proc_macro2::{Ident, TokenStream};
7use quote::{format_ident, quote}; 7use quote::{format_ident, quote};
8use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet}; 8use stm32_metapac::metadata::{
9use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, StopMode, METADATA}; 9 MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA,
10};
10 11
11fn main() { 12fn main() {
12 let target = env::var("TARGET").unwrap(); 13 let target = env::var("TARGET").unwrap();
@@ -183,40 +184,33 @@ fn main() {
183 184
184 let time_driver_singleton = match time_driver.as_ref().map(|x| x.as_ref()) { 185 let time_driver_singleton = match time_driver.as_ref().map(|x| x.as_ref()) {
185 None => "", 186 None => "",
187 Some("tim1") => "TIM1",
186 Some("tim2") => "TIM2", 188 Some("tim2") => "TIM2",
187 Some("tim3") => "TIM3", 189 Some("tim3") => "TIM3",
188 Some("tim4") => "TIM4", 190 Some("tim4") => "TIM4",
189 Some("tim5") => "TIM5", 191 Some("tim5") => "TIM5",
192 Some("tim8") => "TIM8",
190 Some("tim9") => "TIM9", 193 Some("tim9") => "TIM9",
191 Some("tim11") => "TIM11",
192 Some("tim12") => "TIM12", 194 Some("tim12") => "TIM12",
193 Some("tim15") => "TIM15", 195 Some("tim15") => "TIM15",
196 Some("tim20") => "TIM20",
194 Some("tim21") => "TIM21", 197 Some("tim21") => "TIM21",
195 Some("tim22") => "TIM22", 198 Some("tim22") => "TIM22",
199 Some("tim23") => "TIM23",
200 Some("tim24") => "TIM24",
196 Some("any") => { 201 Some("any") => {
197 if singletons.contains(&"TIM2".to_string()) { 202 // Order of TIM candidators:
198 "TIM2" 203 // 1. 2CH -> 2CH_CMP -> GP16 -> GP32 -> ADV
199 } else if singletons.contains(&"TIM3".to_string()) { 204 // 2. In same catagory: larger TIM number first
200 "TIM3" 205 [
201 } else if singletons.contains(&"TIM4".to_string()) { 206 "TIM22", "TIM21", "TIM12", "TIM9", // 2CH
202 "TIM4" 207 "TIM15", // 2CH_CMP
203 } else if singletons.contains(&"TIM5".to_string()) { 208 "TIM19", "TIM4", "TIM3", // GP16
204 "TIM5" 209 "TIM24", "TIM23", "TIM5", "TIM2", // GP32
205 } else if singletons.contains(&"TIM9".to_string()) { 210 "TIM20", "TIM8", "TIM1", //ADV
206 "TIM9" 211 ]
207 } else if singletons.contains(&"TIM11".to_string()) { 212 .iter()
208 "TIM11" 213 .find(|tim| singletons.contains(&tim.to_string())).expect("time-driver-any requested, but the chip doesn't have TIM1, TIM2, TIM3, TIM4, TIM5, TIM8, TIM9, TIM12, TIM15, TIM20, TIM21, TIM22, TIM23 or TIM24.")
209 } else if singletons.contains(&"TIM12".to_string()) {
210 "TIM12"
211 } else if singletons.contains(&"TIM15".to_string()) {
212 "TIM15"
213 } else if singletons.contains(&"TIM21".to_string()) {
214 "TIM21"
215 } else if singletons.contains(&"TIM22".to_string()) {
216 "TIM22"
217 } else {
218 panic!("time-driver-any requested, but the chip doesn't have TIM2, TIM3, TIM4, TIM5, TIM9, TIM11, TIM12 or TIM15.")
219 }
220 } 214 }
221 _ => panic!("unknown time_driver {:?}", time_driver), 215 _ => panic!("unknown time_driver {:?}", time_driver),
222 }; 216 };
@@ -362,50 +356,6 @@ fn main() {
362 g.extend(quote! { pub mod flash_regions { #flash_regions } }); 356 g.extend(quote! { pub mod flash_regions { #flash_regions } });
363 357
364 // ======== 358 // ========
365 // Generate DMA IRQs.
366
367 let mut dma_irqs: BTreeMap<&str, Vec<(&str, &str, &str)>> = BTreeMap::new();
368
369 for p in METADATA.peripherals {
370 if let Some(r) = &p.registers {
371 if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" {
372 if p.name == "BDMA1" {
373 // BDMA1 in H7 doesn't use DMAMUX, which breaks
374 continue;
375 }
376 for irq in p.interrupts {
377 dma_irqs
378 .entry(irq.interrupt)
379 .or_default()
380 .push((r.kind, p.name, irq.signal));
381 }
382 }
383 }
384 }
385
386 let dma_irqs: TokenStream = dma_irqs
387 .iter()
388 .map(|(irq, channels)| {
389 let irq = format_ident!("{}", irq);
390
391 let xdma = format_ident!("{}", channels[0].0);
392 let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch));
393
394 quote! {
395 #[cfg(feature = "rt")]
396 #[crate::interrupt]
397 unsafe fn #irq () {
398 #(
399 <crate::peripherals::#channels as crate::dma::#xdma::sealed::Channel>::on_irq();
400 )*
401 }
402 }
403 })
404 .collect();
405
406 g.extend(dma_irqs);
407
408 // ========
409 // Extract the rcc registers 359 // Extract the rcc registers
410 let rcc_registers = METADATA 360 let rcc_registers = METADATA
411 .peripherals 361 .peripherals
@@ -415,42 +365,141 @@ fn main() {
415 .unwrap(); 365 .unwrap();
416 366
417 // ======== 367 // ========
418 // Generate rcc fieldset and enum maps 368 // Generate RccPeripheral impls
419 let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = {
420 let rcc_blocks = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
421 let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.ir.fieldsets.iter().map(|f| (f.name, f)).collect();
422 let rcc_enums: HashMap<&str, &Enum> = rcc_registers.ir.enums.iter().map(|e| (e.name, e)).collect();
423 369
424 rcc_blocks 370 // count how many times each xxENR field is used, to enable refcounting if used more than once.
425 .iter() 371 let mut rcc_field_count: HashMap<_, usize> = HashMap::new();
426 .filter_map(|b| match &b.inner { 372 for p in METADATA.peripherals {
427 BlockItemInner::Register(register) => register.fieldset.map(|f| (b.name, f)), 373 if let Some(rcc) = &p.rcc {
428 _ => None, 374 let en = rcc.enable.as_ref().unwrap();
429 }) 375 *rcc_field_count.entry((en.register, en.field)).or_insert(0) += 1;
430 .filter_map(|(b, f)| { 376 }
431 rcc_fieldsets.get(f).map(|f| { 377 }
432 ( 378
433 b, 379 struct ClockGen<'a> {
434 f.fields 380 rcc_registers: &'a PeripheralRegisters,
435 .iter() 381 chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
436 .filter_map(|f| { 382 force_refcount: HashSet<&'a str>,
437 let enumm = f.enumm?; 383
438 let enumm = rcc_enums.get(enumm)?; 384 refcount_statics: BTreeSet<Ident>,
439 385 clock_names: BTreeSet<String>,
440 Some((f.name, *enumm)) 386 muxes: BTreeSet<(Ident, Ident, Ident)>,
441 }) 387 }
442 .collect(), 388
443 ) 389 let mut clock_gen = ClockGen {
444 }) 390 rcc_registers,
445 }) 391 chained_muxes: HashMap::new(),
446 .collect() 392 force_refcount: HashSet::from(["usart"]),
393
394 refcount_statics: BTreeSet::new(),
395 clock_names: BTreeSet::new(),
396 muxes: BTreeSet::new(),
447 }; 397 };
398 if chip_name.starts_with("stm32h5") {
399 clock_gen.chained_muxes.insert(
400 "PER",
401 &PeripheralRccRegister {
402 register: "CCIPR5",
403 field: "PERSEL",
404 },
405 );
406 }
407 if chip_name.starts_with("stm32h7") {
408 clock_gen.chained_muxes.insert(
409 "PER",
410 &PeripheralRccRegister {
411 register: "D1CCIPR",
412 field: "PERSEL",
413 },
414 );
415 }
416 if chip_name.starts_with("stm32u5") {
417 clock_gen.chained_muxes.insert(
418 "ICLK",
419 &PeripheralRccRegister {
420 register: "CCIPR1",
421 field: "ICLKSEL",
422 },
423 );
424 }
425 if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") {
426 clock_gen.chained_muxes.insert(
427 "CLK48",
428 &PeripheralRccRegister {
429 register: "CCIPR",
430 field: "CLK48SEL",
431 },
432 );
433 }
434 if chip_name.starts_with("stm32f7") {
435 clock_gen.chained_muxes.insert(
436 "CLK48",
437 &PeripheralRccRegister {
438 register: "DCKCFGR2",
439 field: "CLK48SEL",
440 },
441 );
442 }
443 if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") {
444 clock_gen.chained_muxes.insert(
445 "CLK48",
446 &PeripheralRccRegister {
447 register: "DCKCFGR",
448 field: "CLK48SEL",
449 },
450 );
451 }
448 452
449 // ======== 453 impl<'a> ClockGen<'a> {
450 // Generate RccPeripheral impls 454 fn gen_clock(&mut self, name: &str) -> TokenStream {
455 let clock_name = format_ident!("{}", name.to_ascii_lowercase());
456 self.clock_names.insert(name.to_ascii_lowercase());
457 quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } )
458 }
451 459
452 let refcounted_peripherals = HashSet::from(["usart", "adc"]); 460 fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream {
453 let mut refcount_statics = BTreeSet::new(); 461 let ir = &self.rcc_registers.ir;
462 let fieldset_name = mux.register.to_ascii_lowercase();
463 let fieldset = ir
464 .fieldsets
465 .iter()
466 .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
467 .unwrap();
468 let field_name = mux.field.to_ascii_lowercase();
469 let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
470 let enum_name = field.enumm.unwrap();
471 let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
472
473 let fieldset_name = format_ident!("{}", fieldset_name);
474 let field_name = format_ident!("{}", field_name);
475 let enum_name = format_ident!("{}", enum_name);
476
477 self.muxes
478 .insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
479
480 let mut match_arms = TokenStream::new();
481
482 for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") {
483 let variant_name = format_ident!("{}", v.name);
484 let expr = if let Some(mux) = self.chained_muxes.get(&v.name) {
485 self.gen_mux(mux)
486 } else {
487 self.gen_clock(&v.name)
488 };
489 match_arms.extend(quote! {
490 crate::pac::rcc::vals::#enum_name::#variant_name => #expr,
491 });
492 }
493
494 quote! {
495 match crate::pac::RCC.#fieldset_name().read().#field_name() {
496 #match_arms
497 #[allow(unreachable_patterns)]
498 _ => unreachable!(),
499 }
500 }
501 }
502 }
454 503
455 for p in METADATA.peripherals { 504 for p in METADATA.peripherals {
456 if !singletons.contains(&p.name.to_string()) { 505 if !singletons.contains(&p.name.to_string()) {
@@ -483,15 +532,16 @@ fn main() {
483 532
484 let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; 533 let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
485 let pname = format_ident!("{}", p.name); 534 let pname = format_ident!("{}", p.name);
486 let clk = format_ident!("{}", rcc.clock); 535 let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
487 let en_reg = format_ident!("{}", en.register); 536 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
488 let set_en_field = format_ident!("set_{}", en.field);
489 537
490 let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) { 538 let refcount =
539 clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
540 let (before_enable, before_disable) = if refcount {
491 let refcount_static = 541 let refcount_static =
492 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); 542 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
493 543
494 refcount_statics.insert(refcount_static.clone()); 544 clock_gen.refcount_statics.insert(refcount_static.clone());
495 545
496 ( 546 (
497 quote! { 547 quote! {
@@ -511,68 +561,13 @@ fn main() {
511 (TokenStream::new(), TokenStream::new()) 561 (TokenStream::new(), TokenStream::new())
512 }; 562 };
513 563
514 let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g0", "g4", "l4"]) 564 let clock_frequency = match &rcc.kernel_clock {
515 .contains(rcc_registers.version); 565 PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux),
516 let mux_for = |mux: Option<&'static PeripheralRccRegister>| { 566 PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock),
517 // restrict mux implementation to supported versions
518 if !mux_supported {
519 return None;
520 }
521
522 let mux = mux?;
523 let fieldset = rcc_enum_map.get(mux.register)?;
524 let enumm = fieldset.get(mux.field)?;
525
526 Some((mux, *enumm))
527 }; 567 };
528 568
529 let clock_frequency = match mux_for(rcc.mux.as_ref()) { 569 // A refcount leak can result if the same field is shared by peripherals with different stop modes
530 Some((mux, rcc_enumm)) => { 570 // This condition should be checked in stm32-data
531 let fieldset_name = format_ident!("{}", mux.register);
532 let field_name = format_ident!("{}", mux.field);
533 let enum_name = format_ident!("{}", rcc_enumm.name);
534
535 let match_arms: TokenStream = rcc_enumm
536 .variants
537 .iter()
538 .filter(|v| v.name != "DISABLE")
539 .map(|v| {
540 let variant_name = format_ident!("{}", v.name);
541 let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
542
543 if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" {
544 quote! {
545 #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name },
546 }
547 } else {
548 quote! {
549 #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
550 }
551 }
552 })
553 .collect();
554
555 quote! {
556 use crate::pac::rcc::vals::#enum_name;
557
558 #[allow(unreachable_patterns)]
559 match crate::pac::RCC.#fieldset_name().read().#field_name() {
560 #match_arms
561
562 _ => unreachable!(),
563 }
564 }
565 }
566 None => quote! {
567 unsafe { crate::rcc::get_freqs().#clk }
568 },
569 };
570
571 /*
572 A refcount leak can result if the same field is shared by peripherals with different stop modes
573
574 This condition should be checked in stm32-data
575 */
576 let stop_refcount = match rcc.stop_mode { 571 let stop_refcount = match rcc.stop_mode {
577 StopMode::Standby => None, 572 StopMode::Standby => None,
578 StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }), 573 StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }),
@@ -617,7 +612,110 @@ fn main() {
617 } 612 }
618 } 613 }
619 614
620 let refcount_mod: TokenStream = refcount_statics 615 let struct_fields: Vec<_> = clock_gen
616 .muxes
617 .iter()
618 .map(|(_fieldset, fieldname, enum_name)| {
619 quote! {
620 pub #fieldname: #enum_name
621 }
622 })
623 .collect();
624
625 let mut inits = TokenStream::new();
626 for fieldset in clock_gen
627 .muxes
628 .iter()
629 .map(|(f, _, _)| f)
630 .collect::<BTreeSet<_>>()
631 .into_iter()
632 {
633 let setters: Vec<_> = clock_gen
634 .muxes
635 .iter()
636 .filter(|(f, _, _)| f == fieldset)
637 .map(|(_, fieldname, _)| {
638 let setter = format_ident!("set_{}", fieldname);
639 quote! {
640 w.#setter(self.#fieldname);
641 }
642 })
643 .collect();
644
645 inits.extend(quote! {
646 crate::pac::RCC.#fieldset().modify(|w| {
647 #(#setters)*
648 });
649 })
650 }
651
652 let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect();
653
654 g.extend(quote! {
655 pub mod mux {
656 #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
657
658 #[derive(Clone, Copy)]
659 pub struct ClockMux {
660 #( #struct_fields, )*
661 }
662
663 impl ClockMux {
664 pub(crate) const fn default() -> Self {
665 // safety: zero value is valid for all PAC enums.
666 unsafe { ::core::mem::zeroed() }
667 }
668 }
669
670 impl Default for ClockMux {
671 fn default() -> Self {
672 Self::default()
673 }
674 }
675
676 impl ClockMux {
677 pub(crate) fn init(&self) {
678 #inits
679 }
680 }
681 }
682 });
683
684 // Generate RCC
685 clock_gen.clock_names.insert("sys".to_string());
686 clock_gen.clock_names.insert("rtc".to_string());
687 let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect();
688 g.extend(quote! {
689 #[derive(Clone, Copy, Debug)]
690 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
691 pub struct Clocks {
692 #(
693 pub #clock_idents: Option<crate::time::Hertz>,
694 )*
695 }
696 });
697
698 let clocks_macro = quote!(
699 macro_rules! set_clocks {
700 ($($(#[$m:meta])* $k:ident: $v:expr,)*) => {
701 {
702 #[allow(unused)]
703 struct Temp {
704 $($(#[$m])* $k: Option<crate::time::Hertz>,)*
705 }
706 let all = Temp {
707 $($(#[$m])* $k: $v,)*
708 };
709 crate::rcc::set_freqs(crate::rcc::Clocks {
710 #( #clock_idents: all.#clock_idents, )*
711 });
712 }
713 };
714 }
715 );
716
717 let refcount_mod: TokenStream = clock_gen
718 .refcount_statics
621 .iter() 719 .iter()
622 .map(|refcount_static| { 720 .map(|refcount_static| {
623 quote! { 721 quote! {
@@ -665,7 +763,7 @@ fn main() {
665 763
666 #[rustfmt::skip] 764 #[rustfmt::skip]
667 let signals: HashMap<_, _> = [ 765 let signals: HashMap<_, _> = [
668 // (kind, signal) => trait 766 // (kind, signal) => trait
669 (("usart", "TX"), quote!(crate::usart::TxPin)), 767 (("usart", "TX"), quote!(crate::usart::TxPin)),
670 (("usart", "RX"), quote!(crate::usart::RxPin)), 768 (("usart", "RX"), quote!(crate::usart::RxPin)),
671 (("usart", "CTS"), quote!(crate::usart::CtsPin)), 769 (("usart", "CTS"), quote!(crate::usart::CtsPin)),
@@ -735,13 +833,20 @@ fn main() {
735 (("can", "TX"), quote!(crate::can::TxPin)), 833 (("can", "TX"), quote!(crate::can::TxPin)),
736 (("can", "RX"), quote!(crate::can::RxPin)), 834 (("can", "RX"), quote!(crate::can::RxPin)),
737 (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), 835 (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)),
836 (("eth", "RX_CLK"), quote!(crate::eth::RXClkPin)),
837 (("eth", "TX_CLK"), quote!(crate::eth::TXClkPin)),
738 (("eth", "MDIO"), quote!(crate::eth::MDIOPin)), 838 (("eth", "MDIO"), quote!(crate::eth::MDIOPin)),
739 (("eth", "MDC"), quote!(crate::eth::MDCPin)), 839 (("eth", "MDC"), quote!(crate::eth::MDCPin)),
740 (("eth", "CRS_DV"), quote!(crate::eth::CRSPin)), 840 (("eth", "CRS_DV"), quote!(crate::eth::CRSPin)),
841 (("eth", "RX_DV"), quote!(crate::eth::RXDVPin)),
741 (("eth", "RXD0"), quote!(crate::eth::RXD0Pin)), 842 (("eth", "RXD0"), quote!(crate::eth::RXD0Pin)),
742 (("eth", "RXD1"), quote!(crate::eth::RXD1Pin)), 843 (("eth", "RXD1"), quote!(crate::eth::RXD1Pin)),
844 (("eth", "RXD2"), quote!(crate::eth::RXD2Pin)),
845 (("eth", "RXD3"), quote!(crate::eth::RXD3Pin)),
743 (("eth", "TXD0"), quote!(crate::eth::TXD0Pin)), 846 (("eth", "TXD0"), quote!(crate::eth::TXD0Pin)),
744 (("eth", "TXD1"), quote!(crate::eth::TXD1Pin)), 847 (("eth", "TXD1"), quote!(crate::eth::TXD1Pin)),
848 (("eth", "TXD2"), quote!(crate::eth::TXD2Pin)),
849 (("eth", "TXD3"), quote!(crate::eth::TXD3Pin)),
745 (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)), 850 (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)),
746 (("fmc", "A0"), quote!(crate::fmc::A0Pin)), 851 (("fmc", "A0"), quote!(crate::fmc::A0Pin)),
747 (("fmc", "A1"), quote!(crate::fmc::A1Pin)), 852 (("fmc", "A1"), quote!(crate::fmc::A1Pin)),
@@ -905,6 +1010,7 @@ fn main() {
905 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)), 1010 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)),
906 ].into(); 1011 ].into();
907 1012
1013
908 for p in METADATA.peripherals { 1014 for p in METADATA.peripherals {
909 if let Some(regs) = &p.registers { 1015 if let Some(regs) = &p.registers {
910 for pin in p.pins { 1016 for pin in p.pins {
@@ -954,9 +1060,9 @@ fn main() {
954 } else if pin.signal.starts_with("INN") { 1060 } else if pin.signal.starts_with("INN") {
955 // TODO handle in the future when embassy supports differential measurements 1061 // TODO handle in the future when embassy supports differential measurements
956 None 1062 None
957 } else if pin.signal.starts_with("IN") && pin.signal.ends_with("b") { 1063 } else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') {
958 // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63 1064 // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63
959 let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix("b").unwrap(); 1065 let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap();
960 Some(32u8 + signal.parse::<u8>().unwrap()) 1066 Some(32u8 + signal.parse::<u8>().unwrap())
961 } else if pin.signal.starts_with("IN") { 1067 } else if pin.signal.starts_with("IN") {
962 Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap()) 1068 Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap())
@@ -965,7 +1071,7 @@ fn main() {
965 }; 1071 };
966 if let Some(ch) = ch { 1072 if let Some(ch) = ch {
967 g.extend(quote! { 1073 g.extend(quote! {
968 impl_adc_pin!( #peri, #pin_name, #ch); 1074 impl_adc_pin!( #peri, #pin_name, #ch);
969 }) 1075 })
970 } 1076 }
971 } 1077 }
@@ -997,7 +1103,7 @@ fn main() {
997 let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap(); 1103 let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap();
998 1104
999 g.extend(quote! { 1105 g.extend(quote! {
1000 impl_dac_pin!( #peri, #pin_name, #ch); 1106 impl_dac_pin!( #peri, #pin_name, #ch);
1001 }) 1107 })
1002 } 1108 }
1003 } 1109 }
@@ -1028,6 +1134,11 @@ fn main() {
1028 (("dac", "CH1"), quote!(crate::dac::DacDma1)), 1134 (("dac", "CH1"), quote!(crate::dac::DacDma1)),
1029 (("dac", "CH2"), quote!(crate::dac::DacDma2)), 1135 (("dac", "CH2"), quote!(crate::dac::DacDma2)),
1030 (("timer", "UP"), quote!(crate::timer::UpDma)), 1136 (("timer", "UP"), quote!(crate::timer::UpDma)),
1137 (("hash", "IN"), quote!(crate::hash::Dma)),
1138 (("timer", "CH1"), quote!(crate::timer::Ch1Dma)),
1139 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)),
1140 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)),
1141 (("timer", "CH4"), quote!(crate::timer::Ch4Dma)),
1031 ] 1142 ]
1032 .into(); 1143 .into();
1033 1144
@@ -1043,16 +1154,6 @@ fn main() {
1043 } 1154 }
1044 1155
1045 if let Some(tr) = signals.get(&(regs.kind, ch.signal)) { 1156 if let Some(tr) = signals.get(&(regs.kind, ch.signal)) {
1046 // TIM6 of stm32f334 is special, DMA channel for TIM6 depending on SYSCFG state
1047 if chip_name.starts_with("stm32f334") && p.name == "TIM6" {
1048 continue;
1049 }
1050
1051 // TIM6 of stm32f378 is special, DMA channel for TIM6 depending on SYSCFG state
1052 if chip_name.starts_with("stm32f378") && p.name == "TIM6" {
1053 continue;
1054 }
1055
1056 let peri = format_ident!("{}", p.name); 1157 let peri = format_ident!("{}", p.name);
1057 1158
1058 let channel = if let Some(channel) = &ch.channel { 1159 let channel = if let Some(channel) = &ch.channel {
@@ -1201,7 +1302,6 @@ fn main() {
1201 let mut interrupts_table: Vec<Vec<String>> = Vec::new(); 1302 let mut interrupts_table: Vec<Vec<String>> = Vec::new();
1202 let mut peripherals_table: Vec<Vec<String>> = Vec::new(); 1303 let mut peripherals_table: Vec<Vec<String>> = Vec::new();
1203 let mut pins_table: Vec<Vec<String>> = Vec::new(); 1304 let mut pins_table: Vec<Vec<String>> = Vec::new();
1204 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
1205 let mut adc_common_table: Vec<Vec<String>> = Vec::new(); 1305 let mut adc_common_table: Vec<Vec<String>> = Vec::new();
1206 1306
1207 /* 1307 /*
@@ -1211,7 +1311,7 @@ fn main() {
1211 ADC3 and higher are assigned to the adc34 clock in the table 1311 ADC3 and higher are assigned to the adc34 clock in the table
1212 The adc3_common cfg directive is added if ADC3_COMMON exists 1312 The adc3_common cfg directive is added if ADC3_COMMON exists
1213 */ 1313 */
1214 let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some(); 1314 let has_adc3 = METADATA.peripherals.iter().any(|p| p.name == "ADC3_COMMON");
1215 let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]); 1315 let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]);
1216 1316
1217 for m in METADATA 1317 for m in METADATA
@@ -1295,51 +1395,108 @@ fn main() {
1295 } 1395 }
1296 } 1396 }
1297 1397
1298 let mut dma_channel_count: usize = 0; 1398 let mut dmas = TokenStream::new();
1299 let mut bdma_channel_count: usize = 0; 1399 let has_dmamux = METADATA
1300 let mut gpdma_channel_count: usize = 0; 1400 .peripherals
1401 .iter()
1402 .flat_map(|p| &p.registers)
1403 .any(|p| p.kind == "dmamux");
1404
1405 for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() {
1406 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1407 if has_dmamux && ch.dmamux.is_none() {
1408 continue;
1409 }
1410
1411 let name = format_ident!("{}", ch.name);
1412 let idx = ch_idx as u8;
1413 g.extend(quote!(dma_channel_impl!(#name, #idx);));
1414
1415 let dma = format_ident!("{}", ch.dma);
1416 let ch_num = ch.channel as usize;
1301 1417
1302 for ch in METADATA.dma_channels {
1303 let mut row = Vec::new();
1304 let dma_peri = METADATA.peripherals.iter().find(|p| p.name == ch.dma).unwrap(); 1418 let dma_peri = METADATA.peripherals.iter().find(|p| p.name == ch.dma).unwrap();
1305 let bi = dma_peri.registers.as_ref().unwrap(); 1419 let bi = dma_peri.registers.as_ref().unwrap();
1306 1420
1307 let num; 1421 let dma_info = match bi.kind {
1308 match bi.kind { 1422 "dma" => quote!(crate::dma::DmaInfo::Dma(crate::pac::#dma)),
1309 "dma" => { 1423 "bdma" => quote!(crate::dma::DmaInfo::Bdma(crate::pac::#dma)),
1310 num = dma_channel_count; 1424 "gpdma" => quote!(crate::pac::#dma),
1311 dma_channel_count += 1; 1425 _ => panic!("bad dma channel kind {}", bi.kind),
1312 } 1426 };
1313 "bdma" => { 1427
1314 num = bdma_channel_count; 1428 let dmamux = match &ch.dmamux {
1315 bdma_channel_count += 1; 1429 Some(dmamux) => {
1430 let dmamux = format_ident!("{}", dmamux);
1431 let num = ch.dmamux_channel.unwrap() as usize;
1432
1433 g.extend(quote!(dmamux_channel_impl!(#name, #dmamux);));
1434
1435 quote! {
1436 dmamux: crate::dma::DmamuxInfo {
1437 mux: crate::pac::#dmamux,
1438 num: #num,
1439 },
1440 }
1316 } 1441 }
1317 "gpdma" => { 1442 None => quote!(),
1318 num = gpdma_channel_count; 1443 };
1319 gpdma_channel_count += 1; 1444
1445 dmas.extend(quote! {
1446 crate::dma::ChannelInfo {
1447 dma: #dma_info,
1448 num: #ch_num,
1449 #dmamux
1450 },
1451 });
1452 }
1453
1454 // ========
1455 // Generate DMA IRQs.
1456
1457 let mut dma_irqs: BTreeMap<&str, Vec<String>> = BTreeMap::new();
1458
1459 for p in METADATA.peripherals {
1460 if let Some(r) = &p.registers {
1461 if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" {
1462 for irq in p.interrupts {
1463 let ch_name = format!("{}_{}", p.name, irq.signal);
1464 let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap();
1465
1466 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1467 if has_dmamux && ch.dmamux.is_none() {
1468 continue;
1469 }
1470
1471 dma_irqs.entry(irq.interrupt).or_default().push(ch_name);
1472 }
1320 } 1473 }
1321 _ => panic!("bad dma channel kind {}", bi.kind),
1322 } 1474 }
1475 }
1323 1476
1324 row.push(ch.name.to_string()); 1477 let dma_irqs: TokenStream = dma_irqs
1325 row.push(ch.dma.to_string()); 1478 .iter()
1326 row.push(bi.kind.to_string()); 1479 .map(|(irq, channels)| {
1327 row.push(ch.channel.to_string()); 1480 let irq = format_ident!("{}", irq);
1328 row.push(num.to_string());
1329 if let Some(dmamux) = &ch.dmamux {
1330 let dmamux_channel = ch.dmamux_channel.unwrap();
1331 row.push(format!("{{dmamux: {}, dmamux_channel: {}}}", dmamux, dmamux_channel));
1332 } else {
1333 row.push("{}".to_string());
1334 }
1335 1481
1336 dma_channels_table.push(row); 1482 let channels = channels.iter().map(|c| format_ident!("{}", c));
1337 } 1483
1484 quote! {
1485 #[cfg(feature = "rt")]
1486 #[crate::interrupt]
1487 unsafe fn #irq () {
1488 #(
1489 <crate::peripherals::#channels as crate::dma::sealed::ChannelInterrupt>::on_irq();
1490 )*
1491 }
1492 }
1493 })
1494 .collect();
1495
1496 g.extend(dma_irqs);
1338 1497
1339 g.extend(quote! { 1498 g.extend(quote! {
1340 pub(crate) const DMA_CHANNEL_COUNT: usize = #dma_channel_count; 1499 pub(crate) const DMA_CHANNELS: &[crate::dma::ChannelInfo] = &[#dmas];
1341 pub(crate) const BDMA_CHANNEL_COUNT: usize = #bdma_channel_count;
1342 pub(crate) const GPDMA_CHANNEL_COUNT: usize = #gpdma_channel_count;
1343 }); 1500 });
1344 1501
1345 for irq in METADATA.interrupts { 1502 for irq in METADATA.interrupts {
@@ -1350,7 +1507,7 @@ fn main() {
1350 } 1507 }
1351 } 1508 }
1352 1509
1353 let mut m = String::new(); 1510 let mut m = clocks_macro.to_string();
1354 1511
1355 // DO NOT ADD more macros like these. 1512 // DO NOT ADD more macros like these.
1356 // These turned to be a bad idea! 1513 // These turned to be a bad idea!
@@ -1359,7 +1516,6 @@ fn main() {
1359 make_table(&mut m, "foreach_interrupt", &interrupts_table); 1516 make_table(&mut m, "foreach_interrupt", &interrupts_table);
1360 make_table(&mut m, "foreach_peripheral", &peripherals_table); 1517 make_table(&mut m, "foreach_peripheral", &peripherals_table);
1361 make_table(&mut m, "foreach_pin", &pins_table); 1518 make_table(&mut m, "foreach_pin", &pins_table);
1362 make_table(&mut m, "foreach_dma_channel", &dma_channels_table);
1363 make_table(&mut m, "foreach_adc", &adc_common_table); 1519 make_table(&mut m, "foreach_adc", &adc_common_table);
1364 1520
1365 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 1521 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
@@ -1395,6 +1551,7 @@ fn main() {
1395 1551
1396 // ======= 1552 // =======
1397 // ADC3_COMMON is present 1553 // ADC3_COMMON is present
1554 #[allow(clippy::print_literal)]
1398 if has_adc3 { 1555 if has_adc3 {
1399 println!("cargo:rustc-cfg={}", "adc3_common"); 1556 println!("cargo:rustc-cfg={}", "adc3_common");
1400 } 1557 }
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index fb27bb87b..b27b99827 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -6,7 +6,6 @@ use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs; 6use embedded_hal_02::blocking::delay::DelayUs;
7 7
8use crate::adc::{Adc, AdcPin, Instance, SampleTime}; 8use crate::adc::{Adc, AdcPin, Instance, SampleTime};
9use crate::rcc::get_freqs;
10use crate::time::Hertz; 9use crate::time::Hertz;
11use crate::{interrupt, Peripheral}; 10use crate::{interrupt, Peripheral};
12 11
@@ -75,24 +74,24 @@ impl<'d, T: Instance> Adc<'d, T> {
75 74
76 Self { 75 Self {
77 adc, 76 adc,
78 sample_time: Default::default(), 77 sample_time: SampleTime::from_bits(0),
79 } 78 }
80 } 79 }
81 80
82 fn freq() -> Hertz { 81 fn freq() -> Hertz {
83 unsafe { get_freqs() }.adc.unwrap() 82 T::frequency()
84 } 83 }
85 84
86 pub fn sample_time_for_us(&self, us: u32) -> SampleTime { 85 pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
87 match us * Self::freq().0 / 1_000_000 { 86 match us * Self::freq().0 / 1_000_000 {
88 0..=1 => SampleTime::Cycles1_5, 87 0..=1 => SampleTime::CYCLES1_5,
89 2..=7 => SampleTime::Cycles7_5, 88 2..=7 => SampleTime::CYCLES7_5,
90 8..=13 => SampleTime::Cycles13_5, 89 8..=13 => SampleTime::CYCLES13_5,
91 14..=28 => SampleTime::Cycles28_5, 90 14..=28 => SampleTime::CYCLES28_5,
92 29..=41 => SampleTime::Cycles41_5, 91 29..=41 => SampleTime::CYCLES41_5,
93 42..=55 => SampleTime::Cycles55_5, 92 42..=55 => SampleTime::CYCLES55_5,
94 56..=71 => SampleTime::Cycles71_5, 93 56..=71 => SampleTime::CYCLES71_5,
95 _ => SampleTime::Cycles239_5, 94 _ => SampleTime::CYCLES239_5,
96 } 95 }
97 } 96 }
98 97
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 6f59c230f..efade1f64 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -97,23 +97,23 @@ impl<'d, T: Instance> Adc<'d, T> {
97 97
98 Self { 98 Self {
99 adc, 99 adc,
100 sample_time: Default::default(), 100 sample_time: SampleTime::from_bits(0),
101 } 101 }
102 } 102 }
103 103
104 fn freq() -> Hertz { 104 fn freq() -> Hertz {
105 <T as crate::adc::sealed::Instance>::frequency() 105 <T as crate::rcc::sealed::RccPeripheral>::frequency()
106 } 106 }
107 107
108 pub fn sample_time_for_us(&self, us: u32) -> SampleTime { 108 pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
109 match us * Self::freq().0 / 1_000_000 { 109 match us * Self::freq().0 / 1_000_000 {
110 0..=1 => SampleTime::Cycles1_5, 110 0..=1 => SampleTime::CYCLES1_5,
111 2..=4 => SampleTime::Cycles4_5, 111 2..=4 => SampleTime::CYCLES4_5,
112 5..=7 => SampleTime::Cycles7_5, 112 5..=7 => SampleTime::CYCLES7_5,
113 8..=19 => SampleTime::Cycles19_5, 113 8..=19 => SampleTime::CYCLES19_5,
114 20..=61 => SampleTime::Cycles61_5, 114 20..=61 => SampleTime::CYCLES61_5,
115 62..=181 => SampleTime::Cycles181_5, 115 62..=181 => SampleTime::CYCLES181_5,
116 _ => SampleTime::Cycles601_5, 116 _ => SampleTime::CYCLES601_5,
117 } 117 }
118 } 118 }
119 119
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 6915a8f1c..f842893fa 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -107,12 +107,12 @@ impl Calibration {
107 107
108 /// Returns a calibrated voltage value as in microvolts (uV) 108 /// Returns a calibrated voltage value as in microvolts (uV)
109 pub fn cal_uv(&self, raw: u16, resolution: super::Resolution) -> u32 { 109 pub fn cal_uv(&self, raw: u16, resolution: super::Resolution) -> u32 {
110 (self.vdda_uv() / resolution.to_max_count()) * raw as u32 110 (self.vdda_uv() / super::resolution_to_max_count(resolution)) * raw as u32
111 } 111 }
112 112
113 /// Returns a calibrated voltage value as an f32 113 /// Returns a calibrated voltage value as an f32
114 pub fn cal_f32(&self, raw: u16, resolution: super::Resolution) -> f32 { 114 pub fn cal_f32(&self, raw: u16, resolution: super::Resolution) -> f32 {
115 raw as f32 * self.vdda_f32() / resolution.to_max_count() as f32 115 raw as f32 * self.vdda_f32() / super::resolution_to_max_count(resolution) as f32
116 } 116 }
117} 117}
118 118
@@ -175,12 +175,7 @@ impl<'d, T: Instance> Adc<'d, T> {
175 } 175 }
176 176
177 pub fn resolution(&self) -> Resolution { 177 pub fn resolution(&self) -> Resolution {
178 match T::regs().cr1().read().res() { 178 T::regs().cr1().read().res()
179 crate::pac::adc::vals::Res::TWELVEBIT => Resolution::TwelveBit,
180 crate::pac::adc::vals::Res::TENBIT => Resolution::TenBit,
181 crate::pac::adc::vals::Res::EIGHTBIT => Resolution::EightBit,
182 crate::pac::adc::vals::Res::SIXBIT => Resolution::SixBit,
183 }
184 } 179 }
185 180
186 pub fn enable_vref(&self) -> Vref<T> { 181 pub fn enable_vref(&self) -> Vref<T> {
@@ -359,23 +354,23 @@ impl<'d, T: Instance> Adc<'d, T> {
359 354
360 fn get_res_clks(res: Resolution) -> u32 { 355 fn get_res_clks(res: Resolution) -> u32 {
361 match res { 356 match res {
362 Resolution::TwelveBit => 12, 357 Resolution::BITS12 => 12,
363 Resolution::TenBit => 11, 358 Resolution::BITS10 => 11,
364 Resolution::EightBit => 9, 359 Resolution::BITS8 => 9,
365 Resolution::SixBit => 7, 360 Resolution::BITS6 => 7,
366 } 361 }
367 } 362 }
368 363
369 fn get_sample_time_clks(sample_time: SampleTime) -> u32 { 364 fn get_sample_time_clks(sample_time: SampleTime) -> u32 {
370 match sample_time { 365 match sample_time {
371 SampleTime::Cycles4 => 4, 366 SampleTime::CYCLES4 => 4,
372 SampleTime::Cycles9 => 9, 367 SampleTime::CYCLES9 => 9,
373 SampleTime::Cycles16 => 16, 368 SampleTime::CYCLES16 => 16,
374 SampleTime::Cycles24 => 24, 369 SampleTime::CYCLES24 => 24,
375 SampleTime::Cycles48 => 48, 370 SampleTime::CYCLES48 => 48,
376 SampleTime::Cycles96 => 96, 371 SampleTime::CYCLES96 => 96,
377 SampleTime::Cycles192 => 192, 372 SampleTime::CYCLES192 => 192,
378 SampleTime::Cycles384 => 384, 373 SampleTime::CYCLES384 => 384,
379 } 374 }
380 } 375 }
381 376
@@ -384,14 +379,14 @@ impl<'d, T: Instance> Adc<'d, T> {
384 let us_clks = us * Self::freq().0 / 1_000_000; 379 let us_clks = us * Self::freq().0 / 1_000_000;
385 let clks = us_clks.saturating_sub(res_clks); 380 let clks = us_clks.saturating_sub(res_clks);
386 match clks { 381 match clks {
387 0..=4 => SampleTime::Cycles4, 382 0..=4 => SampleTime::CYCLES4,
388 5..=9 => SampleTime::Cycles9, 383 5..=9 => SampleTime::CYCLES9,
389 10..=16 => SampleTime::Cycles16, 384 10..=16 => SampleTime::CYCLES16,
390 17..=24 => SampleTime::Cycles24, 385 17..=24 => SampleTime::CYCLES24,
391 25..=48 => SampleTime::Cycles48, 386 25..=48 => SampleTime::CYCLES48,
392 49..=96 => SampleTime::Cycles96, 387 49..=96 => SampleTime::CYCLES96,
393 97..=192 => SampleTime::Cycles192, 388 97..=192 => SampleTime::CYCLES192,
394 193.. => SampleTime::Cycles384, 389 193.. => SampleTime::CYCLES384,
395 } 390 }
396 } 391 }
397 392
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index e4dd35c34..0d0d40549 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -8,23 +8,19 @@
8#[cfg_attr(adc_f3, path = "f3.rs")] 8#[cfg_attr(adc_f3, path = "f3.rs")]
9#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] 9#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
10#[cfg_attr(adc_v1, path = "v1.rs")] 10#[cfg_attr(adc_v1, path = "v1.rs")]
11#[cfg_attr(adc_l0, path = "v1.rs")]
11#[cfg_attr(adc_v2, path = "v2.rs")] 12#[cfg_attr(adc_v2, path = "v2.rs")]
12#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] 13#[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")]
13#[cfg_attr(adc_v4, path = "v4.rs")] 14#[cfg_attr(adc_v4, path = "v4.rs")]
14mod _version; 15mod _version;
15 16
16#[cfg(not(any(adc_f1, adc_f3_v2)))]
17mod resolution;
18mod sample_time;
19
20#[allow(unused)] 17#[allow(unused)]
21#[cfg(not(adc_f3_v2))] 18#[cfg(not(adc_f3_v2))]
22pub use _version::*; 19pub use _version::*;
23#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
24pub use resolution::Resolution;
25#[cfg(not(adc_f3_v2))]
26pub use sample_time::SampleTime;
27 20
21#[cfg(not(any(adc_f1, adc_f3_v2)))]
22pub use crate::pac::adc::vals::Res as Resolution;
23pub use crate::pac::adc::vals::SampleTime;
28use crate::peripherals; 24use crate::peripherals;
29 25
30/// Analog to Digital driver. 26/// Analog to Digital driver.
@@ -36,15 +32,15 @@ pub struct Adc<'d, T: Instance> {
36} 32}
37 33
38pub(crate) mod sealed { 34pub(crate) mod sealed {
39 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 35 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
40 use embassy_sync::waitqueue::AtomicWaker; 36 use embassy_sync::waitqueue::AtomicWaker;
41 37
42 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 38 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
43 pub struct State { 39 pub struct State {
44 pub waker: AtomicWaker, 40 pub waker: AtomicWaker,
45 } 41 }
46 42
47 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 43 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
48 impl State { 44 impl State {
49 pub const fn new() -> Self { 45 pub const fn new() -> Self {
50 Self { 46 Self {
@@ -59,16 +55,14 @@ pub(crate) mod sealed {
59 55
60 pub trait Instance: InterruptableInstance { 56 pub trait Instance: InterruptableInstance {
61 fn regs() -> crate::pac::adc::Adc; 57 fn regs() -> crate::pac::adc::Adc;
62 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 58 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
63 fn common_regs() -> crate::pac::adccommon::AdcCommon; 59 fn common_regs() -> crate::pac::adccommon::AdcCommon;
64 #[cfg(adc_f3)] 60 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
65 fn frequency() -> crate::time::Hertz;
66 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
67 fn state() -> &'static State; 61 fn state() -> &'static State;
68 } 62 }
69 63
70 pub trait AdcPin<T: Instance> { 64 pub trait AdcPin<T: Instance> {
71 #[cfg(any(adc_v1, adc_v2))] 65 #[cfg(any(adc_v1, adc_l0, adc_v2))]
72 fn set_as_analog(&mut self) {} 66 fn set_as_analog(&mut self) {}
73 67
74 fn channel(&self) -> u8; 68 fn channel(&self) -> u8;
@@ -80,10 +74,10 @@ pub(crate) mod sealed {
80} 74}
81 75
82/// ADC instance. 76/// ADC instance.
83#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] 77#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))]
84pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 78pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
85/// ADC instance. 79/// ADC instance.
86#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] 80#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))]
87pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 81pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
88 82
89/// ADC pin. 83/// ADC pin.
@@ -98,17 +92,12 @@ foreach_adc!(
98 crate::pac::$inst 92 crate::pac::$inst
99 } 93 }
100 94
101 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 95 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
102 fn common_regs() -> crate::pac::adccommon::AdcCommon { 96 fn common_regs() -> crate::pac::adccommon::AdcCommon {
103 return crate::pac::$common_inst 97 return crate::pac::$common_inst
104 } 98 }
105 99
106 #[cfg(adc_f3)] 100 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
107 fn frequency() -> crate::time::Hertz {
108 unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
109 }
110
111 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
112 fn state() -> &'static sealed::State { 101 fn state() -> &'static sealed::State {
113 static STATE: sealed::State = sealed::State::new(); 102 static STATE: sealed::State = sealed::State::new();
114 &STATE 103 &STATE
@@ -132,7 +121,7 @@ macro_rules! impl_adc_pin {
132 impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} 121 impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
133 122
134 impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { 123 impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
135 #[cfg(any(adc_v1, adc_v2))] 124 #[cfg(any(adc_v1, adc_l0, adc_v2))]
136 fn set_as_analog(&mut self) { 125 fn set_as_analog(&mut self) {
137 <Self as crate::gpio::sealed::Pin>::set_as_analog(self); 126 <Self as crate::gpio::sealed::Pin>::set_as_analog(self);
138 } 127 }
@@ -143,3 +132,27 @@ macro_rules! impl_adc_pin {
143 } 132 }
144 }; 133 };
145} 134}
135
136/// Get the maximum reading value for this resolution.
137///
138/// This is `2**n - 1`.
139#[cfg(not(any(adc_f1, adc_f3_v2)))]
140pub const fn resolution_to_max_count(res: Resolution) -> u32 {
141 match res {
142 #[cfg(adc_v4)]
143 Resolution::BITS16 => (1 << 16) - 1,
144 #[cfg(adc_v4)]
145 Resolution::BITS14 => (1 << 14) - 1,
146 #[cfg(adc_v4)]
147 Resolution::BITS14V => (1 << 14) - 1,
148 #[cfg(adc_v4)]
149 Resolution::BITS12V => (1 << 12) - 1,
150 Resolution::BITS12 => (1 << 12) - 1,
151 Resolution::BITS10 => (1 << 10) - 1,
152 Resolution::BITS8 => (1 << 8) - 1,
153 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))]
154 Resolution::BITS6 => (1 << 6) - 1,
155 #[allow(unreachable_patterns)]
156 _ => core::unreachable!(),
157 }
158}
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
deleted file mode 100644
index 64c25a776..000000000
--- a/embassy-stm32/src/adc/resolution.rs
+++ /dev/null
@@ -1,72 +0,0 @@
1/// ADC resolution
2#[allow(missing_docs)]
3#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub enum Resolution {
7 TwelveBit,
8 TenBit,
9 EightBit,
10 SixBit,
11}
12
13/// ADC resolution
14#[allow(missing_docs)]
15#[cfg(adc_v4)]
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Resolution {
19 SixteenBit,
20 FourteenBit,
21 TwelveBit,
22 TenBit,
23 EightBit,
24}
25
26impl Default for Resolution {
27 fn default() -> Self {
28 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
29 {
30 Self::TwelveBit
31 }
32 #[cfg(adc_v4)]
33 {
34 Self::SixteenBit
35 }
36 }
37}
38
39impl From<Resolution> for crate::pac::adc::vals::Res {
40 fn from(res: Resolution) -> crate::pac::adc::vals::Res {
41 match res {
42 #[cfg(adc_v4)]
43 Resolution::SixteenBit => crate::pac::adc::vals::Res::SIXTEENBIT,
44 #[cfg(adc_v4)]
45 Resolution::FourteenBit => crate::pac::adc::vals::Res::FOURTEENBITV,
46 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
47 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
48 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
49 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
50 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
51 }
52 }
53}
54
55impl Resolution {
56 /// Get the maximum reading value for this resolution.
57 ///
58 /// This is `2**n - 1`.
59 pub fn to_max_count(&self) -> u32 {
60 match self {
61 #[cfg(adc_v4)]
62 Resolution::SixteenBit => (1 << 16) - 1,
63 #[cfg(adc_v4)]
64 Resolution::FourteenBit => (1 << 14) - 1,
65 Resolution::TwelveBit => (1 << 12) - 1,
66 Resolution::TenBit => (1 << 10) - 1,
67 Resolution::EightBit => (1 << 8) - 1,
68 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
69 Resolution::SixBit => (1 << 6) - 1,
70 }
71 }
72}
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
deleted file mode 100644
index 5a06f1a5a..000000000
--- a/embassy-stm32/src/adc/sample_time.rs
+++ /dev/null
@@ -1,148 +0,0 @@
1#[cfg(not(adc_f3_v2))]
2macro_rules! impl_sample_time {
3 ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
4 #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
5 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
6 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
7 pub enum SampleTime {
8 $(
9 #[doc = concat!($doc, " ADC clock cycles.")]
10 $variant,
11 )*
12 }
13
14 impl From<SampleTime> for crate::pac::adc::vals::SampleTime {
15 fn from(sample_time: SampleTime) -> crate::pac::adc::vals::SampleTime {
16 match sample_time {
17 $(SampleTime::$variant => crate::pac::adc::vals::SampleTime::$pac_variant),*
18 }
19 }
20 }
21
22 impl From<crate::pac::adc::vals::SampleTime> for SampleTime {
23 fn from(sample_time: crate::pac::adc::vals::SampleTime) -> SampleTime {
24 match sample_time {
25 $(crate::pac::adc::vals::SampleTime::$pac_variant => SampleTime::$variant),*
26 }
27 }
28 }
29
30 impl Default for SampleTime {
31 fn default() -> Self {
32 Self::$default
33 }
34 }
35 };
36}
37
38#[cfg(any(adc_f1, adc_v1))]
39impl_sample_time!(
40 "1.5",
41 Cycles1_5,
42 (
43 ("1.5", Cycles1_5, CYCLES1_5),
44 ("7.5", Cycles7_5, CYCLES7_5),
45 ("13.5", Cycles13_5, CYCLES13_5),
46 ("28.5", Cycles28_5, CYCLES28_5),
47 ("41.5", Cycles41_5, CYCLES41_5),
48 ("55.5", Cycles55_5, CYCLES55_5),
49 ("71.5", Cycles71_5, CYCLES71_5),
50 ("239.5", Cycles239_5, CYCLES239_5)
51 )
52);
53
54#[cfg(adc_v2)]
55impl_sample_time!(
56 "3",
57 Cycles3,
58 (
59 ("3", Cycles3, CYCLES3),
60 ("15", Cycles15, CYCLES15),
61 ("28", Cycles28, CYCLES28),
62 ("56", Cycles56, CYCLES56),
63 ("84", Cycles84, CYCLES84),
64 ("112", Cycles112, CYCLES112),
65 ("144", Cycles144, CYCLES144),
66 ("480", Cycles480, CYCLES480)
67 )
68);
69
70#[cfg(adc_v3)]
71impl_sample_time!(
72 "2.5",
73 Cycles2_5,
74 (
75 ("2.5", Cycles2_5, CYCLES2_5),
76 ("6.5", Cycles6_5, CYCLES6_5),
77 ("12.5", Cycles12_5, CYCLES12_5),
78 ("24.5", Cycles24_5, CYCLES24_5),
79 ("47.5", Cycles47_5, CYCLES47_5),
80 ("92.5", Cycles92_5, CYCLES92_5),
81 ("247.5", Cycles247_5, CYCLES247_5),
82 ("640.5", Cycles640_5, CYCLES640_5)
83 )
84);
85
86#[cfg(adc_g0)]
87impl_sample_time!(
88 "1.5",
89 Cycles1_5,
90 (
91 ("1.5", Cycles1_5, CYCLES1_5),
92 ("3.5", Cycles3_5, CYCLES3_5),
93 ("7.5", Cycles7_5, CYCLES7_5),
94 ("12.5", Cycles12_5, CYCLES12_5),
95 ("19.5", Cycles19_5, CYCLES19_5),
96 ("39.5", Cycles39_5, CYCLES39_5),
97 ("79.5", Cycles79_5, CYCLES79_5),
98 ("160.5", Cycles160_5, CYCLES160_5)
99 )
100);
101
102#[cfg(adc_v4)]
103impl_sample_time!(
104 "1.5",
105 Cycles1_5,
106 (
107 ("1.5", Cycles1_5, CYCLES1_5),
108 ("2.5", Cycles2_5, CYCLES2_5),
109 ("8.5", Cycles8_5, CYCLES8_5),
110 ("16.5", Cycles16_5, CYCLES16_5),
111 ("32.5", Cycles32_5, CYCLES32_5),
112 ("64.5", Cycles64_5, CYCLES64_5),
113 ("387.5", Cycles387_5, CYCLES387_5),
114 ("810.5", Cycles810_5, CYCLES810_5)
115 )
116);
117
118#[cfg(adc_f3)]
119impl_sample_time!(
120 "1.5",
121 Cycles1_5,
122 (
123 ("1.5", Cycles1_5, CYCLES1_5),
124 ("2.5", Cycles2_5, CYCLES2_5),
125 ("4.5", Cycles4_5, CYCLES4_5),
126 ("7.5", Cycles7_5, CYCLES7_5),
127 ("19.5", Cycles19_5, CYCLES19_5),
128 ("61.5", Cycles61_5, CYCLES61_5),
129 ("181.5", Cycles181_5, CYCLES181_5),
130 ("601.5", Cycles601_5, CYCLES601_5)
131 )
132);
133
134#[cfg(any(adc_f3_v1_1))]
135impl_sample_time!(
136 "4",
137 Cycles4,
138 (
139 ("4", Cycles4, CYCLES4),
140 ("9", Cycles9, CYCLES9),
141 ("16", Cycles16, CYCLES16),
142 ("24", Cycles24, CYCLES24),
143 ("48", Cycles48, CYCLES48),
144 ("96", Cycles96, CYCLES96),
145 ("192", Cycles192, CYCLES192),
146 ("384", Cycles384, CYCLES384)
147 )
148);
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 852b027df..a8dc6ce98 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -4,6 +4,8 @@ use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs; 6use embedded_hal_02::blocking::delay::DelayUs;
7#[cfg(adc_l0)]
8use stm32_metapac::adc::vals::Ckmode;
7 9
8use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 10use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
9use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
@@ -30,8 +32,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
30 } 32 }
31} 33}
32 34
35#[cfg(not(adc_l0))]
33pub struct Vbat; 36pub struct Vbat;
37
38#[cfg(not(adc_l0))]
34impl AdcPin<ADC> for Vbat {} 39impl AdcPin<ADC> for Vbat {}
40
41#[cfg(not(adc_l0))]
35impl super::sealed::AdcPin<ADC> for Vbat { 42impl super::sealed::AdcPin<ADC> for Vbat {
36 fn channel(&self) -> u8 { 43 fn channel(&self) -> u8 {
37 18 44 18
@@ -69,9 +76,18 @@ impl<'d, T: Instance> Adc<'d, T> {
69 // tstab = 14 * 1/fadc 76 // tstab = 14 * 1/fadc
70 delay.delay_us(1); 77 delay.delay_us(1);
71 78
79 // set default PCKL/2 on L0s because HSI is disabled in the default clock config
80 #[cfg(adc_l0)]
81 T::regs().cfgr2().modify(|reg| reg.set_ckmode(Ckmode::PCLK_DIV2));
82
72 // A.7.1 ADC calibration code example 83 // A.7.1 ADC calibration code example
73 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); 84 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
74 T::regs().cr().modify(|reg| reg.set_adcal(true)); 85 T::regs().cr().modify(|reg| reg.set_adcal(true));
86
87 #[cfg(adc_l0)]
88 while !T::regs().isr().read().eocal() {}
89
90 #[cfg(not(adc_l0))]
75 while T::regs().cr().read().adcal() {} 91 while T::regs().cr().read().adcal() {}
76 92
77 // A.7.2 ADC enable sequence code example 93 // A.7.2 ADC enable sequence code example
@@ -93,10 +109,11 @@ impl<'d, T: Instance> Adc<'d, T> {
93 109
94 Self { 110 Self {
95 adc, 111 adc,
96 sample_time: Default::default(), 112 sample_time: SampleTime::from_bits(0),
97 } 113 }
98 } 114 }
99 115
116 #[cfg(not(adc_l0))]
100 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { 117 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
101 // SMP must be ≥ 56 ADC clock cycles when using HSI14. 118 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
102 // 119 //
@@ -133,6 +150,12 @@ impl<'d, T: Instance> Adc<'d, T> {
133 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 150 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
134 } 151 }
135 152
153 #[cfg(adc_l0)]
154 pub fn set_ckmode(&mut self, ckmode: Ckmode) {
155 // set ADC clock mode
156 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
157 }
158
136 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 159 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
137 let channel = pin.channel(); 160 let channel = pin.channel();
138 pin.set_as_analog(); 161 pin.set_as_analog();
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 4622b40a9..f6f7dbfcc 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -34,7 +34,7 @@ impl AdcPin<ADC1> for Temperature {}
34impl super::sealed::AdcPin<ADC1> for Temperature { 34impl super::sealed::AdcPin<ADC1> for Temperature {
35 fn channel(&self) -> u8 { 35 fn channel(&self) -> u8 {
36 cfg_if::cfg_if! { 36 cfg_if::cfg_if! {
37 if #[cfg(any(stm32f40, stm32f41))] { 37 if #[cfg(any(stm32f2, stm32f40, stm32f41))] {
38 16 38 16
39 } else { 39 } else {
40 18 40 18
@@ -67,7 +67,11 @@ enum Prescaler {
67 67
68impl Prescaler { 68impl Prescaler {
69 fn from_pclk2(freq: Hertz) -> Self { 69 fn from_pclk2(freq: Hertz) -> Self {
70 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
71 #[cfg(stm32f2)]
72 const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
70 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. 73 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
74 #[cfg(not(stm32f2))]
71 const MAX_FREQUENCY: Hertz = Hertz(36_000_000); 75 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
72 let raw_div = freq.0 / MAX_FREQUENCY.0; 76 let raw_div = freq.0 / MAX_FREQUENCY.0;
73 match raw_div { 77 match raw_div {
@@ -107,7 +111,7 @@ where
107 111
108 Self { 112 Self {
109 adc, 113 adc,
110 sample_time: Default::default(), 114 sample_time: SampleTime::from_bits(0),
111 } 115 }
112 } 116 }
113 117
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 281a99f72..5f3512cad 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,3 +1,4 @@
1use cfg_if::cfg_if;
1use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs; 3use embedded_hal_02::blocking::delay::DelayUs;
3 4
@@ -13,10 +14,15 @@ pub struct VrefInt;
13impl<T: Instance> AdcPin<T> for VrefInt {} 14impl<T: Instance> AdcPin<T> for VrefInt {}
14impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { 15impl<T: Instance> super::sealed::AdcPin<T> for VrefInt {
15 fn channel(&self) -> u8 { 16 fn channel(&self) -> u8 {
16 #[cfg(not(adc_g0))] 17 cfg_if! {
17 let val = 0; 18 if #[cfg(adc_g0)] {
18 #[cfg(adc_g0)] 19 let val = 13;
19 let val = 13; 20 } else if #[cfg(adc_h5)] {
21 let val = 17;
22 } else {
23 let val = 0;
24 }
25 }
20 val 26 val
21 } 27 }
22} 28}
@@ -25,10 +31,15 @@ pub struct Temperature;
25impl<T: Instance> AdcPin<T> for Temperature {} 31impl<T: Instance> AdcPin<T> for Temperature {}
26impl<T: Instance> super::sealed::AdcPin<T> for Temperature { 32impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
27 fn channel(&self) -> u8 { 33 fn channel(&self) -> u8 {
28 #[cfg(not(adc_g0))] 34 cfg_if! {
29 let val = 17; 35 if #[cfg(adc_g0)] {
30 #[cfg(adc_g0)] 36 let val = 12;
31 let val = 12; 37 } else if #[cfg(adc_h5)] {
38 let val = 16;
39 } else {
40 let val = 17;
41 }
42 }
32 val 43 val
33 } 44 }
34} 45}
@@ -37,14 +48,31 @@ pub struct Vbat;
37impl<T: Instance> AdcPin<T> for Vbat {} 48impl<T: Instance> AdcPin<T> for Vbat {}
38impl<T: Instance> super::sealed::AdcPin<T> for Vbat { 49impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
39 fn channel(&self) -> u8 { 50 fn channel(&self) -> u8 {
40 #[cfg(not(adc_g0))] 51 cfg_if! {
41 let val = 18; 52 if #[cfg(adc_g0)] {
42 #[cfg(adc_g0)] 53 let val = 14;
43 let val = 14; 54 } else if #[cfg(adc_h5)] {
55 let val = 2;
56 } else {
57 let val = 18;
58 }
59 }
44 val 60 val
45 } 61 }
46} 62}
47 63
64cfg_if! {
65 if #[cfg(adc_h5)] {
66 pub struct VddCore;
67 impl<T: Instance> AdcPin<T> for VddCore {}
68 impl<T: Instance> super::sealed::AdcPin<T> for VddCore {
69 fn channel(&self) -> u8 {
70 6
71 }
72 }
73 }
74}
75
48impl<'d, T: Instance> Adc<'d, T> { 76impl<'d, T: Instance> Adc<'d, T> {
49 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { 77 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
50 into_ref!(adc); 78 into_ref!(adc);
@@ -74,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> {
74 102
75 Self { 103 Self {
76 adc, 104 adc,
77 sample_time: Default::default(), 105 sample_time: SampleTime::from_bits(0),
78 } 106 }
79 } 107 }
80 108
@@ -98,27 +126,41 @@ impl<'d, T: Instance> Adc<'d, T> {
98 } 126 }
99 127
100 pub fn enable_temperature(&self) -> Temperature { 128 pub fn enable_temperature(&self) -> Temperature {
101 #[cfg(not(adc_g0))] 129 cfg_if! {
102 T::common_regs().ccr().modify(|reg| { 130 if #[cfg(adc_g0)] {
103 reg.set_ch17sel(true); 131 T::regs().ccr().modify(|reg| {
104 }); 132 reg.set_tsen(true);
105 #[cfg(adc_g0)] 133 });
106 T::regs().ccr().modify(|reg| { 134 } else if #[cfg(adc_h5)] {
107 reg.set_tsen(true); 135 T::common_regs().ccr().modify(|reg| {
108 }); 136 reg.set_tsen(true);
137 });
138 } else {
139 T::common_regs().ccr().modify(|reg| {
140 reg.set_ch17sel(true);
141 });
142 }
143 }
109 144
110 Temperature {} 145 Temperature {}
111 } 146 }
112 147
113 pub fn enable_vbat(&self) -> Vbat { 148 pub fn enable_vbat(&self) -> Vbat {
114 #[cfg(not(adc_g0))] 149 cfg_if! {
115 T::common_regs().ccr().modify(|reg| { 150 if #[cfg(adc_g0)] {
116 reg.set_ch18sel(true); 151 T::regs().ccr().modify(|reg| {
117 }); 152 reg.set_vbaten(true);
118 #[cfg(adc_g0)] 153 });
119 T::regs().ccr().modify(|reg| { 154 } else if #[cfg(adc_h5)] {
120 reg.set_vbaten(true); 155 T::common_regs().ccr().modify(|reg| {
121 }); 156 reg.set_vbaten(true);
157 });
158 } else {
159 T::common_regs().ccr().modify(|reg| {
160 reg.set_ch18sel(true);
161 });
162 }
163 }
122 164
123 Vbat {} 165 Vbat {}
124 } 166 }
@@ -205,16 +247,21 @@ impl<'d, T: Instance> Adc<'d, T> {
205 val 247 val
206 } 248 }
207 249
208 #[cfg(adc_g0)]
209 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 250 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
210 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 251 cfg_if! {
211 } 252 if #[cfg(adc_g0)] {
212 253 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
213 #[cfg(not(adc_g0))] 254 } else if #[cfg(adc_h5)] {
214 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 255 match _ch {
215 let sample_time = sample_time.into(); 256 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())),
216 T::regs() 257 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())),
217 .smpr(ch as usize / 10) 258 }
218 .modify(|reg| reg.set_smp(ch as usize % 10, sample_time)); 259 } else {
260 let sample_time = sample_time.into();
261 T::regs()
262 .smpr(_ch as usize / 10)
263 .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time));
264 }
265 }
219 } 266 }
220} 267}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 048e73184..3fd047375 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -159,7 +159,7 @@ impl<'d, T: Instance> Adc<'d, T> {
159 } 159 }
160 let mut s = Self { 160 let mut s = Self {
161 adc, 161 adc,
162 sample_time: Default::default(), 162 sample_time: SampleTime::from_bits(0),
163 }; 163 };
164 s.power_up(delay); 164 s.power_up(delay);
165 s.configure_differential_inputs(); 165 s.configure_differential_inputs();
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index cc87b2565..7e00eca6f 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -13,9 +13,12 @@ use crate::gpio::sealed::AFType;
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::can::vals::{Ide, Lec}; 14use crate::pac::can::vals::{Ide, Lec};
15use crate::rcc::RccPeripheral; 15use crate::rcc::RccPeripheral;
16use crate::time::Hertz;
17use crate::{interrupt, peripherals, Peripheral}; 16use crate::{interrupt, peripherals, Peripheral};
18 17
18pub mod enums;
19use enums::*;
20pub mod util;
21
19/// Contains CAN frame and additional metadata. 22/// Contains CAN frame and additional metadata.
20/// 23///
21/// Timestamp is available if `time` feature is enabled. 24/// Timestamp is available if `time` feature is enabled.
@@ -93,23 +96,6 @@ pub struct Can<'d, T: Instance> {
93 can: bxcan::Can<BxcanInstance<'d, T>>, 96 can: bxcan::Can<BxcanInstance<'d, T>>,
94} 97}
95 98
96/// CAN bus error
97#[allow(missing_docs)]
98#[derive(Debug)]
99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
100pub enum BusError {
101 Stuff,
102 Form,
103 Acknowledge,
104 BitRecessive,
105 BitDominant,
106 Crc,
107 Software,
108 BusOff,
109 BusPassive,
110 BusWarning,
111}
112
113/// Error returned by `try_read` 99/// Error returned by `try_read`
114#[derive(Debug)] 100#[derive(Debug)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))] 101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -186,8 +172,15 @@ impl<'d, T: Instance> Can<'d, T> {
186 172
187 /// Set CAN bit rate. 173 /// Set CAN bit rate.
188 pub fn set_bitrate(&mut self, bitrate: u32) { 174 pub fn set_bitrate(&mut self, bitrate: u32) {
189 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); 175 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
190 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); 176 let sjw = u8::from(bit_timing.sync_jump_width) as u32;
177 let seg1 = u8::from(bit_timing.seg1) as u32;
178 let seg2 = u8::from(bit_timing.seg2) as u32;
179 let prescaler = u16::from(bit_timing.prescaler) as u32;
180 self.can
181 .modify_config()
182 .set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1))
183 .leave_disabled();
191 } 184 }
192 185
193 /// Enables the peripheral and synchronizes with the bus. 186 /// Enables the peripheral and synchronizes with the bus.
@@ -302,97 +295,6 @@ impl<'d, T: Instance> Can<'d, T> {
302 } 295 }
303 } 296 }
304 297
305 const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
306 const BS1_MAX: u8 = 16;
307 const BS2_MAX: u8 = 8;
308 const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
309
310 let periph_clock = periph_clock.0;
311
312 if can_bitrate < 1000 {
313 return None;
314 }
315
316 // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
317 // CAN in Automation, 2003
318 //
319 // According to the source, optimal quanta per bit are:
320 // Bitrate Optimal Maximum
321 // 1000 kbps 8 10
322 // 500 kbps 16 17
323 // 250 kbps 16 17
324 // 125 kbps 16 17
325 let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
326
327 // Computing (prescaler * BS):
328 // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
329 // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
330 // let:
331 // BS = 1 + BS1 + BS2 -- Number of time quanta per bit
332 // PRESCALER_BS = PRESCALER * BS
333 // ==>
334 // PRESCALER_BS = PCLK / BITRATE
335 let prescaler_bs = periph_clock / can_bitrate;
336
337 // Searching for such prescaler value so that the number of quanta per bit is highest.
338 let mut bs1_bs2_sum = max_quanta_per_bit - 1;
339 while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
340 if bs1_bs2_sum <= 2 {
341 return None; // No solution
342 }
343 bs1_bs2_sum -= 1;
344 }
345
346 let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
347 if (prescaler < 1) || (prescaler > 1024) {
348 return None; // No solution
349 }
350
351 // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
352 // We need to find such values so that the sample point is as close as possible to the optimal value,
353 // which is 87.5%, which is 7/8.
354 //
355 // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
356 // {{bs2 -> (1 + bs1)/7}}
357 //
358 // Hence:
359 // bs2 = (1 + bs1) / 7
360 // bs1 = (7 * bs1_bs2_sum - 1) / 8
361 //
362 // Sample point location can be computed as follows:
363 // Sample point location = (1 + bs1) / (1 + bs1 + bs2)
364 //
365 // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
366 // - With rounding to nearest
367 // - With rounding to zero
368 let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
369 let mut bs2 = bs1_bs2_sum - bs1;
370 core::assert!(bs1_bs2_sum > bs1);
371
372 let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
373 if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
374 // Nope, too far; now rounding to zero
375 bs1 = (7 * bs1_bs2_sum - 1) / 8;
376 bs2 = bs1_bs2_sum - bs1;
377 }
378
379 // Check is BS1 and BS2 are in range
380 if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
381 return None;
382 }
383
384 // Check if final bitrate matches the requested
385 if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
386 return None;
387 }
388
389 // One is recommended by DS-015, CANOpen, and DeviceNet
390 let sjw = 1;
391
392 // Pack into BTR register values
393 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1))
394 }
395
396 /// Split the CAN driver into transmit and receive halves. 298 /// Split the CAN driver into transmit and receive halves.
397 /// 299 ///
398 /// Useful for doing separate transmit/receive tasks. 300 /// Useful for doing separate transmit/receive tasks.
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs
new file mode 100644
index 000000000..36139a45c
--- /dev/null
+++ b/embassy-stm32/src/can/enums.rs
@@ -0,0 +1,30 @@
1//! Enums shared between CAN controller types.
2
3/// Bus error
4#[derive(Debug)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub enum BusError {
7 /// Bit stuffing error - more than 5 equal bits
8 Stuff,
9 /// Form error - A fixed format part of a received message has wrong format
10 Form,
11 /// The message transmitted by the FDCAN was not acknowledged by another node.
12 Acknowledge,
13 /// Bit0Error: During the transmission of a message the device wanted to send a dominant level
14 /// but the monitored bus value was recessive.
15 BitRecessive,
16 /// Bit1Error: During the transmission of a message the device wanted to send a recessive level
17 /// but the monitored bus value was dominant.
18 BitDominant,
19 /// The CRC check sum of a received message was incorrect. The CRC of an
20 /// incoming message does not match with the CRC calculated from the received data.
21 Crc,
22 /// A software error occured
23 Software,
24 /// The FDCAN is in Bus_Off state.
25 BusOff,
26 /// The FDCAN is in the Error_Passive state.
27 BusPassive,
28 /// At least one of error counter has reached the Error_Warning limit of 96.
29 BusWarning,
30}
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
new file mode 100644
index 000000000..68161ca50
--- /dev/null
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -0,0 +1,475 @@
1//! Configuration for FDCAN Module
2// Note: This file is copied and modified from fdcan crate by Richard Meadows
3
4use core::num::{NonZeroU16, NonZeroU8};
5
6/// Configures the bit timings.
7///
8/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
9/// parameters as follows:
10///
11/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
12/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
13/// - *Sample Point*: Should normally be left at the default value of 87.5%.
14/// - *SJW*: Should normally be left at the default value of 1.
15///
16/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
17/// parameter to this method.
18#[derive(Clone, Copy, Debug)]
19pub struct NominalBitTiming {
20 /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
21 /// time is built up from a multiple of this quanta. Valid values are 1 to 512.
22 pub prescaler: NonZeroU16,
23 /// Valid values are 1 to 128.
24 pub seg1: NonZeroU8,
25 /// Valid values are 1 to 255.
26 pub seg2: NonZeroU8,
27 /// Valid values are 1 to 128.
28 pub sync_jump_width: NonZeroU8,
29}
30impl NominalBitTiming {
31 #[inline]
32 pub(crate) fn nbrp(&self) -> u16 {
33 u16::from(self.prescaler) & 0x1FF
34 }
35 #[inline]
36 pub(crate) fn ntseg1(&self) -> u8 {
37 u8::from(self.seg1)
38 }
39 #[inline]
40 pub(crate) fn ntseg2(&self) -> u8 {
41 u8::from(self.seg2) & 0x7F
42 }
43 #[inline]
44 pub(crate) fn nsjw(&self) -> u8 {
45 u8::from(self.sync_jump_width) & 0x7F
46 }
47}
48
49impl Default for NominalBitTiming {
50 #[inline]
51 fn default() -> Self {
52 // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a NBTP
53 // register value of 0x0600_0A03
54 Self {
55 prescaler: NonZeroU16::new(1).unwrap(),
56 seg1: NonZeroU8::new(11).unwrap(),
57 seg2: NonZeroU8::new(4).unwrap(),
58 sync_jump_width: NonZeroU8::new(4).unwrap(),
59 }
60 }
61}
62
63/// Configures the data bit timings for the FdCan Variable Bitrates.
64/// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
65#[derive(Clone, Copy, Debug)]
66pub struct DataBitTiming {
67 /// Tranceiver Delay Compensation
68 pub transceiver_delay_compensation: bool,
69 /// The value by which the oscillator frequency is divided to generate the bit time quanta. The bit
70 /// time is built up from a multiple of this quanta. Valid values for the Baud Rate Prescaler are 1
71 /// to 31.
72 pub prescaler: NonZeroU16,
73 /// Valid values are 1 to 31.
74 pub seg1: NonZeroU8,
75 /// Valid values are 1 to 15.
76 pub seg2: NonZeroU8,
77 /// Must always be smaller than DTSEG2, valid values are 1 to 15.
78 pub sync_jump_width: NonZeroU8,
79}
80impl DataBitTiming {
81 // #[inline]
82 // fn tdc(&self) -> u8 {
83 // let tsd = self.transceiver_delay_compensation as u8;
84 // //TODO: stm32g4 does not export the TDC field
85 // todo!()
86 // }
87 #[inline]
88 pub(crate) fn dbrp(&self) -> u8 {
89 (u16::from(self.prescaler) & 0x001F) as u8
90 }
91 #[inline]
92 pub(crate) fn dtseg1(&self) -> u8 {
93 u8::from(self.seg1) & 0x1F
94 }
95 #[inline]
96 pub(crate) fn dtseg2(&self) -> u8 {
97 u8::from(self.seg2) & 0x0F
98 }
99 #[inline]
100 pub(crate) fn dsjw(&self) -> u8 {
101 u8::from(self.sync_jump_width) & 0x0F
102 }
103}
104
105impl Default for DataBitTiming {
106 #[inline]
107 fn default() -> Self {
108 // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a DBTP
109 // register value of 0x0000_0A33
110 Self {
111 transceiver_delay_compensation: false,
112 prescaler: NonZeroU16::new(1).unwrap(),
113 seg1: NonZeroU8::new(11).unwrap(),
114 seg2: NonZeroU8::new(4).unwrap(),
115 sync_jump_width: NonZeroU8::new(4).unwrap(),
116 }
117 }
118}
119
120/// Configures which modes to use
121/// Individual headers can contain a desire to be send via FdCan
122/// or use Bit rate switching. But if this general setting does not allow
123/// that, only classic CAN is used instead.
124#[derive(Clone, Copy, Debug)]
125pub enum FrameTransmissionConfig {
126 /// Only allow Classic CAN message Frames
127 ClassicCanOnly,
128 /// Allow (non-brs) FdCAN Message Frames
129 AllowFdCan,
130 /// Allow FdCAN Message Frames and allow Bit Rate Switching
131 AllowFdCanAndBRS,
132}
133
134///
135#[derive(Clone, Copy, Debug)]
136pub enum ClockDivider {
137 /// Divide by 1
138 _1 = 0b0000,
139 /// Divide by 2
140 _2 = 0b0001,
141 /// Divide by 4
142 _4 = 0b0010,
143 /// Divide by 6
144 _6 = 0b0011,
145 /// Divide by 8
146 _8 = 0b0100,
147 /// Divide by 10
148 _10 = 0b0101,
149 /// Divide by 12
150 _12 = 0b0110,
151 /// Divide by 14
152 _14 = 0b0111,
153 /// Divide by 16
154 _16 = 0b1000,
155 /// Divide by 18
156 _18 = 0b1001,
157 /// Divide by 20
158 _20 = 0b1010,
159 /// Divide by 22
160 _22 = 0b1011,
161 /// Divide by 24
162 _24 = 0b1100,
163 /// Divide by 26
164 _26 = 0b1101,
165 /// Divide by 28
166 _28 = 0b1110,
167 /// Divide by 30
168 _30 = 0b1111,
169}
170
171/// Prescaler of the Timestamp counter
172#[derive(Clone, Copy, Debug)]
173pub enum TimestampPrescaler {
174 /// 1
175 _1 = 1,
176 /// 2
177 _2 = 2,
178 /// 3
179 _3 = 3,
180 /// 4
181 _4 = 4,
182 /// 5
183 _5 = 5,
184 /// 6
185 _6 = 6,
186 /// 7
187 _7 = 7,
188 /// 8
189 _8 = 8,
190 /// 9
191 _9 = 9,
192 /// 10
193 _10 = 10,
194 /// 11
195 _11 = 11,
196 /// 12
197 _12 = 12,
198 /// 13
199 _13 = 13,
200 /// 14
201 _14 = 14,
202 /// 15
203 _15 = 15,
204 /// 16
205 _16 = 16,
206}
207
208/// Selects the source of the Timestamp counter
209#[derive(Clone, Copy, Debug)]
210pub enum TimestampSource {
211 /// The Timestamp counter is disabled
212 None,
213 /// Using the FdCan input clock as the Timstamp counter's source,
214 /// and using a specific prescaler
215 Prescaler(TimestampPrescaler),
216 /// Using TIM3 as a source
217 FromTIM3,
218}
219
220/// How to handle frames in the global filter
221#[derive(Clone, Copy, Debug)]
222pub enum NonMatchingFilter {
223 /// Frames will go to Fifo0 when they do no match any specific filter
224 IntoRxFifo0 = 0b00,
225 /// Frames will go to Fifo1 when they do no match any specific filter
226 IntoRxFifo1 = 0b01,
227 /// Frames will be rejected when they do not match any specific filter
228 Reject = 0b11,
229}
230
231/// How to handle frames which do not match a specific filter
232#[derive(Clone, Copy, Debug)]
233pub struct GlobalFilter {
234 /// How to handle non-matching standard frames
235 pub handle_standard_frames: NonMatchingFilter,
236
237 /// How to handle non-matching extended frames
238 pub handle_extended_frames: NonMatchingFilter,
239
240 /// How to handle remote standard frames
241 pub reject_remote_standard_frames: bool,
242
243 /// How to handle remote extended frames
244 pub reject_remote_extended_frames: bool,
245}
246impl GlobalFilter {
247 /// Reject all non-matching and remote frames
248 pub const fn reject_all() -> Self {
249 Self {
250 handle_standard_frames: NonMatchingFilter::Reject,
251 handle_extended_frames: NonMatchingFilter::Reject,
252 reject_remote_standard_frames: true,
253 reject_remote_extended_frames: true,
254 }
255 }
256
257 /// How to handle non-matching standard frames
258 pub const fn set_handle_standard_frames(mut self, filter: NonMatchingFilter) -> Self {
259 self.handle_standard_frames = filter;
260 self
261 }
262 /// How to handle non-matching exteded frames
263 pub const fn set_handle_extended_frames(mut self, filter: NonMatchingFilter) -> Self {
264 self.handle_extended_frames = filter;
265 self
266 }
267 /// How to handle remote standard frames
268 pub const fn set_reject_remote_standard_frames(mut self, filter: bool) -> Self {
269 self.reject_remote_standard_frames = filter;
270 self
271 }
272 /// How to handle remote extended frames
273 pub const fn set_reject_remote_extended_frames(mut self, filter: bool) -> Self {
274 self.reject_remote_extended_frames = filter;
275 self
276 }
277}
278impl Default for GlobalFilter {
279 #[inline]
280 fn default() -> Self {
281 Self {
282 handle_standard_frames: NonMatchingFilter::IntoRxFifo0,
283 handle_extended_frames: NonMatchingFilter::IntoRxFifo0,
284 reject_remote_standard_frames: false,
285 reject_remote_extended_frames: false,
286 }
287 }
288}
289
290/// TX buffer operation mode
291#[derive(Clone, Copy, PartialEq, Eq, Debug)]
292pub enum TxBufferMode {
293 /// TX FIFO operation - In this mode CAN frames are trasmitted strictly in write order.
294 Fifo,
295 /// TX priority queue operation - In this mode CAN frames are transmitted according to CAN priority.
296 Priority,
297}
298
299impl From<TxBufferMode> for crate::pac::can::vals::Tfqm {
300 fn from(value: TxBufferMode) -> Self {
301 match value {
302 TxBufferMode::Priority => Self::QUEUE,
303 TxBufferMode::Fifo => Self::FIFO,
304 }
305 }
306}
307
308impl From<crate::pac::can::vals::Tfqm> for TxBufferMode {
309 fn from(value: crate::pac::can::vals::Tfqm) -> Self {
310 match value {
311 crate::pac::can::vals::Tfqm::QUEUE => Self::Priority,
312 crate::pac::can::vals::Tfqm::FIFO => Self::Fifo,
313 }
314 }
315}
316
317/// FdCan Config Struct
318#[derive(Clone, Copy, Debug)]
319pub struct FdCanConfig {
320 /// Nominal Bit Timings
321 pub nbtr: NominalBitTiming,
322 /// (Variable) Data Bit Timings
323 pub dbtr: DataBitTiming,
324 /// Enables or disables automatic retransmission of messages
325 ///
326 /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
327 /// util it can be sent. Otherwise, it will try only once to send each frame.
328 ///
329 /// Automatic retransmission is enabled by default.
330 pub automatic_retransmit: bool,
331 /// Enabled or disables the pausing between transmissions
332 ///
333 /// This feature looses up burst transmissions coming from a single node and it protects against
334 /// "babbling idiot" scenarios where the application program erroneously requests too many
335 /// transmissions.
336 pub transmit_pause: bool,
337 /// Enabled or disables the pausing between transmissions
338 ///
339 /// This feature looses up burst transmissions coming from a single node and it protects against
340 /// "babbling idiot" scenarios where the application program erroneously requests too many
341 /// transmissions.
342 pub frame_transmit: FrameTransmissionConfig,
343 /// Non Isoe Mode
344 /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
345 /// FD Specification V1.0.
346 pub non_iso_mode: bool,
347 /// Edge Filtering: Two consecutive dominant tq required to detect an edge for hard synchronization
348 pub edge_filtering: bool,
349 /// Enables protocol exception handling
350 pub protocol_exception_handling: bool,
351 /// Sets the general clock divider for this FdCAN instance
352 pub clock_divider: ClockDivider,
353 /// Sets the timestamp source
354 pub timestamp_source: TimestampSource,
355 /// Configures the Global Filter
356 pub global_filter: GlobalFilter,
357 /// TX buffer mode (FIFO or priority queue)
358 pub tx_buffer_mode: TxBufferMode,
359}
360
361impl FdCanConfig {
362 /// Configures the bit timings.
363 #[inline]
364 pub const fn set_nominal_bit_timing(mut self, btr: NominalBitTiming) -> Self {
365 self.nbtr = btr;
366 self
367 }
368
369 /// Configures the bit timings.
370 #[inline]
371 pub const fn set_data_bit_timing(mut self, btr: DataBitTiming) -> Self {
372 self.dbtr = btr;
373 self
374 }
375
376 /// Enables or disables automatic retransmission of messages
377 ///
378 /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
379 /// util it can be sent. Otherwise, it will try only once to send each frame.
380 ///
381 /// Automatic retransmission is enabled by default.
382 #[inline]
383 pub const fn set_automatic_retransmit(mut self, enabled: bool) -> Self {
384 self.automatic_retransmit = enabled;
385 self
386 }
387
388 /// Enabled or disables the pausing between transmissions
389 ///
390 /// This feature looses up burst transmissions coming from a single node and it protects against
391 /// "babbling idiot" scenarios where the application program erroneously requests too many
392 /// transmissions.
393 #[inline]
394 pub const fn set_transmit_pause(mut self, enabled: bool) -> Self {
395 self.transmit_pause = enabled;
396 self
397 }
398
399 /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
400 /// FD Specification V1.0.
401 #[inline]
402 pub const fn set_non_iso_mode(mut self, enabled: bool) -> Self {
403 self.non_iso_mode = enabled;
404 self
405 }
406
407 /// Two consecutive dominant tq required to detect an edge for hard synchronization
408 #[inline]
409 pub const fn set_edge_filtering(mut self, enabled: bool) -> Self {
410 self.edge_filtering = enabled;
411 self
412 }
413
414 /// Sets the allowed transmission types for messages.
415 #[inline]
416 pub const fn set_frame_transmit(mut self, fts: FrameTransmissionConfig) -> Self {
417 self.frame_transmit = fts;
418 self
419 }
420
421 /// Enables protocol exception handling
422 #[inline]
423 pub const fn set_protocol_exception_handling(mut self, peh: bool) -> Self {
424 self.protocol_exception_handling = peh;
425 self
426 }
427
428 /// Sets the general clock divider for this FdCAN instance
429 #[inline]
430 pub const fn set_clock_divider(mut self, div: ClockDivider) -> Self {
431 self.clock_divider = div;
432 self
433 }
434
435 /// Sets the timestamp source
436 #[inline]
437 pub const fn set_timestamp_source(mut self, tss: TimestampSource) -> Self {
438 self.timestamp_source = tss;
439 self
440 }
441
442 /// Sets the global filter settings
443 #[inline]
444 pub const fn set_global_filter(mut self, filter: GlobalFilter) -> Self {
445 self.global_filter = filter;
446 self
447 }
448
449 /// Sets the TX buffer mode (FIFO or priority queue)
450 #[inline]
451 pub const fn set_tx_buffer_mode(mut self, txbm: TxBufferMode) -> Self {
452 self.tx_buffer_mode = txbm;
453 self
454 }
455}
456
457impl Default for FdCanConfig {
458 #[inline]
459 fn default() -> Self {
460 Self {
461 nbtr: NominalBitTiming::default(),
462 dbtr: DataBitTiming::default(),
463 automatic_retransmit: true,
464 transmit_pause: false,
465 frame_transmit: FrameTransmissionConfig::ClassicCanOnly,
466 non_iso_mode: false,
467 edge_filtering: false,
468 protocol_exception_handling: true,
469 clock_divider: ClockDivider::_1,
470 timestamp_source: TimestampSource::None,
471 global_filter: GlobalFilter::default(),
472 tx_buffer_mode: TxBufferMode::Priority,
473 }
474 }
475}
diff --git a/embassy-stm32/src/can/fd/filter.rs b/embassy-stm32/src/can/fd/filter.rs
new file mode 100644
index 000000000..2023a2ef0
--- /dev/null
+++ b/embassy-stm32/src/can/fd/filter.rs
@@ -0,0 +1,379 @@
1//! Definition of Filter structs for FDCAN Module
2// Note: This file is copied and modified from fdcan crate by Richard Meadows
3
4use embedded_can::{ExtendedId, StandardId};
5
6use crate::can::fd::message_ram;
7pub use crate::can::fd::message_ram::{EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX};
8
9/// A Standard Filter
10pub type StandardFilter = Filter<StandardId, u16>;
11/// An Extended Filter
12pub type ExtendedFilter = Filter<ExtendedId, u32>;
13
14impl Default for StandardFilter {
15 fn default() -> Self {
16 StandardFilter::disable()
17 }
18}
19impl Default for ExtendedFilter {
20 fn default() -> Self {
21 ExtendedFilter::disable()
22 }
23}
24
25impl StandardFilter {
26 /// Accept all messages in FIFO 0
27 pub fn accept_all_into_fifo0() -> StandardFilter {
28 StandardFilter {
29 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
30 action: Action::StoreInFifo0,
31 }
32 }
33
34 /// Accept all messages in FIFO 1
35 pub fn accept_all_into_fifo1() -> StandardFilter {
36 StandardFilter {
37 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
38 action: Action::StoreInFifo1,
39 }
40 }
41
42 /// Reject all messages
43 pub fn reject_all() -> StandardFilter {
44 StandardFilter {
45 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
46 action: Action::Reject,
47 }
48 }
49
50 /// Disable the filter
51 pub fn disable() -> StandardFilter {
52 StandardFilter {
53 filter: FilterType::Disabled,
54 action: Action::Disable,
55 }
56 }
57}
58
59impl ExtendedFilter {
60 /// Accept all messages in FIFO 0
61 pub fn accept_all_into_fifo0() -> ExtendedFilter {
62 ExtendedFilter {
63 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
64 action: Action::StoreInFifo0,
65 }
66 }
67
68 /// Accept all messages in FIFO 1
69 pub fn accept_all_into_fifo1() -> ExtendedFilter {
70 ExtendedFilter {
71 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
72 action: Action::StoreInFifo1,
73 }
74 }
75
76 /// Reject all messages
77 pub fn reject_all() -> ExtendedFilter {
78 ExtendedFilter {
79 filter: FilterType::BitMask { filter: 0x0, mask: 0x0 },
80 action: Action::Reject,
81 }
82 }
83
84 /// Disable the filter
85 pub fn disable() -> ExtendedFilter {
86 ExtendedFilter {
87 filter: FilterType::Disabled,
88 action: Action::Disable,
89 }
90 }
91}
92
93/// Filter Type
94#[derive(Clone, Copy, Debug)]
95pub enum FilterType<ID, UNIT>
96where
97 ID: Copy + Clone + core::fmt::Debug,
98 UNIT: Copy + Clone + core::fmt::Debug,
99{
100 /// Match with a range between two messages
101 Range {
102 /// First Id of the range
103 from: ID,
104 /// Last Id of the range
105 to: ID,
106 },
107 /// Match with a bitmask
108 BitMask {
109 /// Filter of the bitmask
110 filter: UNIT,
111 /// Mask of the bitmask
112 mask: UNIT,
113 },
114 /// Match with a single ID
115 DedicatedSingle(ID),
116 /// Match with one of two ID's
117 DedicatedDual(ID, ID),
118 /// Filter is disabled
119 Disabled,
120}
121impl<ID, UNIT> From<FilterType<ID, UNIT>> for message_ram::enums::FilterType
122where
123 ID: Copy + Clone + core::fmt::Debug,
124 UNIT: Copy + Clone + core::fmt::Debug,
125{
126 fn from(f: FilterType<ID, UNIT>) -> Self {
127 match f {
128 FilterType::Range { to: _, from: _ } => Self::RangeFilter,
129 FilterType::BitMask { filter: _, mask: _ } => Self::ClassicFilter,
130 FilterType::DedicatedSingle(_) => Self::DualIdFilter,
131 FilterType::DedicatedDual(_, _) => Self::DualIdFilter,
132 FilterType::Disabled => Self::FilterDisabled,
133 }
134 }
135}
136
137/// Filter Action
138#[derive(Clone, Copy, Debug)]
139pub enum Action {
140 /// No Action
141 Disable = 0b000,
142 /// Store an matching message in FIFO 0
143 StoreInFifo0 = 0b001,
144 /// Store an matching message in FIFO 1
145 StoreInFifo1 = 0b010,
146 /// Reject an matching message
147 Reject = 0b011,
148 /// Flag a matching message (But not store?!?)
149 FlagHighPrio = 0b100,
150 /// Flag a matching message as a High Priority message and store it in FIFO 0
151 FlagHighPrioAndStoreInFifo0 = 0b101,
152 /// Flag a matching message as a High Priority message and store it in FIFO 1
153 FlagHighPrioAndStoreInFifo1 = 0b110,
154}
155impl From<Action> for message_ram::enums::FilterElementConfig {
156 fn from(a: Action) -> Self {
157 match a {
158 Action::Disable => Self::DisableFilterElement,
159 Action::StoreInFifo0 => Self::StoreInFifo0,
160 Action::StoreInFifo1 => Self::StoreInFifo1,
161 Action::Reject => Self::Reject,
162 Action::FlagHighPrio => Self::SetPriority,
163 Action::FlagHighPrioAndStoreInFifo0 => Self::SetPriorityAndStoreInFifo0,
164 Action::FlagHighPrioAndStoreInFifo1 => Self::SetPriorityAndStoreInFifo1,
165 }
166 }
167}
168
169/// Filter
170#[derive(Clone, Copy, Debug)]
171pub struct Filter<ID, UNIT>
172where
173 ID: Copy + Clone + core::fmt::Debug,
174 UNIT: Copy + Clone + core::fmt::Debug,
175{
176 /// How to match an incoming message
177 pub filter: FilterType<ID, UNIT>,
178 /// What to do with a matching message
179 pub action: Action,
180}
181
182/// Standard Filter Slot
183#[derive(Debug, Copy, Clone, Eq, PartialEq)]
184pub enum StandardFilterSlot {
185 /// 0
186 _0 = 0,
187 /// 1
188 _1 = 1,
189 /// 2
190 _2 = 2,
191 /// 3
192 _3 = 3,
193 /// 4
194 _4 = 4,
195 /// 5
196 _5 = 5,
197 /// 6
198 _6 = 6,
199 /// 7
200 _7 = 7,
201 /// 8
202 _8 = 8,
203 /// 9
204 _9 = 9,
205 /// 10
206 _10 = 10,
207 /// 11
208 _11 = 11,
209 /// 12
210 _12 = 12,
211 /// 13
212 _13 = 13,
213 /// 14
214 _14 = 14,
215 /// 15
216 _15 = 15,
217 /// 16
218 _16 = 16,
219 /// 17
220 _17 = 17,
221 /// 18
222 _18 = 18,
223 /// 19
224 _19 = 19,
225 /// 20
226 _20 = 20,
227 /// 21
228 _21 = 21,
229 /// 22
230 _22 = 22,
231 /// 23
232 _23 = 23,
233 /// 24
234 _24 = 24,
235 /// 25
236 _25 = 25,
237 /// 26
238 _26 = 26,
239 /// 27
240 _27 = 27,
241}
242impl From<u8> for StandardFilterSlot {
243 fn from(u: u8) -> Self {
244 match u {
245 0 => StandardFilterSlot::_0,
246 1 => StandardFilterSlot::_1,
247 2 => StandardFilterSlot::_2,
248 3 => StandardFilterSlot::_3,
249 4 => StandardFilterSlot::_4,
250 5 => StandardFilterSlot::_5,
251 6 => StandardFilterSlot::_6,
252 7 => StandardFilterSlot::_7,
253 8 => StandardFilterSlot::_8,
254 9 => StandardFilterSlot::_9,
255 10 => StandardFilterSlot::_10,
256 11 => StandardFilterSlot::_11,
257 12 => StandardFilterSlot::_12,
258 13 => StandardFilterSlot::_13,
259 14 => StandardFilterSlot::_14,
260 15 => StandardFilterSlot::_15,
261 16 => StandardFilterSlot::_16,
262 17 => StandardFilterSlot::_17,
263 18 => StandardFilterSlot::_18,
264 19 => StandardFilterSlot::_19,
265 20 => StandardFilterSlot::_20,
266 21 => StandardFilterSlot::_21,
267 22 => StandardFilterSlot::_22,
268 23 => StandardFilterSlot::_23,
269 24 => StandardFilterSlot::_24,
270 25 => StandardFilterSlot::_25,
271 26 => StandardFilterSlot::_26,
272 27 => StandardFilterSlot::_27,
273 _ => panic!("Standard Filter Slot Too High!"),
274 }
275 }
276}
277
278/// Extended Filter Slot
279#[derive(Debug, Copy, Clone, Eq, PartialEq)]
280pub enum ExtendedFilterSlot {
281 /// 0
282 _0 = 0,
283 /// 1
284 _1 = 1,
285 /// 2
286 _2 = 2,
287 /// 3
288 _3 = 3,
289 /// 4
290 _4 = 4,
291 /// 5
292 _5 = 5,
293 /// 6
294 _6 = 6,
295 /// 7
296 _7 = 7,
297}
298impl From<u8> for ExtendedFilterSlot {
299 fn from(u: u8) -> Self {
300 match u {
301 0 => ExtendedFilterSlot::_0,
302 1 => ExtendedFilterSlot::_1,
303 2 => ExtendedFilterSlot::_2,
304 3 => ExtendedFilterSlot::_3,
305 4 => ExtendedFilterSlot::_4,
306 5 => ExtendedFilterSlot::_5,
307 6 => ExtendedFilterSlot::_6,
308 7 => ExtendedFilterSlot::_7,
309 _ => panic!("Extended Filter Slot Too High!"), // Should be unreachable
310 }
311 }
312}
313
314/// Enum over both Standard and Extended Filter ID's
315#[derive(Debug, Copy, Clone, Eq, PartialEq)]
316pub enum FilterId {
317 /// Standard Filter Slots
318 Standard(StandardFilterSlot),
319 /// Extended Filter Slots
320 Extended(ExtendedFilterSlot),
321}
322
323pub(crate) trait ActivateFilter<ID, UNIT>
324where
325 ID: Copy + Clone + core::fmt::Debug,
326 UNIT: Copy + Clone + core::fmt::Debug,
327{
328 fn activate(&mut self, f: Filter<ID, UNIT>);
329 // fn read(&self) -> Filter<ID, UNIT>;
330}
331
332impl ActivateFilter<StandardId, u16> for message_ram::StandardFilter {
333 fn activate(&mut self, f: Filter<StandardId, u16>) {
334 let sft = f.filter.into();
335
336 let (sfid1, sfid2) = match f.filter {
337 FilterType::Range { to, from } => (to.as_raw(), from.as_raw()),
338 FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()),
339 FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()),
340 FilterType::BitMask { filter, mask } => (filter, mask),
341 FilterType::Disabled => (0x0, 0x0),
342 };
343 let sfec = f.action.into();
344 self.write(|w| {
345 unsafe { w.sfid1().bits(sfid1).sfid2().bits(sfid2) }
346 .sft()
347 .set_filter_type(sft)
348 .sfec()
349 .set_filter_element_config(sfec)
350 });
351 }
352 // fn read(&self) -> Filter<StandardId, u16> {
353 // todo!()
354 // }
355}
356impl ActivateFilter<ExtendedId, u32> for message_ram::ExtendedFilter {
357 fn activate(&mut self, f: Filter<ExtendedId, u32>) {
358 let eft = f.filter.into();
359
360 let (efid1, efid2) = match f.filter {
361 FilterType::Range { to, from } => (to.as_raw(), from.as_raw()),
362 FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()),
363 FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()),
364 FilterType::BitMask { filter, mask } => (filter, mask),
365 FilterType::Disabled => (0x0, 0x0),
366 };
367 let efec = f.action.into();
368 self.write(|w| {
369 unsafe { w.efid1().bits(efid1).efid2().bits(efid2) }
370 .eft()
371 .set_filter_type(eft)
372 .efec()
373 .set_filter_element_config(efec)
374 });
375 }
376 // fn read(&self) -> Filter<ExtendedId, u32> {
377 // todo!()
378 // }
379}
diff --git a/embassy-stm32/src/can/fd/message_ram/common.rs b/embassy-stm32/src/can/fd/message_ram/common.rs
new file mode 100644
index 000000000..108c1a428
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/common.rs
@@ -0,0 +1,134 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(unused)]
5
6use super::enums::{
7 BitRateSwitching, ErrorStateIndicator, FilterElementConfig, FilterType, FrameFormat, IdType,
8 RemoteTransmissionRequest,
9};
10use super::generic;
11
12#[doc = "Reader of field `ID`"]
13pub type ID_R = generic::R<u32, u32>;
14
15#[doc = "Reader of field `RTR`"]
16pub type RTR_R = generic::R<bool, RemoteTransmissionRequest>;
17impl RTR_R {
18 pub fn rtr(&self) -> RemoteTransmissionRequest {
19 match self.bits {
20 false => RemoteTransmissionRequest::TransmitDataFrame,
21 true => RemoteTransmissionRequest::TransmitRemoteFrame,
22 }
23 }
24 pub fn is_transmit_remote_frame(&self) -> bool {
25 *self == RemoteTransmissionRequest::TransmitRemoteFrame
26 }
27 pub fn is_transmit_data_frame(&self) -> bool {
28 *self == RemoteTransmissionRequest::TransmitDataFrame
29 }
30}
31
32#[doc = "Reader of field `XTD`"]
33pub type XTD_R = generic::R<bool, IdType>;
34impl XTD_R {
35 pub fn id_type(&self) -> IdType {
36 match self.bits() {
37 false => IdType::StandardId,
38 true => IdType::ExtendedId,
39 }
40 }
41 pub fn is_standard_id(&self) -> bool {
42 *self == IdType::StandardId
43 }
44 pub fn is_exteded_id(&self) -> bool {
45 *self == IdType::ExtendedId
46 }
47}
48
49#[doc = "Reader of field `ESI`"]
50pub type ESI_R = generic::R<bool, ErrorStateIndicator>;
51impl ESI_R {
52 pub fn error_state(&self) -> ErrorStateIndicator {
53 match self.bits() {
54 false => ErrorStateIndicator::ErrorActive,
55 true => ErrorStateIndicator::ErrorPassive,
56 }
57 }
58 pub fn is_error_active(&self) -> bool {
59 *self == ErrorStateIndicator::ErrorActive
60 }
61 pub fn is_error_passive(&self) -> bool {
62 *self == ErrorStateIndicator::ErrorPassive
63 }
64}
65
66#[doc = "Reader of field `DLC`"]
67pub type DLC_R = generic::R<u8, u8>;
68
69#[doc = "Reader of field `BRS`"]
70pub type BRS_R = generic::R<bool, BitRateSwitching>;
71impl BRS_R {
72 pub fn bit_rate_switching(&self) -> BitRateSwitching {
73 match self.bits() {
74 true => BitRateSwitching::WithBRS,
75 false => BitRateSwitching::WithoutBRS,
76 }
77 }
78 pub fn is_with_brs(&self) -> bool {
79 *self == BitRateSwitching::WithBRS
80 }
81 pub fn is_without_brs(&self) -> bool {
82 *self == BitRateSwitching::WithoutBRS
83 }
84}
85
86#[doc = "Reader of field `FDF`"]
87pub type FDF_R = generic::R<bool, FrameFormat>;
88impl FDF_R {
89 pub fn frame_format(&self) -> FrameFormat {
90 match self.bits() {
91 false => FrameFormat::Classic,
92 true => FrameFormat::Fdcan,
93 }
94 }
95 pub fn is_classic_format(&self) -> bool {
96 *self == FrameFormat::Classic
97 }
98 pub fn is_fdcan_format(&self) -> bool {
99 *self == FrameFormat::Fdcan
100 }
101}
102
103#[doc = "Reader of field `(X|S)FT`"]
104pub type ESFT_R = generic::R<u8, FilterType>;
105impl ESFT_R {
106 #[doc = r"Gets the Filtertype"]
107 #[inline(always)]
108 pub fn to_filter_type(&self) -> FilterType {
109 match self.bits() {
110 0b00 => FilterType::RangeFilter,
111 0b01 => FilterType::DualIdFilter,
112 0b10 => FilterType::ClassicFilter,
113 0b11 => FilterType::FilterDisabled,
114 _ => unreachable!(),
115 }
116 }
117}
118
119#[doc = "Reader of field `(E|S)FEC`"]
120pub type ESFEC_R = generic::R<u8, FilterElementConfig>;
121impl ESFEC_R {
122 pub fn to_filter_element_config(&self) -> FilterElementConfig {
123 match self.bits() {
124 0b000 => FilterElementConfig::DisableFilterElement,
125 0b001 => FilterElementConfig::StoreInFifo0,
126 0b010 => FilterElementConfig::StoreInFifo1,
127 0b011 => FilterElementConfig::Reject,
128 0b100 => FilterElementConfig::SetPriority,
129 0b101 => FilterElementConfig::SetPriorityAndStoreInFifo0,
130 0b110 => FilterElementConfig::SetPriorityAndStoreInFifo1,
131 _ => unimplemented!(),
132 }
133 }
134}
diff --git a/embassy-stm32/src/can/fd/message_ram/enums.rs b/embassy-stm32/src/can/fd/message_ram/enums.rs
new file mode 100644
index 000000000..0ec5e0f34
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/enums.rs
@@ -0,0 +1,233 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3/// Datalength is the message length generalised over
4/// the Standard (Classic) and FDCAN message types
5
6#[derive(Clone, Copy, Debug, PartialEq)]
7pub enum DataLength {
8 Classic(u8),
9 Fdcan(u8),
10}
11impl DataLength {
12 /// Creates a DataLength type
13 ///
14 /// Uses the byte length and Type of frame as input
15 pub fn new(len: u8, ff: FrameFormat) -> DataLength {
16 match ff {
17 FrameFormat::Classic => match len {
18 0..=8 => DataLength::Classic(len),
19 _ => panic!("DataLength > 8"),
20 },
21 FrameFormat::Fdcan => match len {
22 0..=64 => DataLength::Fdcan(len),
23 _ => panic!("DataLength > 64"),
24 },
25 }
26 }
27 /// Specialised function to create classic frames
28 pub fn new_classic(len: u8) -> DataLength {
29 Self::new(len, FrameFormat::Classic)
30 }
31 /// Specialised function to create FDCAN frames
32 pub fn new_fdcan(len: u8) -> DataLength {
33 Self::new(len, FrameFormat::Fdcan)
34 }
35
36 /// returns the length in bytes
37 pub fn len(&self) -> u8 {
38 match self {
39 DataLength::Classic(l) | DataLength::Fdcan(l) => *l,
40 }
41 }
42
43 pub(crate) fn dlc(&self) -> u8 {
44 match self {
45 DataLength::Classic(l) => *l,
46 // See RM0433 Rev 7 Table 475. DLC coding
47 DataLength::Fdcan(l) => match l {
48 0..=8 => *l,
49 9..=12 => 9,
50 13..=16 => 10,
51 17..=20 => 11,
52 21..=24 => 12,
53 25..=32 => 13,
54 33..=48 => 14,
55 49..=64 => 15,
56 _ => panic!("DataLength > 64"),
57 },
58 }
59 }
60}
61impl From<DataLength> for FrameFormat {
62 fn from(dl: DataLength) -> FrameFormat {
63 match dl {
64 DataLength::Classic(_) => FrameFormat::Classic,
65 DataLength::Fdcan(_) => FrameFormat::Fdcan,
66 }
67 }
68}
69
70/// Wheter or not to generate an Tx Event
71#[derive(Clone, Copy, Debug, PartialEq)]
72pub enum Event {
73 /// Do not generate an Tx Event
74 NoEvent,
75 /// Generate an Tx Event with a specified ID
76 Event(u8),
77}
78
79impl From<Event> for EventControl {
80 fn from(e: Event) -> Self {
81 match e {
82 Event::NoEvent => EventControl::DoNotStore,
83 Event::Event(_) => EventControl::Store,
84 }
85 }
86}
87
88impl From<Option<u8>> for Event {
89 fn from(mm: Option<u8>) -> Self {
90 match mm {
91 None => Event::NoEvent,
92 Some(mm) => Event::Event(mm),
93 }
94 }
95}
96
97impl From<Event> for Option<u8> {
98 fn from(e: Event) -> Option<u8> {
99 match e {
100 Event::NoEvent => None,
101 Event::Event(mm) => Some(mm),
102 }
103 }
104}
105
106/// TODO
107#[derive(Clone, Copy, Debug, PartialEq)]
108pub enum ErrorStateIndicator {
109 /// TODO
110 ErrorActive = 0,
111 /// TODO
112 ErrorPassive = 1,
113}
114impl From<ErrorStateIndicator> for bool {
115 #[inline(always)]
116 fn from(e: ErrorStateIndicator) -> Self {
117 e as u8 != 0
118 }
119}
120
121/// Type of frame, standard (classic) or FdCAN
122#[derive(Clone, Copy, Debug, PartialEq)]
123pub enum FrameFormat {
124 Classic = 0,
125 Fdcan = 1,
126}
127impl From<FrameFormat> for bool {
128 #[inline(always)]
129 fn from(e: FrameFormat) -> Self {
130 e as u8 != 0
131 }
132}
133
134/// Type of Id, Standard or Extended
135#[derive(Clone, Copy, Debug, PartialEq)]
136pub enum IdType {
137 /// Standard ID
138 StandardId = 0,
139 /// Extended ID
140 ExtendedId = 1,
141}
142impl From<IdType> for bool {
143 #[inline(always)]
144 fn from(e: IdType) -> Self {
145 e as u8 != 0
146 }
147}
148
149/// Whether the frame contains data or requests data
150#[derive(Clone, Copy, Debug, PartialEq)]
151pub enum RemoteTransmissionRequest {
152 /// Frame contains data
153 TransmitDataFrame = 0,
154 /// frame does not contain data
155 TransmitRemoteFrame = 1,
156}
157impl From<RemoteTransmissionRequest> for bool {
158 #[inline(always)]
159 fn from(e: RemoteTransmissionRequest) -> Self {
160 e as u8 != 0
161 }
162}
163
164/// Whether BitRateSwitching should be or was enabled
165#[derive(Clone, Copy, Debug, PartialEq)]
166pub enum BitRateSwitching {
167 /// disable bit rate switching
168 WithoutBRS = 0,
169 /// enable bit rate switching
170 WithBRS = 1,
171}
172impl From<BitRateSwitching> for bool {
173 #[inline(always)]
174 fn from(e: BitRateSwitching) -> Self {
175 e as u8 != 0
176 }
177}
178
179/// Whether to store transmit Events
180#[derive(Clone, Copy, Debug, PartialEq)]
181pub enum EventControl {
182 /// do not store an tx event
183 DoNotStore,
184 /// store transmit events
185 Store,
186}
187impl From<EventControl> for bool {
188 #[inline(always)]
189 fn from(e: EventControl) -> Self {
190 e as u8 != 0
191 }
192}
193
194/// If an received message matched any filters
195#[derive(Clone, Copy, Debug, PartialEq)]
196pub enum FilterFrameMatch {
197 /// This did match filter <id>
198 DidMatch(u8),
199 /// This received frame did not match any specific filters
200 DidNotMatch,
201}
202
203/// Type of filter to be used
204#[derive(Clone, Copy, Debug, PartialEq)]
205pub enum FilterType {
206 /// Filter uses the range between two id's
207 RangeFilter = 0b00,
208 /// The filter matches on two specific id's (or one ID checked twice)
209 DualIdFilter = 0b01,
210 /// Filter is using a bitmask
211 ClassicFilter = 0b10,
212 /// Filter is disabled
213 FilterDisabled = 0b11,
214}
215
216#[derive(Clone, Copy, Debug, PartialEq)]
217pub enum FilterElementConfig {
218 /// Filter is disabled
219 DisableFilterElement = 0b000,
220 /// Store a matching message in FIFO 0
221 StoreInFifo0 = 0b001,
222 /// Store a matching message in FIFO 1
223 StoreInFifo1 = 0b010,
224 /// Reject a matching message
225 Reject = 0b011,
226 /// Flag that a priority message has been received, *But do note store!*??
227 SetPriority = 0b100,
228 /// Flag and store message in FIFO 0
229 SetPriorityAndStoreInFifo0 = 0b101,
230 /// Flag and store message in FIFO 1
231 SetPriorityAndStoreInFifo1 = 0b110,
232 //_Unused = 0b111,
233}
diff --git a/embassy-stm32/src/can/fd/message_ram/extended_filter.rs b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs
new file mode 100644
index 000000000..453e9056e
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs
@@ -0,0 +1,136 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{ESFEC_R, ESFT_R};
8use super::enums::{FilterElementConfig, FilterType};
9use super::generic;
10
11#[doc = "Reader of register ExtendedFilter"]
12pub(crate) type R = generic::R<super::ExtendedFilterType, super::ExtendedFilter>;
13#[doc = "Writer for register ExtendedFilter"]
14pub(crate) type W = generic::W<super::ExtendedFilterType, super::ExtendedFilter>;
15#[doc = "Register ExtendedFilter `reset()`'s"]
16impl generic::ResetValue for super::ExtendedFilter {
17 type Type = super::ExtendedFilterType;
18 #[inline(always)]
19 fn reset_value() -> Self::Type {
20 // Sets filter element to Disabled
21 [0x0, 0x0]
22 }
23}
24
25#[doc = "Reader of field `EFID2`"]
26pub(crate) type EFID2_R = generic::R<u32, u32>;
27#[doc = "Write proxy for field `EFID2`"]
28pub(crate) struct EFID2_W<'a> {
29 w: &'a mut W,
30}
31impl<'a> EFID2_W<'a> {
32 #[doc = r"Writes raw bits to the field"]
33 #[inline(always)]
34 pub unsafe fn bits(self, value: u32) -> &'a mut W {
35 self.w.bits[1] = (self.w.bits[1] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
36 self.w
37 }
38}
39
40#[doc = "Reader of field `EFID1`"]
41pub(crate) type EFID1_R = generic::R<u32, u32>;
42#[doc = "Write proxy for field `EFID1`"]
43pub(crate) struct EFID1_W<'a> {
44 w: &'a mut W,
45}
46impl<'a> EFID1_W<'a> {
47 #[doc = r"Writes raw bits to the field"]
48 #[inline(always)]
49 pub unsafe fn bits(self, value: u32) -> &'a mut W {
50 self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
51 self.w
52 }
53}
54
55#[doc = "Write proxy for field `EFEC`"]
56pub(crate) struct EFEC_W<'a> {
57 w: &'a mut W,
58}
59impl<'a> EFEC_W<'a> {
60 #[doc = r"Writes raw bits to the field"]
61 #[inline(always)]
62 pub unsafe fn bits(self, value: u8) -> &'a mut W {
63 self.w.bits[0] = (self.w.bits[0] & !(0x07 << 29)) | (((value as u32) & 0x07) << 29);
64 self.w
65 }
66 #[doc = r"Sets the field according to FilterElementConfig"]
67 #[inline(always)]
68 pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W {
69 //SAFETY: FilterElementConfig only be valid options
70 unsafe { self.bits(fec as u8) }
71 }
72}
73
74#[doc = "Write proxy for field `EFT`"]
75pub(crate) struct EFT_W<'a> {
76 w: &'a mut W,
77}
78impl<'a> EFT_W<'a> {
79 #[doc = r"Sets the field according the FilterType"]
80 #[inline(always)]
81 pub fn set_filter_type(self, filter: FilterType) -> &'a mut W {
82 //SAFETY: FilterType only be valid options
83 unsafe { self.bits(filter as u8) }
84 }
85 #[doc = r"Writes raw bits to the field"]
86 #[inline(always)]
87 pub unsafe fn bits(self, value: u8) -> &'a mut W {
88 self.w.bits[1] = (self.w.bits[1] & !(0x03 << 30)) | (((value as u32) & 0x03) << 30);
89 self.w
90 }
91}
92
93impl R {
94 #[doc = "Byte 0 - Bits 0:28 - EFID1"]
95 #[inline(always)]
96 pub fn sfid1(&self) -> EFID1_R {
97 EFID1_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
98 }
99 #[doc = "Byte 0 - Bits 29:31 - EFEC"]
100 #[inline(always)]
101 pub fn efec(&self) -> ESFEC_R {
102 ESFEC_R::new(((self.bits[0] >> 29) & 0x07) as u8)
103 }
104 #[doc = "Byte 1 - Bits 0:28 - EFID2"]
105 #[inline(always)]
106 pub fn sfid2(&self) -> EFID2_R {
107 EFID2_R::new(((self.bits[1]) & 0x1FFFFFFF) as u32)
108 }
109 #[doc = "Byte 1 - Bits 30:31 - EFT"]
110 #[inline(always)]
111 pub fn eft(&self) -> ESFT_R {
112 ESFT_R::new(((self.bits[1] >> 30) & 0x03) as u8)
113 }
114}
115impl W {
116 #[doc = "Byte 0 - Bits 0:28 - EFID1"]
117 #[inline(always)]
118 pub fn efid1(&mut self) -> EFID1_W {
119 EFID1_W { w: self }
120 }
121 #[doc = "Byte 0 - Bits 29:31 - EFEC"]
122 #[inline(always)]
123 pub fn efec(&mut self) -> EFEC_W {
124 EFEC_W { w: self }
125 }
126 #[doc = "Byte 1 - Bits 0:28 - EFID2"]
127 #[inline(always)]
128 pub fn efid2(&mut self) -> EFID2_W {
129 EFID2_W { w: self }
130 }
131 #[doc = "Byte 1 - Bits 30:31 - EFT"]
132 #[inline(always)]
133 pub fn eft(&mut self) -> EFT_W {
134 EFT_W { w: self }
135 }
136}
diff --git a/embassy-stm32/src/can/fd/message_ram/generic.rs b/embassy-stm32/src/can/fd/message_ram/generic.rs
new file mode 100644
index 000000000..1a5e121b4
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/generic.rs
@@ -0,0 +1,168 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3use core::marker;
4
5///This trait shows that register has `read` method
6///
7///Registers marked with `Writable` can be also `modify`'ed
8pub trait Readable {}
9
10///This trait shows that register has `write`, `write_with_zero` and `reset` method
11///
12///Registers marked with `Readable` can be also `modify`'ed
13pub trait Writable {}
14
15///Reset value of the register
16///
17///This value is initial value for `write` method.
18///It can be also directly writed to register by `reset` method.
19pub trait ResetValue {
20 ///Register size
21 type Type;
22 ///Reset value of the register
23 fn reset_value() -> Self::Type;
24}
25
26///This structure provides volatile access to register
27pub struct Reg<U, REG> {
28 register: vcell::VolatileCell<U>,
29 _marker: marker::PhantomData<REG>,
30}
31
32unsafe impl<U: Send, REG> Send for Reg<U, REG> {}
33
34impl<U, REG> Reg<U, REG>
35where
36 Self: Readable,
37 U: Copy,
38{
39 ///Reads the contents of `Readable` register
40 ///
41 ///You can read the contents of a register in such way:
42 ///```ignore
43 ///let bits = periph.reg.read().bits();
44 ///```
45 ///or get the content of a particular field of a register.
46 ///```ignore
47 ///let reader = periph.reg.read();
48 ///let bits = reader.field1().bits();
49 ///let flag = reader.field2().bit_is_set();
50 ///```
51 #[inline(always)]
52 pub fn read(&self) -> R<U, Self> {
53 R {
54 bits: self.register.get(),
55 _reg: marker::PhantomData,
56 }
57 }
58}
59
60impl<U, REG> Reg<U, REG>
61where
62 Self: ResetValue<Type = U> + Writable,
63 U: Copy,
64{
65 ///Writes the reset value to `Writable` register
66 ///
67 ///Resets the register to its initial state
68 #[inline(always)]
69 pub fn reset(&self) {
70 self.register.set(Self::reset_value())
71 }
72}
73
74impl<U, REG> Reg<U, REG>
75where
76 Self: ResetValue<Type = U> + Writable,
77 U: Copy,
78{
79 ///Writes bits to `Writable` register
80 ///
81 ///You can write raw bits into a register:
82 ///```ignore
83 ///periph.reg.write(|w| unsafe { w.bits(rawbits) });
84 ///```
85 ///or write only the fields you need:
86 ///```ignore
87 ///periph.reg.write(|w| w
88 /// .field1().bits(newfield1bits)
89 /// .field2().set_bit()
90 /// .field3().variant(VARIANT)
91 ///);
92 ///```
93 ///Other fields will have reset value.
94 #[inline(always)]
95 pub fn write<F>(&self, f: F)
96 where
97 F: FnOnce(&mut W<U, Self>) -> &mut W<U, Self>,
98 {
99 self.register.set(
100 f(&mut W {
101 bits: Self::reset_value(),
102 _reg: marker::PhantomData,
103 })
104 .bits,
105 );
106 }
107}
108
109///Register/field reader
110///
111///Result of the [`read`](Reg::read) method of a register.
112///Also it can be used in the [`modify`](Reg::read) method
113pub struct R<U, T> {
114 pub(crate) bits: U,
115 _reg: marker::PhantomData<T>,
116}
117
118impl<U, T> R<U, T>
119where
120 U: Copy,
121{
122 ///Create new instance of reader
123 #[inline(always)]
124 pub(crate) fn new(bits: U) -> Self {
125 Self {
126 bits,
127 _reg: marker::PhantomData,
128 }
129 }
130 ///Read raw bits from register/field
131 #[inline(always)]
132 pub fn bits(&self) -> U {
133 self.bits
134 }
135}
136
137impl<U, T, FI> PartialEq<FI> for R<U, T>
138where
139 U: PartialEq,
140 FI: Copy + Into<U>,
141{
142 #[inline(always)]
143 fn eq(&self, other: &FI) -> bool {
144 self.bits.eq(&(*other).into())
145 }
146}
147
148impl<FI> R<bool, FI> {
149 ///Value of the field as raw bits
150 #[inline(always)]
151 pub fn bit(&self) -> bool {
152 self.bits
153 }
154 ///Returns `true` if the bit is clear (0)
155 #[inline(always)]
156 pub fn bit_is_clear(&self) -> bool {
157 !self.bit()
158 }
159}
160
161///Register writer
162///
163///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register
164pub struct W<U, REG> {
165 ///Writable bits
166 pub(crate) bits: U,
167 _reg: marker::PhantomData<REG>,
168}
diff --git a/embassy-stm32/src/can/fd/message_ram/mod.rs b/embassy-stm32/src/can/fd/message_ram/mod.rs
new file mode 100644
index 000000000..830edf3bb
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/mod.rs
@@ -0,0 +1,170 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3use volatile_register::RW;
4
5pub(crate) mod common;
6pub(crate) mod enums;
7pub(crate) mod generic;
8
9/// Number of Receive Fifos configured by this module
10pub const RX_FIFOS_MAX: u8 = 2;
11/// Number of Receive Messages per RxFifo configured by this module
12pub const RX_FIFO_MAX: u8 = 3;
13/// Number of Transmit Messages configured by this module
14pub const TX_FIFO_MAX: u8 = 3;
15/// Number of Transmit Events configured by this module
16pub const TX_EVENT_MAX: u8 = 3;
17/// Number of Standard Filters configured by this module
18pub const STANDARD_FILTER_MAX: u8 = 28;
19/// Number of Extended Filters configured by this module
20pub const EXTENDED_FILTER_MAX: u8 = 8;
21
22/// MessageRam Overlay
23#[repr(C)]
24pub struct RegisterBlock {
25 pub(crate) filters: Filters,
26 pub(crate) receive: [Receive; RX_FIFOS_MAX as usize],
27 pub(crate) transmit: Transmit,
28}
29impl RegisterBlock {
30 pub fn reset(&mut self) {
31 self.filters.reset();
32 self.receive[0].reset();
33 self.receive[1].reset();
34 self.transmit.reset();
35 }
36}
37
38#[repr(C)]
39pub(crate) struct Filters {
40 pub(crate) flssa: [StandardFilter; STANDARD_FILTER_MAX as usize],
41 pub(crate) flesa: [ExtendedFilter; EXTENDED_FILTER_MAX as usize],
42}
43impl Filters {
44 pub fn reset(&mut self) {
45 for sf in &mut self.flssa {
46 sf.reset();
47 }
48 for ef in &mut self.flesa {
49 ef.reset();
50 }
51 }
52}
53
54#[repr(C)]
55pub(crate) struct Receive {
56 pub(crate) fxsa: [RxFifoElement; RX_FIFO_MAX as usize],
57}
58impl Receive {
59 pub fn reset(&mut self) {
60 for fe in &mut self.fxsa {
61 fe.reset();
62 }
63 }
64}
65
66#[repr(C)]
67pub(crate) struct Transmit {
68 pub(crate) efsa: [TxEventElement; TX_EVENT_MAX as usize],
69 pub(crate) tbsa: [TxBufferElement; TX_FIFO_MAX as usize],
70}
71impl Transmit {
72 pub fn reset(&mut self) {
73 for ee in &mut self.efsa {
74 ee.reset();
75 }
76 for be in &mut self.tbsa {
77 be.reset();
78 }
79 }
80}
81
82pub(crate) mod standard_filter;
83pub(crate) type StandardFilterType = u32;
84pub(crate) type StandardFilter = generic::Reg<StandardFilterType, _StandardFilter>;
85pub(crate) struct _StandardFilter;
86impl generic::Readable for StandardFilter {}
87impl generic::Writable for StandardFilter {}
88
89pub(crate) mod extended_filter;
90pub(crate) type ExtendedFilterType = [u32; 2];
91pub(crate) type ExtendedFilter = generic::Reg<ExtendedFilterType, _ExtendedFilter>;
92pub(crate) struct _ExtendedFilter;
93impl generic::Readable for ExtendedFilter {}
94impl generic::Writable for ExtendedFilter {}
95
96pub(crate) mod txevent_element;
97pub(crate) type TxEventElementType = [u32; 2];
98pub(crate) type TxEventElement = generic::Reg<TxEventElementType, _TxEventElement>;
99pub(crate) struct _TxEventElement;
100impl generic::Readable for TxEventElement {}
101impl generic::Writable for TxEventElement {}
102
103pub(crate) mod rxfifo_element;
104#[repr(C)]
105pub(crate) struct RxFifoElement {
106 pub(crate) header: RxFifoElementHeader,
107 pub(crate) data: [RW<u32>; 16],
108}
109impl RxFifoElement {
110 pub(crate) fn reset(&mut self) {
111 self.header.reset();
112 for byte in self.data.iter_mut() {
113 unsafe { byte.write(0) };
114 }
115 }
116}
117pub(crate) type RxFifoElementHeaderType = [u32; 2];
118pub(crate) type RxFifoElementHeader = generic::Reg<RxFifoElementHeaderType, _RxFifoElement>;
119pub(crate) struct _RxFifoElement;
120impl generic::Readable for RxFifoElementHeader {}
121impl generic::Writable for RxFifoElementHeader {}
122
123pub(crate) mod txbuffer_element;
124#[repr(C)]
125pub(crate) struct TxBufferElement {
126 pub(crate) header: TxBufferElementHeader,
127 pub(crate) data: [RW<u32>; 16],
128}
129impl TxBufferElement {
130 pub(crate) fn reset(&mut self) {
131 self.header.reset();
132 for byte in self.data.iter_mut() {
133 unsafe { byte.write(0) };
134 }
135 }
136}
137pub(crate) type TxBufferElementHeader = generic::Reg<TxBufferElementHeaderType, _TxBufferElement>;
138pub(crate) type TxBufferElementHeaderType = [u32; 2];
139pub(crate) struct _TxBufferElement;
140impl generic::Readable for TxBufferElementHeader {}
141impl generic::Writable for TxBufferElementHeader {}
142
143/// FdCan Message RAM instance.
144///
145/// # Safety
146///
147/// It is only safe to implement this trait, when:
148///
149/// * The implementing type has ownership of the Message RAM, preventing any
150/// other accesses to the register block.
151/// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed
152/// for as long as ownership or a borrow of the implementing type is present.
153pub unsafe trait Instance {
154 const MSG_RAM: *mut RegisterBlock;
155 fn msg_ram(&self) -> &RegisterBlock {
156 unsafe { &*Self::MSG_RAM }
157 }
158 fn msg_ram_mut(&mut self) -> &mut RegisterBlock {
159 unsafe { &mut *Self::MSG_RAM }
160 }
161}
162
163// Ensure the RegisterBlock is the same size as on pg 1957 of RM0440.
164static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]);
165static_assertions::assert_eq_size!(Receive, [u32; 54]);
166static_assertions::assert_eq_size!(Transmit, [u32; 6 + 54]);
167static_assertions::assert_eq_size!(
168 RegisterBlock,
169 [u32; 28 /*Standard Filters*/ +16 /*Extended Filters*/ +54 /*RxFifo0*/ +54 /*RxFifo1*/ +6 /*TxEvent*/ +54 /*TxFifo */]
170);
diff --git a/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs
new file mode 100644
index 000000000..48fc3a091
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs
@@ -0,0 +1,122 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R};
8use super::enums::{DataLength, FilterFrameMatch, FrameFormat};
9use super::generic;
10
11#[doc = "Reader of register RxFifoElement"]
12pub(crate) type R = generic::R<super::RxFifoElementHeaderType, super::RxFifoElementHeader>;
13// #[doc = "Writer for register ExtendedFilter"]
14// pub(crate) type W = generic::W<super::RxFifoElementHeaderType, super::RxFifoElementHeader>;
15#[doc = "Register ExtendedFilter `reset()`'s"]
16impl generic::ResetValue for super::RxFifoElementHeader {
17 type Type = super::RxFifoElementHeaderType;
18 #[inline(always)]
19 fn reset_value() -> Self::Type {
20 [0x0, 0x0]
21 }
22}
23
24#[doc = "Reader of field `RXTS`"]
25pub(crate) type RXTS_R = generic::R<u16, u16>;
26
27#[doc = "Reader of field `FIDX`"]
28pub(crate) type FIDX_R = generic::R<u8, u8>;
29
30pub(crate) struct _ANMF;
31#[doc = "Reader of field `ANMF`"]
32pub(crate) type ANMF_R = generic::R<bool, _ANMF>;
33impl ANMF_R {
34 pub fn is_matching_frame(&self) -> bool {
35 self.bit_is_clear()
36 }
37}
38
39impl R {
40 #[doc = "Byte 0 - Bits 0:28 - ID"]
41 #[inline(always)]
42 pub fn id(&self) -> ID_R {
43 ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
44 }
45 #[doc = "Byte 0 - Bit 29 - RTR"]
46 #[inline(always)]
47 pub fn rtr(&self) -> RTR_R {
48 RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
49 }
50 #[doc = "Byte 0 - Bit 30 - XTD"]
51 #[inline(always)]
52 pub fn xtd(&self) -> XTD_R {
53 XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
54 }
55 #[doc = "Byte 0 - Bit 30 - ESI"]
56 #[inline(always)]
57 pub fn esi(&self) -> ESI_R {
58 ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
59 }
60 #[doc = "Byte 1 - Bits 0:15 - RXTS"]
61 #[inline(always)]
62 pub fn txts(&self) -> RXTS_R {
63 RXTS_R::new(((self.bits[1]) & 0xFFFF) as u16)
64 }
65 #[doc = "Byte 1 - Bits 16:19 - DLC"]
66 #[inline(always)]
67 pub fn dlc(&self) -> DLC_R {
68 DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
69 }
70 #[doc = "Byte 1 - Bits 20 - BRS"]
71 #[inline(always)]
72 pub fn brs(&self) -> BRS_R {
73 BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
74 }
75 #[doc = "Byte 1 - Bits 20 - FDF"]
76 #[inline(always)]
77 pub fn fdf(&self) -> FDF_R {
78 FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0)
79 }
80 #[doc = "Byte 1 - Bits 24:30 - FIDX"]
81 #[inline(always)]
82 pub fn fidx(&self) -> FIDX_R {
83 FIDX_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
84 }
85 #[doc = "Byte 1 - Bits 31 - ANMF"]
86 #[inline(always)]
87 pub fn anmf(&self) -> ANMF_R {
88 ANMF_R::new(((self.bits[1] >> 31) & 0x01) != 0)
89 }
90 pub fn to_data_length(&self) -> DataLength {
91 let dlc = self.dlc().bits();
92 let ff = self.fdf().frame_format();
93 let len = if ff == FrameFormat::Fdcan {
94 // See RM0433 Rev 7 Table 475. DLC coding
95 match dlc {
96 0..=8 => dlc,
97 9 => 12,
98 10 => 16,
99 11 => 20,
100 12 => 24,
101 13 => 32,
102 14 => 48,
103 15 => 64,
104 _ => panic!("DLC > 15"),
105 }
106 } else {
107 match dlc {
108 0..=8 => dlc,
109 9..=15 => 8,
110 _ => panic!("DLC > 15"),
111 }
112 };
113 DataLength::new(len, ff)
114 }
115 pub fn to_filter_match(&self) -> FilterFrameMatch {
116 if self.anmf().is_matching_frame() {
117 FilterFrameMatch::DidMatch(self.fidx().bits())
118 } else {
119 FilterFrameMatch::DidNotMatch
120 }
121 }
122}
diff --git a/embassy-stm32/src/can/fd/message_ram/standard_filter.rs b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs
new file mode 100644
index 000000000..3a3bbcf12
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs
@@ -0,0 +1,136 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{ESFEC_R, ESFT_R};
8use super::enums::{FilterElementConfig, FilterType};
9use super::generic;
10
11#[doc = "Reader of register StandardFilter"]
12pub(crate) type R = generic::R<super::StandardFilterType, super::StandardFilter>;
13#[doc = "Writer for register StandardFilter"]
14pub(crate) type W = generic::W<super::StandardFilterType, super::StandardFilter>;
15#[doc = "Register StandardFilter `reset()`'s with value 0xC0000"]
16impl generic::ResetValue for super::StandardFilter {
17 type Type = super::StandardFilterType;
18 #[inline(always)]
19 fn reset_value() -> Self::Type {
20 // Sets filter element to Disabled
21 0xC000
22 }
23}
24
25#[doc = "Reader of field `SFID2`"]
26pub(crate) type SFID2_R = generic::R<u16, u16>;
27#[doc = "Write proxy for field `SFID2`"]
28pub(crate) struct SFID2_W<'a> {
29 w: &'a mut W,
30}
31impl<'a> SFID2_W<'a> {
32 #[doc = r"Writes raw bits to the field"]
33 #[inline(always)]
34 pub unsafe fn bits(self, value: u16) -> &'a mut W {
35 self.w.bits = (self.w.bits & !(0x07ff)) | ((value as u32) & 0x07ff);
36 self.w
37 }
38}
39
40#[doc = "Reader of field `SFID1`"]
41pub(crate) type SFID1_R = generic::R<u16, u16>;
42#[doc = "Write proxy for field `SFID1`"]
43pub(crate) struct SFID1_W<'a> {
44 w: &'a mut W,
45}
46impl<'a> SFID1_W<'a> {
47 #[doc = r"Writes raw bits to the field"]
48 #[inline(always)]
49 pub unsafe fn bits(self, value: u16) -> &'a mut W {
50 self.w.bits = (self.w.bits & !(0x07ff << 16)) | (((value as u32) & 0x07ff) << 16);
51 self.w
52 }
53}
54
55#[doc = "Write proxy for field `SFEC`"]
56pub(crate) struct SFEC_W<'a> {
57 w: &'a mut W,
58}
59impl<'a> SFEC_W<'a> {
60 #[doc = r"Writes raw bits to the field"]
61 #[inline(always)]
62 pub unsafe fn bits(self, value: u8) -> &'a mut W {
63 self.w.bits = (self.w.bits & !(0x07 << 27)) | (((value as u32) & 0x07) << 27);
64 self.w
65 }
66 #[doc = r"Sets the field according to FilterElementConfig"]
67 #[inline(always)]
68 pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W {
69 //SAFETY: FilterElementConfig only be valid options
70 unsafe { self.bits(fec as u8) }
71 }
72}
73
74#[doc = "Write proxy for field `SFT`"]
75pub(crate) struct SFT_W<'a> {
76 w: &'a mut W,
77}
78impl<'a> SFT_W<'a> {
79 #[doc = r"Sets the field according the FilterType"]
80 #[inline(always)]
81 pub fn set_filter_type(self, filter: FilterType) -> &'a mut W {
82 //SAFETY: FilterType only be valid options
83 unsafe { self.bits(filter as u8) }
84 }
85 #[doc = r"Writes raw bits to the field"]
86 #[inline(always)]
87 pub unsafe fn bits(self, value: u8) -> &'a mut W {
88 self.w.bits = (self.w.bits & !(0x03 << 30)) | (((value as u32) & 0x03) << 30);
89 self.w
90 }
91}
92
93impl R {
94 #[doc = "Bits 0:10 - SFID2"]
95 #[inline(always)]
96 pub fn sfid2(&self) -> SFID2_R {
97 SFID2_R::new((self.bits & 0x07ff) as u16)
98 }
99 #[doc = "Bits 16:26 - SFID1"]
100 #[inline(always)]
101 pub fn sfid1(&self) -> SFID1_R {
102 SFID1_R::new(((self.bits >> 16) & 0x07ff) as u16)
103 }
104 #[doc = "Bits 27:29 - SFEC"]
105 #[inline(always)]
106 pub fn sfec(&self) -> ESFEC_R {
107 ESFEC_R::new(((self.bits >> 27) & 0x07) as u8)
108 }
109 #[doc = "Bits 30:31 - SFT"]
110 #[inline(always)]
111 pub fn sft(&self) -> ESFT_R {
112 ESFT_R::new(((self.bits >> 30) & 0x03) as u8)
113 }
114}
115impl W {
116 #[doc = "Bits 0:10 - SFID2"]
117 #[inline(always)]
118 pub fn sfid2(&mut self) -> SFID2_W {
119 SFID2_W { w: self }
120 }
121 #[doc = "Bits 16:26 - SFID1"]
122 #[inline(always)]
123 pub fn sfid1(&mut self) -> SFID1_W {
124 SFID1_W { w: self }
125 }
126 #[doc = "Bits 27:29 - SFEC"]
127 #[inline(always)]
128 pub fn sfec(&mut self) -> SFEC_W {
129 SFEC_W { w: self }
130 }
131 #[doc = "Bits 30:31 - SFT"]
132 #[inline(always)]
133 pub fn sft(&mut self) -> SFT_W {
134 SFT_W { w: self }
135 }
136}
diff --git a/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs
new file mode 100644
index 000000000..455406a1c
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs
@@ -0,0 +1,433 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R};
8use super::enums::{
9 BitRateSwitching, DataLength, ErrorStateIndicator, Event, EventControl, FrameFormat, IdType,
10 RemoteTransmissionRequest,
11};
12use super::generic;
13
14#[doc = "Reader of register TxBufferElement"]
15pub(crate) type R = generic::R<super::TxBufferElementHeaderType, super::TxBufferElementHeader>;
16#[doc = "Writer for register TxBufferElement"]
17pub(crate) type W = generic::W<super::TxBufferElementHeaderType, super::TxBufferElementHeader>;
18impl generic::ResetValue for super::TxBufferElementHeader {
19 type Type = super::TxBufferElementHeaderType;
20
21 #[allow(dead_code)]
22 #[inline(always)]
23 fn reset_value() -> Self::Type {
24 [0; 2]
25 }
26}
27
28#[doc = "Write proxy for field `ESI`"]
29pub(crate) struct ESI_W<'a> {
30 w: &'a mut W,
31}
32impl<'a> ESI_W<'a> {
33 #[doc = r"Writes `variant` to the field"]
34 #[inline(always)]
35 #[allow(dead_code)]
36 pub fn set_error_indicator(self, esi: ErrorStateIndicator) -> &'a mut W {
37 self.bit(esi as u8 != 0)
38 }
39
40 #[doc = r"Sets the field bit"]
41 #[inline(always)]
42 #[allow(dead_code)]
43 pub fn set_bit(self) -> &'a mut W {
44 self.bit(true)
45 }
46 #[doc = r"Clears the field bit"]
47 #[inline(always)]
48 #[allow(dead_code)]
49 pub fn clear_bit(self) -> &'a mut W {
50 self.bit(false)
51 }
52 #[doc = r"Writes raw bits to the field"]
53 #[inline(always)]
54 #[allow(dead_code)]
55 pub fn bit(self, value: bool) -> &'a mut W {
56 self.w.bits[0] = (self.w.bits[0] & !(0x01 << 31)) | (((value as u32) & 0x01) << 31);
57 self.w
58 }
59}
60
61#[doc = "Write proxy for field `XTD`"]
62pub(crate) struct XTD_W<'a> {
63 w: &'a mut W,
64}
65impl<'a> XTD_W<'a> {
66 #[doc = r"Writes `variant` to the field"]
67 #[inline(always)]
68 #[allow(dead_code)]
69 pub fn set_id_type(self, idt: IdType) -> &'a mut W {
70 self.bit(idt as u8 != 0)
71 }
72
73 #[doc = r"Sets the field bit"]
74 #[inline(always)]
75 #[allow(dead_code)]
76 pub fn set_bit(self) -> &'a mut W {
77 self.bit(true)
78 }
79 #[doc = r"Clears the field bit"]
80 #[inline(always)]
81 #[allow(dead_code)]
82 pub fn clear_bit(self) -> &'a mut W {
83 self.bit(false)
84 }
85 #[doc = r"Writes raw bits to the field"]
86 #[inline(always)]
87 #[allow(dead_code)]
88 pub fn bit(self, value: bool) -> &'a mut W {
89 self.w.bits[0] = (self.w.bits[0] & !(0x01 << 30)) | (((value as u32) & 0x01) << 30);
90 self.w
91 }
92}
93
94#[doc = "Write proxy for field `RTR`"]
95pub(crate) struct RTR_W<'a> {
96 w: &'a mut W,
97}
98impl<'a> RTR_W<'a> {
99 #[doc = r"Writes `variant` to the field"]
100 #[inline(always)]
101 #[allow(dead_code)]
102 pub fn set_rtr(self, rtr: RemoteTransmissionRequest) -> &'a mut W {
103 self.bit(rtr as u8 != 0)
104 }
105
106 #[doc = r"Sets the field bit"]
107 #[inline(always)]
108 #[allow(dead_code)]
109 pub fn set_bit(self) -> &'a mut W {
110 self.bit(true)
111 }
112 #[doc = r"Clears the field bit"]
113 #[inline(always)]
114 #[allow(dead_code)]
115 pub fn clear_bit(self) -> &'a mut W {
116 self.bit(false)
117 }
118 #[doc = r"Writes raw bits to the field"]
119 #[inline(always)]
120 #[allow(dead_code)]
121 pub fn bit(self, value: bool) -> &'a mut W {
122 self.w.bits[0] = (self.w.bits[0] & !(0x01 << 29)) | (((value as u32) & 0x01) << 29);
123 self.w
124 }
125}
126
127#[doc = "Write proxy for field `ID`"]
128pub(crate) struct ID_W<'a> {
129 w: &'a mut W,
130}
131impl<'a> ID_W<'a> {
132 #[doc = r"Writes raw bits to the field"]
133 #[inline(always)]
134 #[allow(dead_code)]
135 pub unsafe fn bits(self, value: u32) -> &'a mut W {
136 self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF);
137 self.w
138 }
139}
140
141#[doc = "Write proxy for field `DLC`"]
142pub(crate) struct DLC_W<'a> {
143 w: &'a mut W,
144}
145impl<'a> DLC_W<'a> {
146 #[doc = r"Writes raw bits to the field"]
147 #[inline(always)]
148 #[allow(dead_code)]
149 pub unsafe fn bits(self, value: u8) -> &'a mut W {
150 self.w.bits[1] = (self.w.bits[1] & !(0x0F << 16)) | (((value as u32) & 0x0F) << 16);
151 self.w
152 }
153}
154
155#[doc = "Write proxy for field `BRS`"]
156pub(crate) struct BRS_W<'a> {
157 w: &'a mut W,
158}
159impl<'a> BRS_W<'a> {
160 #[doc = r"Writes `variant` to the field"]
161 #[inline(always)]
162 #[allow(dead_code)]
163 pub fn set_brs(self, brs: BitRateSwitching) -> &'a mut W {
164 self.bit(brs as u8 != 0)
165 }
166
167 #[doc = r"Sets the field bit"]
168 #[inline(always)]
169 #[allow(dead_code)]
170 pub fn set_bit(self) -> &'a mut W {
171 self.bit(true)
172 }
173 #[doc = r"Clears the field bit"]
174 #[inline(always)]
175 #[allow(dead_code)]
176 pub fn clear_bit(self) -> &'a mut W {
177 self.bit(false)
178 }
179 #[doc = r"Writes raw bits to the field"]
180 #[inline(always)]
181 #[allow(dead_code)]
182 pub fn bit(self, value: bool) -> &'a mut W {
183 self.w.bits[1] = (self.w.bits[1] & !(0x01 << 20)) | (((value as u32) & 0x01) << 20);
184 self.w
185 }
186}
187
188#[doc = "Write proxy for field `FDF`"]
189pub(crate) struct FDF_W<'a> {
190 w: &'a mut W,
191}
192impl<'a> FDF_W<'a> {
193 #[doc = r"Writes `variant` to the field"]
194 #[inline(always)]
195 #[allow(dead_code)]
196 pub fn set_format(self, fdf: FrameFormat) -> &'a mut W {
197 self.bit(fdf as u8 != 0)
198 }
199
200 #[doc = r"Sets the field bit"]
201 #[inline(always)]
202 #[allow(dead_code)]
203 pub fn set_bit(self) -> &'a mut W {
204 self.bit(true)
205 }
206 #[doc = r"Clears the field bit"]
207 #[inline(always)]
208 #[allow(dead_code)]
209 pub fn clear_bit(self) -> &'a mut W {
210 self.bit(false)
211 }
212 #[doc = r"Writes raw bits to the field"]
213 #[inline(always)]
214 #[allow(dead_code)]
215 pub fn bit(self, value: bool) -> &'a mut W {
216 self.w.bits[1] = (self.w.bits[1] & !(0x01 << 21)) | (((value as u32) & 0x01) << 21);
217 self.w
218 }
219}
220
221#[doc = "Reader of field `EFC`"]
222pub(crate) type EFC_R = generic::R<bool, EventControl>;
223impl EFC_R {
224 pub fn to_event_control(&self) -> EventControl {
225 match self.bit() {
226 false => EventControl::DoNotStore,
227 true => EventControl::Store,
228 }
229 }
230}
231#[doc = "Write proxy for field `EFC`"]
232pub(crate) struct EFC_W<'a> {
233 w: &'a mut W,
234}
235impl<'a> EFC_W<'a> {
236 #[doc = r"Writes `variant` to the field"]
237 #[inline(always)]
238 #[allow(dead_code)]
239 pub fn set_event_control(self, efc: EventControl) -> &'a mut W {
240 self.bit(match efc {
241 EventControl::DoNotStore => false,
242 EventControl::Store => true,
243 })
244 }
245
246 #[doc = r"Sets the field bit"]
247 #[inline(always)]
248 #[allow(dead_code)]
249 pub fn set_bit(self) -> &'a mut W {
250 self.bit(true)
251 }
252 #[doc = r"Clears the field bit"]
253 #[inline(always)]
254 #[allow(dead_code)]
255 pub fn clear_bit(self) -> &'a mut W {
256 self.bit(false)
257 }
258 #[doc = r"Writes raw bits to the field"]
259 #[inline(always)]
260 #[allow(dead_code)]
261 pub fn bit(self, value: bool) -> &'a mut W {
262 self.w.bits[1] = (self.w.bits[1] & !(0x01 << 23)) | (((value as u32) & 0x01) << 23);
263 self.w
264 }
265}
266
267struct Marker(u8);
268impl From<Event> for Marker {
269 fn from(e: Event) -> Marker {
270 match e {
271 Event::NoEvent => Marker(0),
272 Event::Event(mm) => Marker(mm),
273 }
274 }
275}
276
277#[doc = "Reader of field `MM`"]
278pub(crate) type MM_R = generic::R<u8, u8>;
279#[doc = "Write proxy for field `MM`"]
280pub(crate) struct MM_W<'a> {
281 w: &'a mut W,
282}
283impl<'a> MM_W<'a> {
284 #[doc = r"Writes raw bits to the field"]
285 #[inline(always)]
286 pub unsafe fn bits(self, value: u8) -> &'a mut W {
287 self.w.bits[1] = (self.w.bits[1] & !(0x7F << 24)) | (((value as u32) & 0x7F) << 24);
288 self.w
289 }
290
291 fn set_message_marker(self, mm: Marker) -> &'a mut W {
292 unsafe { self.bits(mm.0) }
293 }
294}
295
296impl R {
297 #[doc = "Byte 0 - Bits 0:28 - ID"]
298 #[inline(always)]
299 pub fn id(&self) -> ID_R {
300 ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
301 }
302 #[doc = "Byte 0 - Bit 29 - RTR"]
303 #[inline(always)]
304 pub fn rtr(&self) -> RTR_R {
305 RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
306 }
307 #[doc = "Byte 0 - Bit 30 - XTD"]
308 #[inline(always)]
309 pub fn xtd(&self) -> XTD_R {
310 XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
311 }
312 #[doc = "Byte 0 - Bit 30 - ESI"]
313 #[inline(always)]
314 pub fn esi(&self) -> ESI_R {
315 ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
316 }
317 #[doc = "Byte 1 - Bits 16:19 - DLC"]
318 #[inline(always)]
319 pub fn dlc(&self) -> DLC_R {
320 DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
321 }
322 #[doc = "Byte 1 - Bits 20 - BRS"]
323 #[inline(always)]
324 pub fn brs(&self) -> BRS_R {
325 BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
326 }
327 #[doc = "Byte 1 - Bits 20 - FDF"]
328 #[inline(always)]
329 pub fn fdf(&self) -> FDF_R {
330 FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0)
331 }
332 #[doc = "Byte 1 - Bits 23 - EFC"]
333 #[inline(always)]
334 pub fn efc(&self) -> EFC_R {
335 EFC_R::new(((self.bits[1] >> 23) & 0x01) != 0)
336 }
337 #[doc = "Byte 1 - Bits 24:31 - MM"]
338 #[inline(always)]
339 pub fn mm(&self) -> MM_R {
340 MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
341 }
342 pub fn to_data_length(&self) -> DataLength {
343 let dlc = self.dlc().bits();
344 let ff = self.fdf().frame_format();
345 let len = if ff == FrameFormat::Fdcan {
346 // See RM0433 Rev 7 Table 475. DLC coding
347 match dlc {
348 0..=8 => dlc,
349 9 => 12,
350 10 => 16,
351 11 => 20,
352 12 => 24,
353 13 => 32,
354 14 => 48,
355 15 => 64,
356 _ => panic!("DLC > 15"),
357 }
358 } else {
359 match dlc {
360 0..=8 => dlc,
361 9..=15 => 8,
362 _ => panic!("DLC > 15"),
363 }
364 };
365 DataLength::new(len, ff)
366 }
367 pub fn to_event(&self) -> Event {
368 let mm = self.mm().bits();
369 let efc = self.efc().to_event_control();
370 match efc {
371 EventControl::DoNotStore => Event::NoEvent,
372 EventControl::Store => Event::Event(mm),
373 }
374 }
375}
376impl W {
377 #[doc = "Byte 0 - Bits 0:28 - ID"]
378 #[inline(always)]
379 pub fn id(&mut self) -> ID_W {
380 ID_W { w: self }
381 }
382 #[doc = "Byte 0 - Bit 29 - RTR"]
383 #[inline(always)]
384 pub fn rtr(&mut self) -> RTR_W {
385 RTR_W { w: self }
386 }
387 #[doc = "Byte 0 - Bit 30 - XTD"]
388 #[inline(always)]
389 pub fn xtd(&mut self) -> XTD_W {
390 XTD_W { w: self }
391 }
392 #[doc = "Byte 0 - Bit 31 - ESI"]
393 #[inline(always)]
394 pub fn esi(&mut self) -> ESI_W {
395 ESI_W { w: self }
396 }
397 #[doc = "Byte 1 - Bit 16:19 - DLC"]
398 #[inline(always)]
399 pub fn dlc(&mut self) -> DLC_W {
400 DLC_W { w: self }
401 }
402 #[doc = "Byte 1 - Bit 20 - BRS"]
403 #[inline(always)]
404 pub fn brs(&mut self) -> BRS_W {
405 BRS_W { w: self }
406 }
407 #[doc = "Byte 1 - Bit 21 - FDF"]
408 #[inline(always)]
409 pub fn fdf(&mut self) -> FDF_W {
410 FDF_W { w: self }
411 }
412 #[doc = "Byte 1 - Bit 23 - EFC"]
413 #[inline(always)]
414 pub fn efc(&mut self) -> EFC_W {
415 EFC_W { w: self }
416 }
417 #[doc = "Byte 1 - Bit 24:31 - MM"]
418 #[inline(always)]
419 pub fn mm(&mut self) -> MM_W {
420 MM_W { w: self }
421 }
422 #[doc = "Convenience function for setting the data length and frame format"]
423 #[inline(always)]
424 pub fn set_len(&mut self, dl: impl Into<DataLength>) -> &mut Self {
425 let dl: DataLength = dl.into();
426 self.fdf().set_format(dl.into());
427 unsafe { self.dlc().bits(dl.dlc()) }
428 }
429 pub fn set_event(&mut self, event: Event) -> &mut Self {
430 self.mm().set_message_marker(event.into());
431 self.efc().set_event_control(event.into())
432 }
433}
diff --git a/embassy-stm32/src/can/fd/message_ram/txevent_element.rs b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs
new file mode 100644
index 000000000..817a4449f
--- /dev/null
+++ b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs
@@ -0,0 +1,138 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(unused)]
6
7use super::common::{BRS_R, DLC_R, ESI_R, RTR_R, XTD_R};
8use super::generic;
9
10#[doc = "Reader of register TxEventElement"]
11pub(crate) type R = generic::R<super::TxEventElementType, super::TxEventElement>;
12// #[doc = "Writer for register TxEventElement"]
13// pub(crate) type W = generic::W<super::TxEventElementType, super::TxEventElement>;
14#[doc = "Register TxEventElement `reset()`'s"]
15impl generic::ResetValue for super::TxEventElement {
16 type Type = super::TxEventElementType;
17 #[inline(always)]
18 fn reset_value() -> Self::Type {
19 [0, 0]
20 }
21}
22
23#[doc = "Reader of field `ID`"]
24pub(crate) type ID_R = generic::R<u32, u32>;
25
26#[doc = "Reader of field `TXTS`"]
27pub(crate) type TXTS_R = generic::R<u16, u16>;
28
29#[derive(Clone, Copy, Debug, PartialEq)]
30pub(crate) enum DataLengthFormat {
31 StandardLength = 0,
32 FDCANLength = 1,
33}
34impl From<DataLengthFormat> for bool {
35 #[inline(always)]
36 fn from(dlf: DataLengthFormat) -> Self {
37 dlf as u8 != 0
38 }
39}
40
41#[doc = "Reader of field `EDL`"]
42pub(crate) type EDL_R = generic::R<bool, DataLengthFormat>;
43impl EDL_R {
44 pub fn data_length_format(&self) -> DataLengthFormat {
45 match self.bits() {
46 false => DataLengthFormat::StandardLength,
47 true => DataLengthFormat::FDCANLength,
48 }
49 }
50 pub fn is_standard_length(&self) -> bool {
51 *self == DataLengthFormat::StandardLength
52 }
53 pub fn is_fdcan_length(&self) -> bool {
54 *self == DataLengthFormat::FDCANLength
55 }
56}
57
58#[derive(Clone, Copy, Debug, PartialEq)]
59pub(crate) enum EventType {
60 //_Reserved = 0b00,
61 TxEvent = 0b01,
62 TxDespiteAbort = 0b10,
63 //_Reserved = 0b10,
64}
65
66#[doc = "Reader of field `EFC`"]
67pub(crate) type EFC_R = generic::R<u8, EventType>;
68impl EFC_R {
69 pub fn event_type(&self) -> EventType {
70 match self.bits() {
71 0b01 => EventType::TxEvent,
72 0b10 => EventType::TxDespiteAbort,
73 _ => unimplemented!(),
74 }
75 }
76 pub fn is_tx_event(&self) -> bool {
77 self.event_type() == EventType::TxEvent
78 }
79 pub fn is_despite_abort(&self) -> bool {
80 self.event_type() == EventType::TxDespiteAbort
81 }
82}
83
84#[doc = "Reader of field `MM`"]
85pub(crate) type MM_R = generic::R<u8, u8>;
86
87impl R {
88 #[doc = "Byte 0 - Bits 0:28 - ID"]
89 #[inline(always)]
90 pub fn id(&self) -> ID_R {
91 ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32)
92 }
93 #[doc = "Byte 0 - Bit 29 - RTR"]
94 #[inline(always)]
95 pub fn rtr(&self) -> RTR_R {
96 RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0)
97 }
98 #[doc = "Byte 0 - Bit 30 - XTD"]
99 #[inline(always)]
100 pub fn xtd(&self) -> XTD_R {
101 XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0)
102 }
103 #[doc = "Byte 0 - Bit 30 - ESI"]
104 #[inline(always)]
105 pub fn esi(&self) -> ESI_R {
106 ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0)
107 }
108 #[doc = "Byte 1 - Bits 0:15 - TXTS"]
109 #[inline(always)]
110 pub fn txts(&self) -> TXTS_R {
111 TXTS_R::new(((self.bits[1]) & 0xFFFF) as u16)
112 }
113 #[doc = "Byte 1 - Bits 16:19 - DLC"]
114 #[inline(always)]
115 pub fn dlc(&self) -> DLC_R {
116 DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8)
117 }
118 #[doc = "Byte 1 - Bits 20 - BRS"]
119 #[inline(always)]
120 pub fn brs(&self) -> BRS_R {
121 BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0)
122 }
123 #[doc = "Byte 1 - Bits 21 - EDL"]
124 #[inline(always)]
125 pub fn edl(&self) -> EDL_R {
126 EDL_R::new(((self.bits[1] >> 21) & 0x01) != 0)
127 }
128 #[doc = "Byte 1 - Bits 22:23 - EFC"]
129 #[inline(always)]
130 pub fn efc(&self) -> EFC_R {
131 EFC_R::new(((self.bits[1] >> 22) & 0x03) as u8)
132 }
133 #[doc = "Byte 1 - Bits 24:31 - MM"]
134 #[inline(always)]
135 pub fn mm(&self) -> MM_R {
136 MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8)
137 }
138}
diff --git a/embassy-stm32/src/can/fd/mod.rs b/embassy-stm32/src/can/fd/mod.rs
new file mode 100644
index 000000000..271ca0b3c
--- /dev/null
+++ b/embassy-stm32/src/can/fd/mod.rs
@@ -0,0 +1,6 @@
1//! Module containing that which is specific to fdcan hardware variant
2
3pub mod config;
4pub mod filter;
5pub(crate) mod message_ram;
6pub(crate) mod peripheral;
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
new file mode 100644
index 000000000..8ec09ac12
--- /dev/null
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -0,0 +1,788 @@
1// Note: This file is copied and modified from fdcan crate by Richard Meadows
2
3use core::convert::Infallible;
4use core::slice;
5
6use cfg_if::cfg_if;
7
8use crate::can::enums::*;
9use crate::can::fd::config::*;
10use crate::can::fd::message_ram::enums::*;
11use crate::can::fd::message_ram::{RegisterBlock, RxFifoElement, TxBufferElement};
12use crate::can::frame::*;
13
14/// Loopback Mode
15#[derive(Clone, Copy, Debug)]
16enum LoopbackMode {
17 None,
18 Internal,
19 External,
20}
21
22pub struct Registers {
23 pub regs: &'static crate::pac::can::Fdcan,
24 pub msgram: &'static crate::pac::fdcanram::Fdcanram,
25 pub msg_ram_offset: usize,
26}
27
28impl Registers {
29 fn tx_buffer_element(&self, bufidx: usize) -> &mut TxBufferElement {
30 &mut self.msg_ram_mut().transmit.tbsa[bufidx]
31 }
32 pub fn msg_ram_mut(&self) -> &mut RegisterBlock {
33 let ptr = self.msgram.as_ptr() as *mut RegisterBlock;
34 unsafe { &mut (*ptr) }
35 }
36
37 fn rx_fifo_element(&self, fifonr: usize, bufnum: usize) -> &mut RxFifoElement {
38 &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum]
39 }
40
41 pub fn read<F: CanHeader>(&self, fifonr: usize) -> Option<(F, u16)> {
42 // Fill level - do we have a msg?
43 if self.regs.rxfs(fifonr).read().ffl() < 1 {
44 return None;
45 }
46
47 let read_idx = self.regs.rxfs(fifonr).read().fgi();
48 let mailbox = self.rx_fifo_element(fifonr, read_idx as usize);
49
50 let mut buffer = [0u8; 64];
51 let maybe_header = extract_frame(mailbox, &mut buffer);
52
53 // Clear FIFO, reduces count and increments read buf
54 self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx));
55
56 match maybe_header {
57 Some((header, ts)) => {
58 let data = &buffer[0..header.len() as usize];
59 Some((F::from_header(header, data)?, ts))
60 }
61 None => None,
62 }
63 }
64
65 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
66 let mailbox = self.tx_buffer_element(bufidx);
67
68 mailbox.reset();
69 put_tx_header(mailbox, header);
70 put_tx_data(mailbox, &buffer[..header.len() as usize]);
71
72 // Set <idx as Mailbox> as ready to transmit
73 self.regs.txbar().modify(|w| w.set_ar(bufidx, true));
74 }
75
76 fn reg_to_error(value: u8) -> Option<BusError> {
77 match value {
78 //0b000 => None,
79 0b001 => Some(BusError::Stuff),
80 0b010 => Some(BusError::Form),
81 0b011 => Some(BusError::Acknowledge),
82 0b100 => Some(BusError::BitRecessive),
83 0b101 => Some(BusError::BitDominant),
84 0b110 => Some(BusError::Crc),
85 //0b111 => Some(BusError::NoError),
86 _ => None,
87 }
88 }
89
90 pub fn curr_error(&self) -> Option<BusError> {
91 let err = { self.regs.psr().read() };
92 if err.bo() {
93 return Some(BusError::BusOff);
94 } else if err.ep() {
95 return Some(BusError::BusPassive);
96 } else if err.ew() {
97 return Some(BusError::BusWarning);
98 } else {
99 cfg_if! {
100 if #[cfg(stm32h7)] {
101 let lec = err.lec();
102 } else {
103 let lec = err.lec().to_bits();
104 }
105 }
106 if let Some(err) = Self::reg_to_error(lec) {
107 return Some(err);
108 }
109 }
110 None
111 }
112 /// Returns if the tx queue is able to accept new messages without having to cancel an existing one
113 #[inline]
114 pub fn tx_queue_is_full(&self) -> bool {
115 self.regs.txfqs().read().tfqf()
116 }
117
118 /// Returns the current TX buffer operation mode (queue or FIFO)
119 #[inline]
120 pub fn tx_queue_mode(&self) -> TxBufferMode {
121 self.regs.txbc().read().tfqm().into()
122 }
123
124 #[inline]
125 pub fn has_pending_frame(&self, idx: usize) -> bool {
126 self.regs.txbrp().read().trp(idx)
127 }
128
129 /// Returns `Ok` when the mailbox is free or if it contains pending frame with a
130 /// lower priority (higher ID) than the identifier `id`.
131 #[inline]
132 pub fn is_available(&self, bufidx: usize, id: &embedded_can::Id) -> bool {
133 if self.has_pending_frame(bufidx) {
134 let mailbox = self.tx_buffer_element(bufidx);
135
136 let header_reg = mailbox.header.read();
137 let old_id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
138
139 *id > old_id
140 } else {
141 true
142 }
143 }
144
145 /// Attempts to abort the sending of a frame that is pending in a mailbox.
146 ///
147 /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
148 /// aborted, this function has no effect and returns `false`.
149 ///
150 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
151 /// returns `true`.
152 #[inline]
153 pub fn abort(&self, bufidx: usize) -> bool {
154 let can = self.regs;
155
156 // Check if there is a request pending to abort
157 if self.has_pending_frame(bufidx) {
158 // Abort Request
159 can.txbcr().write(|w| w.set_cr(bufidx, true));
160
161 // Wait for the abort request to be finished.
162 loop {
163 if can.txbcf().read().cf(bufidx) {
164 // Return false when a transmission has occured
165 break can.txbto().read().to(bufidx) == false;
166 }
167 }
168 } else {
169 false
170 }
171 }
172
173 #[inline]
174 fn abort_pending_mailbox<F: embedded_can::Frame>(&self, bufidx: usize) -> Option<F> {
175 if self.abort(bufidx) {
176 let mailbox = self.tx_buffer_element(bufidx);
177
178 let header_reg = mailbox.header.read();
179 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
180
181 let len = match header_reg.to_data_length() {
182 DataLength::Fdcan(len) => len,
183 DataLength::Classic(len) => len,
184 };
185 if len as usize > ClassicFrame::MAX_DATA_LEN {
186 return None;
187 }
188
189 let mut data = [0u8; 64];
190 data_from_tx_buffer(&mut data, mailbox, len as usize);
191
192 if header_reg.rtr().bit() {
193 F::new_remote(id, len as usize)
194 } else {
195 F::new(id, &data)
196 }
197 } else {
198 // Abort request failed because the frame was already sent (or being sent) on
199 // the bus. All mailboxes are now free. This can happen for small prescaler
200 // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
201 // has preempted the execution.
202 None
203 }
204 }
205
206 pub fn write<F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> nb::Result<Option<F>, Infallible> {
207 let (idx, pending_frame) = if self.tx_queue_is_full() {
208 if self.tx_queue_mode() == TxBufferMode::Fifo {
209 // Does not make sense to cancel a pending frame when using FIFO
210 return Err(nb::Error::WouldBlock);
211 }
212 // If the queue is full,
213 // Discard the first slot with a lower priority message
214 let id = frame.header().id();
215 if self.is_available(0, id) {
216 (0, self.abort_pending_mailbox(0))
217 } else if self.is_available(1, id) {
218 (1, self.abort_pending_mailbox(1))
219 } else if self.is_available(2, id) {
220 (2, self.abort_pending_mailbox(2))
221 } else {
222 // For now we bail when there is no lower priority slot available
223 // Can this lead to priority inversion?
224 return Err(nb::Error::WouldBlock);
225 }
226 } else {
227 // Read the Write Pointer
228 let idx = self.regs.txfqs().read().tfqpi();
229
230 (idx, None)
231 };
232
233 self.put_tx_frame(idx as usize, frame.header(), frame.data());
234
235 Ok(pending_frame)
236 }
237
238 #[inline]
239 fn reset_msg_ram(&mut self) {
240 self.msg_ram_mut().reset();
241 }
242
243 #[inline]
244 fn enter_init_mode(&mut self) {
245 self.regs.cccr().modify(|w| w.set_init(true));
246 while false == self.regs.cccr().read().init() {}
247 self.regs.cccr().modify(|w| w.set_cce(true));
248 }
249
250 /// Enables or disables loopback mode: Internally connects the TX and RX
251 /// signals together.
252 #[inline]
253 fn set_loopback_mode(&mut self, mode: LoopbackMode) {
254 let (test, mon, lbck) = match mode {
255 LoopbackMode::None => (false, false, false),
256 LoopbackMode::Internal => (true, true, true),
257 LoopbackMode::External => (true, false, true),
258 };
259
260 self.set_test_mode(test);
261 self.set_bus_monitoring_mode(mon);
262
263 self.regs.test().modify(|w| w.set_lbck(lbck));
264 }
265
266 /// Enables or disables silent mode: Disconnects the TX signal from the pin.
267 #[inline]
268 fn set_bus_monitoring_mode(&mut self, enabled: bool) {
269 self.regs.cccr().modify(|w| w.set_mon(enabled));
270 }
271
272 #[inline]
273 fn set_restricted_operations(&mut self, enabled: bool) {
274 self.regs.cccr().modify(|w| w.set_asm(enabled));
275 }
276
277 #[inline]
278 fn set_normal_operations(&mut self, _enabled: bool) {
279 self.set_loopback_mode(LoopbackMode::None);
280 }
281
282 #[inline]
283 fn set_test_mode(&mut self, enabled: bool) {
284 self.regs.cccr().modify(|w| w.set_test(enabled));
285 }
286
287 #[inline]
288 fn set_power_down_mode(&mut self, enabled: bool) {
289 self.regs.cccr().modify(|w| w.set_csr(enabled));
290 while self.regs.cccr().read().csa() != enabled {}
291 }
292
293 /// Moves out of PoweredDownMode and into ConfigMode
294 #[inline]
295 pub fn into_config_mode(mut self, _config: FdCanConfig) {
296 self.set_power_down_mode(false);
297 self.enter_init_mode();
298 self.reset_msg_ram();
299
300 // check the FDCAN core matches our expections
301 assert!(
302 self.regs.crel().read().rel() == 3,
303 "Expected FDCAN core major release 3"
304 );
305 assert!(
306 self.regs.endn().read().etv() == 0x87654321_u32,
307 "Error reading endianness test value from FDCAN core"
308 );
309
310 /*
311 for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX {
312 self.set_standard_filter((fid as u8).into(), StandardFilter::disable());
313 }
314 for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX {
315 self.set_extended_filter(fid.into(), ExtendedFilter::disable());
316 }
317 */
318 }
319
320 /// Disables the CAN interface and returns back the raw peripheral it was created from.
321 #[inline]
322 pub fn free(mut self) {
323 //self.disable_interrupts(Interrupts::all());
324
325 //TODO check this!
326 self.enter_init_mode();
327 self.set_power_down_mode(true);
328 //self.control.instance
329 }
330
331 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
332 #[inline]
333 pub fn apply_config(&mut self, config: FdCanConfig) {
334 self.set_tx_buffer_mode(config.tx_buffer_mode);
335
336 // set standard filters list size to 28
337 // set extended filters list size to 8
338 // REQUIRED: we use the memory map as if these settings are set
339 // instead of re-calculating them.
340 #[cfg(not(stm32h7))]
341 {
342 self.regs.rxgfc().modify(|w| {
343 w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX);
344 w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX);
345 });
346 }
347 #[cfg(stm32h7)]
348 {
349 self.regs
350 .sidfc()
351 .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX));
352 self.regs
353 .xidfc()
354 .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX));
355 }
356
357 self.configure_msg_ram();
358
359 // Enable timestamping
360 #[cfg(not(stm32h7))]
361 self.regs
362 .tscc()
363 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
364 #[cfg(stm32h7)]
365 self.regs.tscc().write(|w| w.set_tss(0x01));
366
367 // this isn't really documented in the reference manual
368 // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire
369 self.regs.txbtie().write(|w| w.0 = 0xffff_ffff);
370 self.regs.ie().modify(|w| {
371 w.set_rfne(0, true); // Rx Fifo 0 New Msg
372 w.set_rfne(1, true); // Rx Fifo 1 New Msg
373 w.set_tce(true); // Tx Complete
374 });
375 self.regs.ile().modify(|w| {
376 w.set_eint0(true); // Interrupt Line 0
377 w.set_eint1(true); // Interrupt Line 1
378 });
379
380 self.set_data_bit_timing(config.dbtr);
381 self.set_nominal_bit_timing(config.nbtr);
382 self.set_automatic_retransmit(config.automatic_retransmit);
383 self.set_transmit_pause(config.transmit_pause);
384 self.set_frame_transmit(config.frame_transmit);
385 //self.set_interrupt_line_config(config.interrupt_line_config);
386 self.set_non_iso_mode(config.non_iso_mode);
387 self.set_edge_filtering(config.edge_filtering);
388 self.set_protocol_exception_handling(config.protocol_exception_handling);
389 self.set_global_filter(config.global_filter);
390 }
391
392 #[inline]
393 fn leave_init_mode(&mut self, config: FdCanConfig) {
394 self.apply_config(config);
395
396 self.regs.cccr().modify(|w| w.set_cce(false));
397 self.regs.cccr().modify(|w| w.set_init(false));
398 while self.regs.cccr().read().init() == true {}
399 }
400
401 /// Moves out of ConfigMode and into specified mode
402 #[inline]
403 pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) {
404 match mode {
405 crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
406 crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
407 crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true),
408 crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
409 crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
410 }
411 self.leave_init_mode(config);
412 }
413
414 /// Moves out of ConfigMode and into InternalLoopbackMode
415 #[inline]
416 pub fn into_internal_loopback(mut self, config: FdCanConfig) {
417 self.set_loopback_mode(LoopbackMode::Internal);
418 self.leave_init_mode(config);
419 }
420
421 /// Moves out of ConfigMode and into ExternalLoopbackMode
422 #[inline]
423 pub fn into_external_loopback(mut self, config: FdCanConfig) {
424 self.set_loopback_mode(LoopbackMode::External);
425 self.leave_init_mode(config);
426 }
427
428 /// Moves out of ConfigMode and into RestrictedOperationMode
429 #[inline]
430 pub fn into_restricted(mut self, config: FdCanConfig) {
431 self.set_restricted_operations(true);
432 self.leave_init_mode(config);
433 }
434
435 /// Moves out of ConfigMode and into NormalOperationMode
436 #[inline]
437 pub fn into_normal(mut self, config: FdCanConfig) {
438 self.set_normal_operations(true);
439 self.leave_init_mode(config);
440 }
441
442 /// Moves out of ConfigMode and into BusMonitoringMode
443 #[inline]
444 pub fn into_bus_monitoring(mut self, config: FdCanConfig) {
445 self.set_bus_monitoring_mode(true);
446 self.leave_init_mode(config);
447 }
448
449 /// Moves out of ConfigMode and into Testmode
450 #[inline]
451 pub fn into_test_mode(mut self, config: FdCanConfig) {
452 self.set_test_mode(true);
453 self.leave_init_mode(config);
454 }
455
456 /// Moves out of ConfigMode and into PoweredDownmode
457 #[inline]
458 pub fn into_powered_down(mut self, config: FdCanConfig) {
459 self.set_power_down_mode(true);
460 self.leave_init_mode(config);
461 }
462
463 /// Configures the bit timings.
464 ///
465 /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
466 /// parameters as follows:
467 ///
468 /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
469 /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
470 /// - *Sample Point*: Should normally be left at the default value of 87.5%.
471 /// - *SJW*: Should normally be left at the default value of 1.
472 ///
473 /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
474 /// parameter to this method.
475 #[inline]
476 pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) {
477 self.regs.nbtp().write(|w| {
478 w.set_nbrp(btr.nbrp() - 1);
479 w.set_ntseg1(btr.ntseg1() - 1);
480 w.set_ntseg2(btr.ntseg2() - 1);
481 w.set_nsjw(btr.nsjw() - 1);
482 });
483 }
484
485 /// Configures the data bit timings for the FdCan Variable Bitrates.
486 /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
487 #[inline]
488 pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) {
489 self.regs.dbtp().write(|w| {
490 w.set_dbrp(btr.dbrp() - 1);
491 w.set_dtseg1(btr.dtseg1() - 1);
492 w.set_dtseg2(btr.dtseg2() - 1);
493 w.set_dsjw(btr.dsjw() - 1);
494 });
495 }
496
497 /// Enables or disables automatic retransmission of messages
498 ///
499 /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
500 /// util it can be sent. Otherwise, it will try only once to send each frame.
501 ///
502 /// Automatic retransmission is enabled by default.
503 #[inline]
504 pub fn set_automatic_retransmit(&mut self, enabled: bool) {
505 self.regs.cccr().modify(|w| w.set_dar(!enabled));
506 }
507
508 /// Configures the transmit pause feature. See
509 /// [`FdCanConfig::set_transmit_pause`]
510 #[inline]
511 pub fn set_transmit_pause(&mut self, enabled: bool) {
512 self.regs.cccr().modify(|w| w.set_txp(!enabled));
513 }
514
515 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
516 #[inline]
517 pub fn set_non_iso_mode(&mut self, enabled: bool) {
518 self.regs.cccr().modify(|w| w.set_niso(enabled));
519 }
520
521 /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`]
522 #[inline]
523 pub fn set_edge_filtering(&mut self, enabled: bool) {
524 self.regs.cccr().modify(|w| w.set_efbi(enabled));
525 }
526
527 /// Configures TX Buffer Mode
528 #[inline]
529 pub fn set_tx_buffer_mode(&mut self, tbm: TxBufferMode) {
530 self.regs.txbc().write(|w| w.set_tfqm(tbm.into()));
531 }
532
533 /// Configures frame transmission mode. See
534 /// [`FdCanConfig::set_frame_transmit`]
535 #[inline]
536 pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) {
537 let (fdoe, brse) = match fts {
538 FrameTransmissionConfig::ClassicCanOnly => (false, false),
539 FrameTransmissionConfig::AllowFdCan => (true, false),
540 FrameTransmissionConfig::AllowFdCanAndBRS => (true, true),
541 };
542
543 self.regs.cccr().modify(|w| {
544 w.set_fdoe(fdoe);
545 #[cfg(stm32h7)]
546 w.set_bse(brse);
547 #[cfg(not(stm32h7))]
548 w.set_brse(brse);
549 });
550 }
551
552 /// Sets the protocol exception handling on/off
553 #[inline]
554 pub fn set_protocol_exception_handling(&mut self, enabled: bool) {
555 self.regs.cccr().modify(|w| w.set_pxhd(!enabled));
556 }
557
558 /// Configures and resets the timestamp counter
559 #[inline]
560 pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) {
561 #[cfg(stm32h7)]
562 let (tcp, tss) = match select {
563 TimestampSource::None => (0, 0),
564 TimestampSource::Prescaler(p) => (p as u8, 1),
565 TimestampSource::FromTIM3 => (0, 2),
566 };
567
568 #[cfg(not(stm32h7))]
569 let (tcp, tss) = match select {
570 TimestampSource::None => (0, stm32_metapac::can::vals::Tss::ZERO),
571 TimestampSource::Prescaler(p) => (p as u8, stm32_metapac::can::vals::Tss::INCREMENT),
572 TimestampSource::FromTIM3 => (0, stm32_metapac::can::vals::Tss::EXTERNAL),
573 };
574
575 self.regs.tscc().write(|w| {
576 w.set_tcp(tcp);
577 w.set_tss(tss);
578 });
579 }
580
581 #[cfg(not(stm32h7))]
582 /// Configures the global filter settings
583 #[inline]
584 pub fn set_global_filter(&mut self, filter: GlobalFilter) {
585 let anfs = match filter.handle_standard_frames {
586 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0,
587 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1,
588 crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfs::REJECT,
589 };
590 let anfe = match filter.handle_extended_frames {
591 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_0,
592 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_1,
593 crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfe::REJECT,
594 };
595
596 self.regs.rxgfc().modify(|w| {
597 w.set_anfs(anfs);
598 w.set_anfe(anfe);
599 w.set_rrfs(filter.reject_remote_standard_frames);
600 w.set_rrfe(filter.reject_remote_extended_frames);
601 });
602 }
603
604 #[cfg(stm32h7)]
605 /// Configures the global filter settings
606 #[inline]
607 pub fn set_global_filter(&mut self, filter: GlobalFilter) {
608 let anfs = match filter.handle_standard_frames {
609 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
610 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
611 crate::can::fd::config::NonMatchingFilter::Reject => 2,
612 };
613
614 let anfe = match filter.handle_extended_frames {
615 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
616 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
617 crate::can::fd::config::NonMatchingFilter::Reject => 2,
618 };
619
620 self.regs.gfc().modify(|w| {
621 w.set_anfs(anfs);
622 w.set_anfe(anfe);
623 w.set_rrfs(filter.reject_remote_standard_frames);
624 w.set_rrfe(filter.reject_remote_extended_frames);
625 });
626 }
627
628 #[cfg(not(stm32h7))]
629 fn configure_msg_ram(&mut self) {}
630
631 #[cfg(stm32h7)]
632 fn configure_msg_ram(&mut self) {
633 let r = self.regs;
634
635 use crate::can::fd::message_ram::*;
636 //use fdcan::message_ram::*;
637 let mut offset_words = self.msg_ram_offset as u16;
638
639 // 11-bit filter
640 r.sidfc().modify(|w| w.set_flssa(offset_words));
641 offset_words += STANDARD_FILTER_MAX as u16;
642
643 // 29-bit filter
644 r.xidfc().modify(|w| w.set_flesa(offset_words));
645 offset_words += 2 * EXTENDED_FILTER_MAX as u16;
646
647 // Rx FIFO 0 and 1
648 for i in 0..=1 {
649 r.rxfc(i).modify(|w| {
650 w.set_fsa(offset_words);
651 w.set_fs(RX_FIFO_MAX);
652 w.set_fwm(RX_FIFO_MAX);
653 });
654 offset_words += 18 * RX_FIFO_MAX as u16;
655 }
656
657 // Rx buffer - see below
658 // Tx event FIFO
659 r.txefc().modify(|w| {
660 w.set_efsa(offset_words);
661 w.set_efs(TX_EVENT_MAX);
662 w.set_efwm(TX_EVENT_MAX);
663 });
664 offset_words += 2 * TX_EVENT_MAX as u16;
665
666 // Tx buffers
667 r.txbc().modify(|w| {
668 w.set_tbsa(offset_words);
669 w.set_tfqs(TX_FIFO_MAX);
670 });
671 offset_words += 18 * TX_FIFO_MAX as u16;
672
673 // Rx Buffer - not used
674 r.rxbc().modify(|w| {
675 w.set_rbsa(offset_words);
676 });
677
678 // TX event FIFO?
679 // Trigger memory?
680
681 // Set the element sizes to 16 bytes
682 r.rxesc().modify(|w| {
683 w.set_rbds(0b111);
684 for i in 0..=1 {
685 w.set_fds(i, 0b111);
686 }
687 });
688 r.txesc().modify(|w| {
689 w.set_tbds(0b111);
690 })
691 }
692}
693
694fn make_id(id: u32, extended: bool) -> embedded_can::Id {
695 if extended {
696 embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) })
697 } else {
698 // A standard identifier is stored into ID[28:18].
699 embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked(((id >> 18) & 0x000007FF) as u16) })
700 }
701}
702
703fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) {
704 let (id, id_type) = match header.id() {
705 // A standard identifier has to be written to ID[28:18].
706 embedded_can::Id::Standard(id) => ((id.as_raw() as u32) << 18, IdType::StandardId),
707 embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId),
708 };
709
710 // Use FDCAN only for DLC > 8. FDCAN users can revise this if required.
711 let frame_format = if header.len() > 8 || header.fdcan() {
712 FrameFormat::Fdcan
713 } else {
714 FrameFormat::Classic
715 };
716 let brs = (frame_format == FrameFormat::Fdcan) && header.bit_rate_switching();
717
718 mailbox.header.write(|w| {
719 unsafe { w.id().bits(id) }
720 .rtr()
721 .bit(header.len() == 0 && header.rtr())
722 .xtd()
723 .set_id_type(id_type)
724 .set_len(DataLength::new(header.len(), frame_format))
725 .set_event(Event::NoEvent)
726 .fdf()
727 .set_format(frame_format)
728 .brs()
729 .bit(brs)
730 //esi.set_error_indicator(//TODO//)
731 });
732}
733
734fn put_tx_data(mailbox: &mut TxBufferElement, buffer: &[u8]) {
735 let mut lbuffer = [0_u32; 16];
736 let len = buffer.len();
737 let data = unsafe { slice::from_raw_parts_mut(lbuffer.as_mut_ptr() as *mut u8, len) };
738 data[..len].copy_from_slice(&buffer[..len]);
739 let data_len = ((len) + 3) / 4;
740 for (register, byte) in mailbox.data.iter_mut().zip(lbuffer[..data_len].iter()) {
741 unsafe { register.write(*byte) };
742 }
743}
744
745fn data_from_fifo(buffer: &mut [u8], mailbox: &RxFifoElement, len: usize) {
746 for (i, register) in mailbox.data.iter().enumerate() {
747 let register_value = register.read();
748 let register_bytes = unsafe { slice::from_raw_parts(&register_value as *const u32 as *const u8, 4) };
749 let num_bytes = (len) - i * 4;
750 if num_bytes <= 4 {
751 buffer[i * 4..i * 4 + num_bytes].copy_from_slice(&register_bytes[..num_bytes]);
752 break;
753 }
754 buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes);
755 }
756}
757
758fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize) {
759 for (i, register) in mailbox.data.iter().enumerate() {
760 let register_value = register.read();
761 let register_bytes = unsafe { slice::from_raw_parts(&register_value as *const u32 as *const u8, 4) };
762 let num_bytes = (len) - i * 4;
763 if num_bytes <= 4 {
764 buffer[i * 4..i * 4 + num_bytes].copy_from_slice(&register_bytes[..num_bytes]);
765 break;
766 }
767 buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes);
768 }
769}
770
771fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> {
772 let header_reg = mailbox.header.read();
773
774 let id = make_id(header_reg.id().bits(), header_reg.xtd().bits());
775 let dlc = header_reg.to_data_length().len();
776 let len = dlc as usize;
777 let timestamp = header_reg.txts().bits;
778 if len > buffer.len() {
779 return None;
780 }
781 data_from_fifo(buffer, mailbox, len);
782 let header = if header_reg.fdf().bits {
783 Header::new_fd(id, dlc, header_reg.rtr().bits(), header_reg.brs().bits())
784 } else {
785 Header::new(id, dlc, header_reg.rtr().bits())
786 };
787 Some((header, timestamp))
788}
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 0cc2559cf..fe8969a5a 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -1,54 +1,951 @@
1use crate::peripherals; 1#[allow(unused_variables)]
2use core::future::poll_fn;
3use core::marker::PhantomData;
4use core::task::Poll;
5
6use embassy_hal_internal::{into_ref, PeripheralRef};
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::channel::Channel;
9
10use crate::can::fd::peripheral::Registers;
11use crate::gpio::sealed::AFType;
12use crate::interrupt::typelevel::Interrupt;
13use crate::rcc::RccPeripheral;
14use crate::{interrupt, peripherals, Peripheral};
15
16pub mod enums;
17pub(crate) mod fd;
18pub mod frame;
19mod util;
20
21use enums::*;
22use fd::config::*;
23use fd::filter::*;
24pub use fd::{config, filter};
25use frame::*;
26
27/// Timestamp for incoming packets. Use Embassy time when enabled.
28#[cfg(feature = "time")]
29pub type Timestamp = embassy_time::Instant;
30
31/// Timestamp for incoming packets.
32#[cfg(not(feature = "time"))]
33pub type Timestamp = u16;
34
35/// Interrupt handler channel 0.
36pub struct IT0InterruptHandler<T: Instance> {
37 _phantom: PhantomData<T>,
38}
39
40// We use IT0 for everything currently
41impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
42 unsafe fn on_interrupt() {
43 let regs = T::regs();
44
45 let ir = regs.ir().read();
46
47 {
48 if ir.tc() {
49 regs.ir().write(|w| w.set_tc(true));
50 }
51 if ir.tefn() {
52 regs.ir().write(|w| w.set_tefn(true));
53 }
54
55 match &T::state().tx_mode {
56 sealed::TxMode::NonBuffered(waker) => waker.wake(),
57 sealed::TxMode::ClassicBuffered(buf) => {
58 if !T::registers().tx_queue_is_full() {
59 match buf.tx_receiver.try_receive() {
60 Ok(frame) => {
61 _ = T::registers().write(&frame);
62 }
63 Err(_) => {}
64 }
65 }
66 }
67 sealed::TxMode::FdBuffered(buf) => {
68 if !T::registers().tx_queue_is_full() {
69 match buf.tx_receiver.try_receive() {
70 Ok(frame) => {
71 _ = T::registers().write(&frame);
72 }
73 Err(_) => {}
74 }
75 }
76 }
77 }
78 }
79
80 if ir.ped() || ir.pea() {
81 regs.ir().write(|w| {
82 w.set_ped(true);
83 w.set_pea(true);
84 });
85 }
86
87 if ir.rfn(0) {
88 T::state().rx_mode.on_interrupt::<T>(0);
89 }
90
91 if ir.rfn(1) {
92 T::state().rx_mode.on_interrupt::<T>(1);
93 }
94 }
95}
96
97/// Interrupt handler channel 1.
98pub struct IT1InterruptHandler<T: Instance> {
99 _phantom: PhantomData<T>,
100}
101
102impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1InterruptHandler<T> {
103 unsafe fn on_interrupt() {}
104}
105
106#[derive(Debug, Copy, Clone, Eq, PartialEq)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108/// Different operating modes
109pub enum FdcanOperatingMode {
110 //PoweredDownMode,
111 //ConfigMode,
112 /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without
113 /// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this
114 /// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held
115 /// recessive.
116 InternalLoopbackMode,
117 /// This mode is provided for hardware self-test. To be independent from external stimulation,
118 /// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a
119 /// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal
120 /// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX
121 /// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the
122 /// FDCAN_TX transmit pin.
123 ExternalLoopbackMode,
124 /// The normal use of the Fdcan instance after configurations
125 NormalOperationMode,
126 /// In Restricted operation mode the node is able to receive data and remote frames and to give
127 /// acknowledge to valid frames, but it does not send data frames, remote frames, active error
128 /// frames, or overload frames. In case of an error condition or overload condition, it does not
129 /// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize
130 /// itself to the CAN communication. The error counters for transmit and receive are frozen while
131 /// error logging (can_errors) is active. TODO: automatically enter in this mode?
132 RestrictedOperationMode,
133 /// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring),
134 /// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a
135 /// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is
136 /// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is
137 /// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive
138 /// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring
139 /// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission
140 /// of dominant bits.
141 BusMonitoringMode,
142 //TestMode,
143}
144
145/// FDCAN Configuration instance instance
146/// Create instance of this first
147pub struct FdcanConfigurator<'d, T: Instance> {
148 config: crate::can::fd::config::FdCanConfig,
149 /// Reference to internals.
150 instance: FdcanInstance<'d, T>,
151}
152
153fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
154 match mode {
155 // Use timestamp from Rx FIFO to adjust timestamp reported to user
156 crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => {
157 let freq = T::frequency();
158 let prescale: u64 =
159 ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
160 1_000_000_000 as u64 / (freq.0 as u64 * prescale)
161 }
162 // For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use
163 // timer3 instead which is too hard to do from this module.
164 _ => 0,
165 }
166}
167
168impl<'d, T: Instance> FdcanConfigurator<'d, T> {
169 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
170 /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
171 pub fn new(
172 peri: impl Peripheral<P = T> + 'd,
173 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
174 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
175 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
176 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
177 + 'd,
178 ) -> FdcanConfigurator<'d, T> {
179 into_ref!(peri, rx, tx);
180
181 rx.set_as_af(rx.af_num(), AFType::Input);
182 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
183
184 T::enable_and_reset();
185
186 let mut config = crate::can::fd::config::FdCanConfig::default();
187 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
188 T::registers().into_config_mode(config);
189
190 rx.set_as_af(rx.af_num(), AFType::Input);
191 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
192
193 unsafe {
194 T::IT0Interrupt::unpend(); // Not unsafe
195 T::IT0Interrupt::enable();
196
197 T::IT1Interrupt::unpend(); // Not unsafe
198 T::IT1Interrupt::enable();
199 }
200
201 Self {
202 config,
203 instance: FdcanInstance(peri),
204 }
205 }
206
207 /// Get configuration
208 pub fn config(&self) -> crate::can::fd::config::FdCanConfig {
209 return self.config;
210 }
211
212 /// Set configuration
213 pub fn set_config(&mut self, config: crate::can::fd::config::FdCanConfig) {
214 self.config = config;
215 }
216
217 /// Configures the bit timings calculated from supplied bitrate.
218 pub fn set_bitrate(&mut self, bitrate: u32) {
219 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
220
221 let nbtr = crate::can::fd::config::NominalBitTiming {
222 sync_jump_width: bit_timing.sync_jump_width,
223 prescaler: bit_timing.prescaler,
224 seg1: bit_timing.seg1,
225 seg2: bit_timing.seg2,
226 };
227 self.config = self.config.set_nominal_bit_timing(nbtr);
228 }
229
230 /// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR
231 pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) {
232 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
233 // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
234 let nbtr = crate::can::fd::config::DataBitTiming {
235 transceiver_delay_compensation,
236 sync_jump_width: bit_timing.sync_jump_width,
237 prescaler: bit_timing.prescaler,
238 seg1: bit_timing.seg1,
239 seg2: bit_timing.seg2,
240 };
241 self.config.frame_transmit = FrameTransmissionConfig::AllowFdCanAndBRS;
242 self.config = self.config.set_data_bit_timing(nbtr);
243 }
244
245 /// Set an Standard Address CAN filter into slot 'id'
246 #[inline]
247 pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) {
248 T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
249 }
250
251 /// Set an array of Standard Address CAN filters and overwrite the current set
252 pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
253 for (i, f) in filters.iter().enumerate() {
254 T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
255 }
256 }
257
258 /// Set an Extended Address CAN filter into slot 'id'
259 #[inline]
260 pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
261 T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
262 }
263
264 /// Set an array of Extended Address CAN filters and overwrite the current set
265 pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
266 for (i, f) in filters.iter().enumerate() {
267 T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
268 }
269 }
270
271 /// Start in mode.
272 pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> {
273 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
274 critical_section::with(|_| unsafe {
275 T::mut_state().ns_per_timer_tick = ns_per_timer_tick;
276 });
277 T::registers().into_mode(self.config, mode);
278 let ret = Fdcan {
279 config: self.config,
280 instance: self.instance,
281 _mode: mode,
282 };
283 ret
284 }
285
286 /// Start, entering mode. Does same as start(mode)
287 pub fn into_normal_mode(self) -> Fdcan<'d, T> {
288 self.start(FdcanOperatingMode::NormalOperationMode)
289 }
290
291 /// Start, entering mode. Does same as start(mode)
292 pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> {
293 self.start(FdcanOperatingMode::InternalLoopbackMode)
294 }
295
296 /// Start, entering mode. Does same as start(mode)
297 pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> {
298 self.start(FdcanOperatingMode::ExternalLoopbackMode)
299 }
300}
301
302/// FDCAN Instance
303pub struct Fdcan<'d, T: Instance> {
304 config: crate::can::fd::config::FdCanConfig,
305 /// Reference to internals.
306 instance: FdcanInstance<'d, T>,
307 _mode: FdcanOperatingMode,
308}
309
310impl<'d, T: Instance> Fdcan<'d, T> {
311 /// Flush one of the TX mailboxes.
312 pub async fn flush(&self, idx: usize) {
313 poll_fn(|cx| {
314 T::state().tx_mode.register(cx.waker());
315
316 if idx > 3 {
317 panic!("Bad mailbox");
318 }
319 let idx = 1 << idx;
320 if !T::regs().txbrp().read().trp(idx) {
321 return Poll::Ready(());
322 }
323
324 Poll::Pending
325 })
326 .await;
327 }
328
329 /// Queues the message to be sent but exerts backpressure. If a lower-priority
330 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
331 /// can be replaced, this call asynchronously waits for a frame to be successfully
332 /// transmitted, then tries again.
333 pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
334 T::state().tx_mode.write::<T>(frame).await
335 }
336
337 /// Returns the next received message frame
338 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
339 T::state().rx_mode.read_classic::<T>().await
340 }
341
342 /// Queues the message to be sent but exerts backpressure. If a lower-priority
343 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
344 /// can be replaced, this call asynchronously waits for a frame to be successfully
345 /// transmitted, then tries again.
346 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
347 T::state().tx_mode.write_fd::<T>(frame).await
348 }
349
350 /// Returns the next received message frame
351 pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
352 T::state().rx_mode.read_fd::<T>().await
353 }
354
355 /// Split instance into separate Tx(write) and Rx(read) portions
356 pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) {
357 (
358 FdcanTx {
359 config: self.config,
360 _instance: self.instance,
361 _mode: self._mode,
362 },
363 FdcanRx {
364 _instance1: PhantomData::<T>,
365 _instance2: T::regs(),
366 _mode: self._mode,
367 },
368 )
369 }
370
371 /// Join split rx and tx portions back together
372 pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self {
373 Fdcan {
374 config: tx.config,
375 //_instance2: T::regs(),
376 instance: tx._instance,
377 _mode: rx._mode,
378 }
379 }
380
381 /// Return a buffered instance of driver without CAN FD support. User must supply Buffers
382 pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
383 &self,
384 tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
385 rxb: &'static mut RxBuf<RX_BUF_SIZE>,
386 ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
387 BufferedCan::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
388 }
389
390 /// Return a buffered instance of driver with CAN FD support. User must supply Buffers
391 pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
392 &self,
393 tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
394 rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
395 ) -> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
396 BufferedCanFd::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
397 }
398}
399
400/// User supplied buffer for RX Buffering
401pub type RxBuf<const BUF_SIZE: usize> =
402 Channel<CriticalSectionRawMutex, Result<(ClassicFrame, Timestamp), BusError>, BUF_SIZE>;
403
404/// User supplied buffer for TX buffering
405pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>;
406
407/// Buffered FDCAN Instance
408pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
409 _instance1: PhantomData<T>,
410 _instance2: &'d crate::pac::can::Fdcan,
411 _mode: FdcanOperatingMode,
412 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
413 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
414}
415
416/// Sender that can be used for sending CAN frames.
417#[derive(Copy, Clone)]
418pub struct BufferedCanSender {
419 tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>,
420 waker: fn(),
421}
422
423impl BufferedCanSender {
424 /// Async write frame to TX buffer.
425 pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> {
426 self.tx_buf.try_send(frame)?;
427 (self.waker)();
428 Ok(())
429 }
430
431 /// Async write frame to TX buffer.
432 pub async fn write(&mut self, frame: ClassicFrame) {
433 self.tx_buf.send(frame).await;
434 (self.waker)();
435 }
436
437 /// Allows a poll_fn to poll until the channel is ready to write
438 pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
439 self.tx_buf.poll_ready_to_send(cx)
440 }
441}
442
443/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
444pub type BufferedCanReceiver =
445 embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>;
446
447impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
448 BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
449{
450 fn new(
451 _instance1: PhantomData<T>,
452 _instance2: &'d crate::pac::can::Fdcan,
453 _mode: FdcanOperatingMode,
454 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
455 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
456 ) -> Self {
457 BufferedCan {
458 _instance1,
459 _instance2,
460 _mode,
461 tx_buf,
462 rx_buf,
463 }
464 .setup()
465 }
466
467 fn setup(self) -> Self {
468 // We don't want interrupts being processed while we change modes.
469 critical_section::with(|_| unsafe {
470 let rx_inner = sealed::ClassicBufferedRxInner {
471 rx_sender: self.rx_buf.sender().into(),
472 };
473 let tx_inner = sealed::ClassicBufferedTxInner {
474 tx_receiver: self.tx_buf.receiver().into(),
475 };
476 T::mut_state().rx_mode = sealed::RxMode::ClassicBuffered(rx_inner);
477 T::mut_state().tx_mode = sealed::TxMode::ClassicBuffered(tx_inner);
478 });
479 self
480 }
481
482 /// Async write frame to TX buffer.
483 pub async fn write(&mut self, frame: ClassicFrame) {
484 self.tx_buf.send(frame).await;
485 T::IT0Interrupt::pend(); // Wake for Tx
486 }
487
488 /// Async read frame from RX buffer.
489 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
490 self.rx_buf.receive().await
491 }
492
493 /// Returns a sender that can be used for sending CAN frames.
494 pub fn writer(&self) -> BufferedCanSender {
495 BufferedCanSender {
496 tx_buf: self.tx_buf.sender().into(),
497 waker: T::IT0Interrupt::pend,
498 }
499 }
500
501 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
502 pub fn reader(&self) -> BufferedCanReceiver {
503 self.rx_buf.receiver().into()
504 }
505}
506
507impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
508 for BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
509{
510 fn drop(&mut self) {
511 critical_section::with(|_| unsafe {
512 T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
513 T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
514 });
515 }
516}
517
518/// User supplied buffer for RX Buffering
519pub type RxFdBuf<const BUF_SIZE: usize> =
520 Channel<CriticalSectionRawMutex, Result<(FdFrame, Timestamp), BusError>, BUF_SIZE>;
521
522/// User supplied buffer for TX buffering
523pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
524
525/// Buffered FDCAN Instance
526pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
527 _instance1: PhantomData<T>,
528 _instance2: &'d crate::pac::can::Fdcan,
529 _mode: FdcanOperatingMode,
530 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
531 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
532}
533
534/// Sender that can be used for sending CAN frames.
535#[derive(Copy, Clone)]
536pub struct BufferedFdCanSender {
537 tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>,
538 waker: fn(),
539}
540
541impl BufferedFdCanSender {
542 /// Async write frame to TX buffer.
543 pub fn try_write(&mut self, frame: FdFrame) -> Result<(), embassy_sync::channel::TrySendError<FdFrame>> {
544 self.tx_buf.try_send(frame)?;
545 (self.waker)();
546 Ok(())
547 }
548
549 /// Async write frame to TX buffer.
550 pub async fn write(&mut self, frame: FdFrame) {
551 self.tx_buf.send(frame).await;
552 (self.waker)();
553 }
554
555 /// Allows a poll_fn to poll until the channel is ready to write
556 pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
557 self.tx_buf.poll_ready_to_send(cx)
558 }
559}
560
561/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
562pub type BufferedFdCanReceiver =
563 embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>;
564
565impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
566 BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
567{
568 fn new(
569 _instance1: PhantomData<T>,
570 _instance2: &'d crate::pac::can::Fdcan,
571 _mode: FdcanOperatingMode,
572 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
573 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
574 ) -> Self {
575 BufferedCanFd {
576 _instance1,
577 _instance2,
578 _mode,
579 tx_buf,
580 rx_buf,
581 }
582 .setup()
583 }
584
585 fn setup(self) -> Self {
586 // We don't want interrupts being processed while we change modes.
587 critical_section::with(|_| unsafe {
588 let rx_inner = sealed::FdBufferedRxInner {
589 rx_sender: self.rx_buf.sender().into(),
590 };
591 let tx_inner = sealed::FdBufferedTxInner {
592 tx_receiver: self.tx_buf.receiver().into(),
593 };
594 T::mut_state().rx_mode = sealed::RxMode::FdBuffered(rx_inner);
595 T::mut_state().tx_mode = sealed::TxMode::FdBuffered(tx_inner);
596 });
597 self
598 }
599
600 /// Async write frame to TX buffer.
601 pub async fn write(&mut self, frame: FdFrame) {
602 self.tx_buf.send(frame).await;
603 T::IT0Interrupt::pend(); // Wake for Tx
604 }
605
606 /// Async read frame from RX buffer.
607 pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
608 self.rx_buf.receive().await
609 }
610
611 /// Returns a sender that can be used for sending CAN frames.
612 pub fn writer(&self) -> BufferedFdCanSender {
613 BufferedFdCanSender {
614 tx_buf: self.tx_buf.sender().into(),
615 waker: T::IT0Interrupt::pend,
616 }
617 }
618
619 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
620 pub fn reader(&self) -> BufferedFdCanReceiver {
621 self.rx_buf.receiver().into()
622 }
623}
624
625impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
626 for BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
627{
628 fn drop(&mut self) {
629 critical_section::with(|_| unsafe {
630 T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
631 T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
632 });
633 }
634}
635
636/// FDCAN Rx only Instance
637pub struct FdcanRx<'d, T: Instance> {
638 _instance1: PhantomData<T>,
639 _instance2: &'d crate::pac::can::Fdcan,
640 _mode: FdcanOperatingMode,
641}
642
643/// FDCAN Tx only Instance
644pub struct FdcanTx<'d, T: Instance> {
645 config: crate::can::fd::config::FdCanConfig,
646 _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
647 _mode: FdcanOperatingMode,
648}
649
650impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
651 /// Queues the message to be sent but exerts backpressure. If a lower-priority
652 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
653 /// can be replaced, this call asynchronously waits for a frame to be successfully
654 /// transmitted, then tries again.
655 pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
656 T::state().tx_mode.write::<T>(frame).await
657 }
658
659 /// Queues the message to be sent but exerts backpressure. If a lower-priority
660 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
661 /// can be replaced, this call asynchronously waits for a frame to be successfully
662 /// transmitted, then tries again.
663 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
664 T::state().tx_mode.write_fd::<T>(frame).await
665 }
666}
667
668impl<'c, 'd, T: Instance> FdcanRx<'d, T> {
669 /// Returns the next received message frame
670 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
671 T::state().rx_mode.read_classic::<T>().await
672 }
673
674 /// Returns the next received message frame
675 pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
676 T::state().rx_mode.read_fd::<T>().await
677 }
678}
2 679
3pub(crate) mod sealed { 680pub(crate) mod sealed {
4 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 681 use core::future::poll_fn;
5 use embassy_sync::channel::Channel; 682 use core::task::Poll;
683
684 use embassy_sync::channel::{DynamicReceiver, DynamicSender};
6 use embassy_sync::waitqueue::AtomicWaker; 685 use embassy_sync::waitqueue::AtomicWaker;
7 686
687 use super::CanHeader;
688 use crate::can::_version::{BusError, Timestamp};
689 use crate::can::frame::{ClassicFrame, FdFrame};
690
691 pub struct ClassicBufferedRxInner {
692 pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>,
693 }
694 pub struct ClassicBufferedTxInner {
695 pub tx_receiver: DynamicReceiver<'static, ClassicFrame>,
696 }
697
698 pub struct FdBufferedRxInner {
699 pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>,
700 }
701 pub struct FdBufferedTxInner {
702 pub tx_receiver: DynamicReceiver<'static, FdFrame>,
703 }
704
705 pub enum RxMode {
706 NonBuffered(AtomicWaker),
707 ClassicBuffered(ClassicBufferedRxInner),
708 FdBuffered(FdBufferedRxInner),
709 }
710
711 impl RxMode {
712 pub fn register(&self, arg: &core::task::Waker) {
713 match self {
714 RxMode::NonBuffered(waker) => waker.register(arg),
715 _ => {
716 panic!("Bad Mode")
717 }
718 }
719 }
720
721 pub fn on_interrupt<T: Instance>(&self, fifonr: usize) {
722 T::regs().ir().write(|w| w.set_rfn(fifonr, true));
723 match self {
724 RxMode::NonBuffered(waker) => {
725 waker.wake();
726 }
727 RxMode::ClassicBuffered(buf) => {
728 if let Some(result) = self.read::<T, _>() {
729 let _ = buf.rx_sender.try_send(result);
730 }
731 }
732 RxMode::FdBuffered(buf) => {
733 if let Some(result) = self.read::<T, _>() {
734 let _ = buf.rx_sender.try_send(result);
735 }
736 }
737 }
738 }
739
740 fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> {
741 if let Some((msg, ts)) = T::registers().read(0) {
742 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
743 Some(Ok((msg, ts)))
744 } else if let Some((msg, ts)) = T::registers().read(1) {
745 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
746 Some(Ok((msg, ts)))
747 } else if let Some(err) = T::registers().curr_error() {
748 // TODO: this is probably wrong
749 Some(Err(err))
750 } else {
751 None
752 }
753 }
754
755 async fn read_async<T: Instance, F: CanHeader>(&self) -> Result<(F, Timestamp), BusError> {
756 poll_fn(|cx| {
757 T::state().err_waker.register(cx.waker());
758 self.register(cx.waker());
759 match self.read::<T, _>() {
760 Some(result) => Poll::Ready(result),
761 None => Poll::Pending,
762 }
763 })
764 .await
765 }
766
767 pub async fn read_classic<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> {
768 self.read_async::<T, _>().await
769 }
770
771 pub async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> {
772 self.read_async::<T, _>().await
773 }
774 }
775
776 pub enum TxMode {
777 NonBuffered(AtomicWaker),
778 ClassicBuffered(ClassicBufferedTxInner),
779 FdBuffered(FdBufferedTxInner),
780 }
781
782 impl TxMode {
783 pub fn register(&self, arg: &core::task::Waker) {
784 match self {
785 TxMode::NonBuffered(waker) => {
786 waker.register(arg);
787 }
788 _ => {
789 panic!("Bad mode");
790 }
791 }
792 }
793
794 /// Queues the message to be sent but exerts backpressure. If a lower-priority
795 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
796 /// can be replaced, this call asynchronously waits for a frame to be successfully
797 /// transmitted, then tries again.
798 async fn write_generic<T: Instance, F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> Option<F> {
799 poll_fn(|cx| {
800 self.register(cx.waker());
801
802 if let Ok(dropped) = T::registers().write(frame) {
803 return Poll::Ready(dropped);
804 }
805
806 // Couldn't replace any lower priority frames. Need to wait for some mailboxes
807 // to clear.
808 Poll::Pending
809 })
810 .await
811 }
812
813 /// Queues the message to be sent but exerts backpressure. If a lower-priority
814 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
815 /// can be replaced, this call asynchronously waits for a frame to be successfully
816 /// transmitted, then tries again.
817 pub async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> {
818 self.write_generic::<T, _>(frame).await
819 }
820
821 /// Queues the message to be sent but exerts backpressure. If a lower-priority
822 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
823 /// can be replaced, this call asynchronously waits for a frame to be successfully
824 /// transmitted, then tries again.
825 pub async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> {
826 self.write_generic::<T, _>(frame).await
827 }
828 }
829
8 pub struct State { 830 pub struct State {
9 pub tx_waker: AtomicWaker, 831 pub rx_mode: RxMode,
832 pub tx_mode: TxMode,
833 pub ns_per_timer_tick: u64,
834
10 pub err_waker: AtomicWaker, 835 pub err_waker: AtomicWaker,
11 pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>,
12 } 836 }
13 837
14 impl State { 838 impl State {
15 pub const fn new() -> Self { 839 pub const fn new() -> Self {
16 Self { 840 Self {
17 tx_waker: AtomicWaker::new(), 841 rx_mode: RxMode::NonBuffered(AtomicWaker::new()),
842 tx_mode: TxMode::NonBuffered(AtomicWaker::new()),
843 ns_per_timer_tick: 0,
18 err_waker: AtomicWaker::new(), 844 err_waker: AtomicWaker::new(),
19 rx_queue: Channel::new(),
20 } 845 }
21 } 846 }
22 } 847 }
23 848
24 pub trait Instance { 849 pub trait Instance {
850 const MSG_RAM_OFFSET: usize;
851
25 fn regs() -> &'static crate::pac::can::Fdcan; 852 fn regs() -> &'static crate::pac::can::Fdcan;
853 fn registers() -> crate::can::fd::peripheral::Registers;
854 fn ram() -> &'static crate::pac::fdcanram::Fdcanram;
26 fn state() -> &'static State; 855 fn state() -> &'static State;
856 unsafe fn mut_state() -> &'static mut State;
857 fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp;
27 } 858 }
28} 859}
29 860
30/// Interruptable FDCAN instance. 861/// Instance trait
31pub trait InterruptableInstance {} 862pub trait Instance: sealed::Instance + RccPeripheral + 'static {
32/// FDCAN instance. 863 /// Interrupt 0
33pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} 864 type IT0Interrupt: crate::interrupt::typelevel::Interrupt;
865 /// Interrupt 0
866 type IT1Interrupt: crate::interrupt::typelevel::Interrupt;
867}
34 868
35foreach_peripheral!( 869/// Fdcan Instance struct
36 (can, $inst:ident) => { 870pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
871
872macro_rules! impl_fdcan {
873 ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => {
37 impl sealed::Instance for peripherals::$inst { 874 impl sealed::Instance for peripherals::$inst {
875 const MSG_RAM_OFFSET: usize = $msg_ram_offset;
876
38 fn regs() -> &'static crate::pac::can::Fdcan { 877 fn regs() -> &'static crate::pac::can::Fdcan {
39 &crate::pac::$inst 878 &crate::pac::$inst
40 } 879 }
41 880 fn registers() -> Registers {
881 Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
882 }
883 fn ram() -> &'static crate::pac::fdcanram::Fdcanram {
884 &crate::pac::$msg_ram_inst
885 }
886 unsafe fn mut_state() -> & 'static mut sealed::State {
887 static mut STATE: sealed::State = sealed::State::new();
888 & mut STATE
889 }
42 fn state() -> &'static sealed::State { 890 fn state() -> &'static sealed::State {
43 static STATE: sealed::State = sealed::State::new(); 891 unsafe { peripherals::$inst::mut_state() }
44 &STATE
45 } 892 }
893
894 #[cfg(feature = "time")]
895 fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
896 let now_embassy = embassy_time::Instant::now();
897 if ns_per_timer_tick == 0 {
898 return now_embassy;
899 }
900 let cantime = { Self::regs().tscv().read().tsc() };
901 let delta = cantime.overflowing_sub(ts_val).0 as u64;
902 let ns = ns_per_timer_tick * delta as u64;
903 now_embassy - embassy_time::Duration::from_nanos(ns)
904 }
905
906 #[cfg(not(feature = "time"))]
907 fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
908 ts_val
909 }
910
46 } 911 }
47 912
48 impl Instance for peripherals::$inst {} 913 #[allow(non_snake_case)]
914 pub(crate) mod $inst {
49 915
50 impl InterruptableInstance for peripherals::$inst {} 916 foreach_interrupt!(
917 ($inst,can,FDCAN,IT0,$irq:ident) => {
918 pub type Interrupt0 = crate::interrupt::typelevel::$irq;
919 };
920 ($inst,can,FDCAN,IT1,$irq:ident) => {
921 pub type Interrupt1 = crate::interrupt::typelevel::$irq;
922 };
923 );
924 }
925 impl Instance for peripherals::$inst {
926 type IT0Interrupt = $inst::Interrupt0;
927 type IT1Interrupt = $inst::Interrupt1;
928 }
51 }; 929 };
930
931 ($inst:ident, $msg_ram_inst:ident) => {
932 impl_fdcan!($inst, $msg_ram_inst, 0);
933 };
934}
935
936#[cfg(not(stm32h7))]
937foreach_peripheral!(
938 (can, FDCAN) => { impl_fdcan!(FDCAN, FDCANRAM); };
939 (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM1); };
940 (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM2); };
941 (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM3); };
942);
943
944#[cfg(stm32h7)]
945foreach_peripheral!(
946 (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM, 0x0000); };
947 (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM, 0x0C00); };
948 (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM, 0x1800); };
52); 949);
53 950
54pin_trait!(RxPin, Instance); 951pin_trait!(RxPin, Instance);
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
new file mode 100644
index 000000000..9c293035d
--- /dev/null
+++ b/embassy-stm32/src/can/frame.rs
@@ -0,0 +1,398 @@
1//! Definition for CAN Frames
2use bit_field::BitField;
3
4/// CAN Header, without meta data
5#[derive(Debug, Copy, Clone)]
6pub struct Header {
7 id: embedded_can::Id,
8 len: u8,
9 flags: u8,
10}
11
12impl Header {
13 const FLAG_RTR: usize = 0; // Remote
14 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
15 const FLAG_BRS: usize = 2; // Bit-rate switching, ignored for Classic CAN
16
17 /// Create new CAN Header
18 pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header {
19 let mut flags = 0u8;
20 flags.set_bit(Self::FLAG_RTR, rtr);
21 Header { id, len, flags }
22 }
23
24 /// Create new CAN FD Header
25 pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header {
26 let mut flags = 0u8;
27 flags.set_bit(Self::FLAG_RTR, rtr);
28 flags.set_bit(Self::FLAG_FDCAN, true);
29 flags.set_bit(Self::FLAG_BRS, brs);
30 Header { id, len, flags }
31 }
32
33 /// Return ID
34 pub fn id(&self) -> &embedded_can::Id {
35 &self.id
36 }
37
38 /// Return length as u8
39 pub fn len(&self) -> u8 {
40 self.len
41 }
42
43 /// Is remote frame
44 pub fn rtr(&self) -> bool {
45 self.flags.get_bit(Self::FLAG_RTR)
46 }
47
48 /// Request/is FDCAN frame
49 pub fn fdcan(&self) -> bool {
50 self.flags.get_bit(Self::FLAG_FDCAN)
51 }
52
53 /// Request/is Flexible Data Rate
54 pub fn bit_rate_switching(&self) -> bool {
55 self.flags.get_bit(Self::FLAG_BRS)
56 }
57}
58
59/// Trait for FDCAN frame types, providing ability to construct from a Header
60/// and to retrieve the Header from a frame
61pub trait CanHeader: Sized {
62 /// Construct frame from header and payload
63 fn from_header(header: Header, data: &[u8]) -> Option<Self>;
64
65 /// Get this frame's header struct
66 fn header(&self) -> &Header;
67}
68
69/// Payload of a classic CAN data frame.
70///
71/// Contains 0 to 8 Bytes of data.
72#[derive(Debug, Copy, Clone)]
73pub struct ClassicData {
74 pub(crate) bytes: [u8; 8],
75}
76
77impl ClassicData {
78 /// Creates a data payload from a raw byte slice.
79 ///
80 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
81 /// cannot be represented with an FDCAN DLC.
82 pub fn new(data: &[u8]) -> Option<Self> {
83 if !FdData::is_valid_len(data.len()) {
84 return None;
85 }
86
87 let mut bytes = [0; 8];
88 bytes[..data.len()].copy_from_slice(data);
89
90 Some(Self { bytes })
91 }
92
93 /// Raw read access to data.
94 pub fn raw(&self) -> &[u8] {
95 &self.bytes
96 }
97
98 /// Checks if the length can be encoded in FDCAN DLC field.
99 pub const fn is_valid_len(len: usize) -> bool {
100 match len {
101 0..=8 => true,
102 _ => false,
103 }
104 }
105
106 /// Creates an empty data payload containing 0 bytes.
107 #[inline]
108 pub const fn empty() -> Self {
109 Self { bytes: [0; 8] }
110 }
111}
112
113/// Frame with up to 8 bytes of data payload as per Classic CAN
114#[derive(Debug, Copy, Clone)]
115pub struct ClassicFrame {
116 can_header: Header,
117 data: ClassicData,
118}
119
120impl ClassicFrame {
121 pub(crate) const MAX_DATA_LEN: usize = 8;
122
123 /// Create a new CAN classic Frame
124 pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame {
125 ClassicFrame { can_header, data }
126 }
127
128 /// Create new extended frame
129 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> {
130 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
131 match ClassicData::new(raw_data) {
132 Some(data) => Some(ClassicFrame::new(
133 Header::new(id.into(), raw_data.len() as u8, false),
134 data,
135 )),
136 None => None,
137 }
138 } else {
139 None
140 }
141 }
142
143 /// Create new standard frame
144 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> {
145 if let Some(id) = embedded_can::StandardId::new(raw_id) {
146 match ClassicData::new(raw_data) {
147 Some(data) => Some(ClassicFrame::new(
148 Header::new(id.into(), raw_data.len() as u8, false),
149 data,
150 )),
151 None => None,
152 }
153 } else {
154 None
155 }
156 }
157
158 /// Create new remote frame
159 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
160 if len <= 8usize {
161 Some(ClassicFrame::new(
162 Header::new(id.into(), len as u8, true),
163 ClassicData::empty(),
164 ))
165 } else {
166 None
167 }
168 }
169
170 /// Get reference to data
171 pub fn header(&self) -> &Header {
172 &self.can_header
173 }
174
175 /// Return ID
176 pub fn id(&self) -> &embedded_can::Id {
177 &self.can_header.id
178 }
179
180 /// Get reference to data
181 pub fn data(&self) -> &[u8] {
182 &self.data.raw()
183 }
184}
185
186impl embedded_can::Frame for ClassicFrame {
187 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
188 match ClassicData::new(raw_data) {
189 Some(data) => Some(ClassicFrame::new(
190 Header::new(id.into(), raw_data.len() as u8, false),
191 data,
192 )),
193 None => None,
194 }
195 }
196 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
197 if len <= 8 {
198 Some(ClassicFrame::new(
199 Header::new(id.into(), len as u8, true),
200 ClassicData::empty(),
201 ))
202 } else {
203 None
204 }
205 }
206 fn is_extended(&self) -> bool {
207 match self.can_header.id {
208 embedded_can::Id::Extended(_) => true,
209 embedded_can::Id::Standard(_) => false,
210 }
211 }
212 fn is_remote_frame(&self) -> bool {
213 self.can_header.rtr()
214 }
215 fn id(&self) -> embedded_can::Id {
216 self.can_header.id
217 }
218 fn dlc(&self) -> usize {
219 self.can_header.len as usize
220 }
221 fn data(&self) -> &[u8] {
222 &self.data.raw()
223 }
224}
225
226impl CanHeader for ClassicFrame {
227 fn from_header(header: Header, data: &[u8]) -> Option<Self> {
228 Some(Self::new(header, ClassicData::new(data)?))
229 }
230
231 fn header(&self) -> &Header {
232 self.header()
233 }
234}
235
236/// Payload of a (FD)CAN data frame.
237///
238/// Contains 0 to 64 Bytes of data.
239#[derive(Debug, Copy, Clone)]
240pub struct FdData {
241 pub(crate) bytes: [u8; 64],
242}
243
244impl FdData {
245 /// Creates a data payload from a raw byte slice.
246 ///
247 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
248 /// cannot be represented with an FDCAN DLC.
249 pub fn new(data: &[u8]) -> Option<Self> {
250 if !FdData::is_valid_len(data.len()) {
251 return None;
252 }
253
254 let mut bytes = [0; 64];
255 bytes[..data.len()].copy_from_slice(data);
256
257 Some(Self { bytes })
258 }
259
260 /// Raw read access to data.
261 pub fn raw(&self) -> &[u8] {
262 &self.bytes
263 }
264
265 /// Checks if the length can be encoded in FDCAN DLC field.
266 pub const fn is_valid_len(len: usize) -> bool {
267 match len {
268 0..=8 => true,
269 12 => true,
270 16 => true,
271 20 => true,
272 24 => true,
273 32 => true,
274 48 => true,
275 64 => true,
276 _ => false,
277 }
278 }
279
280 /// Creates an empty data payload containing 0 bytes.
281 #[inline]
282 pub const fn empty() -> Self {
283 Self { bytes: [0; 64] }
284 }
285}
286
287/// Frame with up to 8 bytes of data payload as per Fd CAN
288#[derive(Debug, Copy, Clone)]
289pub struct FdFrame {
290 can_header: Header,
291 data: FdData,
292}
293
294impl FdFrame {
295 /// Create a new CAN classic Frame
296 pub fn new(can_header: Header, data: FdData) -> FdFrame {
297 FdFrame { can_header, data }
298 }
299
300 /// Create new extended frame
301 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> {
302 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
303 match FdData::new(raw_data) {
304 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
305 None => None,
306 }
307 } else {
308 None
309 }
310 }
311
312 /// Create new standard frame
313 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> {
314 if let Some(id) = embedded_can::StandardId::new(raw_id) {
315 match FdData::new(raw_data) {
316 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
317 None => None,
318 }
319 } else {
320 None
321 }
322 }
323
324 /// Create new remote frame
325 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
326 if len <= 8 {
327 Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty()))
328 } else {
329 None
330 }
331 }
332
333 /// Get reference to data
334 pub fn header(&self) -> &Header {
335 &self.can_header
336 }
337
338 /// Return ID
339 pub fn id(&self) -> &embedded_can::Id {
340 &self.can_header.id
341 }
342
343 /// Get reference to data
344 pub fn data(&self) -> &[u8] {
345 &self.data.raw()
346 }
347}
348
349impl embedded_can::Frame for FdFrame {
350 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
351 match FdData::new(raw_data) {
352 Some(data) => Some(FdFrame::new(
353 Header::new_fd(id.into(), raw_data.len() as u8, false, true),
354 data,
355 )),
356 None => None,
357 }
358 }
359 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
360 if len <= 8 {
361 Some(FdFrame::new(
362 Header::new_fd(id.into(), len as u8, true, true),
363 FdData::empty(),
364 ))
365 } else {
366 None
367 }
368 }
369 fn is_extended(&self) -> bool {
370 match self.can_header.id {
371 embedded_can::Id::Extended(_) => true,
372 embedded_can::Id::Standard(_) => false,
373 }
374 }
375 fn is_remote_frame(&self) -> bool {
376 self.can_header.rtr()
377 }
378 fn id(&self) -> embedded_can::Id {
379 self.can_header.id
380 }
381 // Returns length in bytes even for CANFD packets which embedded-can does not really mention.
382 fn dlc(&self) -> usize {
383 self.can_header.len as usize
384 }
385 fn data(&self) -> &[u8] {
386 &self.data.raw()
387 }
388}
389
390impl CanHeader for FdFrame {
391 fn from_header(header: Header, data: &[u8]) -> Option<Self> {
392 Some(Self::new(header, FdData::new(data)?))
393 }
394
395 fn header(&self) -> &Header {
396 self.header()
397 }
398}
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs
new file mode 100644
index 000000000..fcdbbad62
--- /dev/null
+++ b/embassy-stm32/src/can/util.rs
@@ -0,0 +1,117 @@
1//! Utility functions shared between CAN controller types.
2
3use core::num::{NonZeroU16, NonZeroU8};
4
5/// Shared struct to represent bit timings used by calc_can_timings.
6#[derive(Clone, Copy, Debug)]
7pub struct NominalBitTiming {
8 /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
9 /// time is built up from a multiple of this quanta. Valid values are 1 to 512.
10 pub prescaler: NonZeroU16,
11 /// Valid values are 1 to 128.
12 pub seg1: NonZeroU8,
13 /// Valid values are 1 to 255.
14 pub seg2: NonZeroU8,
15 /// Valid values are 1 to 128.
16 pub sync_jump_width: NonZeroU8,
17}
18
19/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency
20pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> {
21 const BS1_MAX: u8 = 16;
22 const BS2_MAX: u8 = 8;
23 const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
24
25 let periph_clock = periph_clock.0;
26
27 if can_bitrate < 1000 {
28 return None;
29 }
30
31 // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
32 // CAN in Automation, 2003
33 //
34 // According to the source, optimal quanta per bit are:
35 // Bitrate Optimal Maximum
36 // 1000 kbps 8 10
37 // 500 kbps 16 17
38 // 250 kbps 16 17
39 // 125 kbps 16 17
40 let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
41
42 // Computing (prescaler * BS):
43 // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
44 // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
45 // let:
46 // BS = 1 + BS1 + BS2 -- Number of time quanta per bit
47 // PRESCALER_BS = PRESCALER * BS
48 // ==>
49 // PRESCALER_BS = PCLK / BITRATE
50 let prescaler_bs = periph_clock / can_bitrate;
51
52 // Searching for such prescaler value so that the number of quanta per bit is highest.
53 let mut bs1_bs2_sum = max_quanta_per_bit - 1;
54 while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
55 if bs1_bs2_sum <= 2 {
56 return None; // No solution
57 }
58 bs1_bs2_sum -= 1;
59 }
60
61 let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
62 if (prescaler < 1) || (prescaler > 1024) {
63 return None; // No solution
64 }
65
66 // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
67 // We need to find such values so that the sample point is as close as possible to the optimal value,
68 // which is 87.5%, which is 7/8.
69 //
70 // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
71 // {{bs2 -> (1 + bs1)/7}}
72 //
73 // Hence:
74 // bs2 = (1 + bs1) / 7
75 // bs1 = (7 * bs1_bs2_sum - 1) / 8
76 //
77 // Sample point location can be computed as follows:
78 // Sample point location = (1 + bs1) / (1 + bs1 + bs2)
79 //
80 // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
81 // - With rounding to nearest
82 // - With rounding to zero
83 let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
84 let mut bs2 = bs1_bs2_sum - bs1;
85 core::assert!(bs1_bs2_sum > bs1);
86
87 let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
88 if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
89 // Nope, too far; now rounding to zero
90 bs1 = (7 * bs1_bs2_sum - 1) / 8;
91 bs2 = bs1_bs2_sum - bs1;
92 }
93
94 // Check is BS1 and BS2 are in range
95 if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
96 return None;
97 }
98
99 // Check if final bitrate matches the requested
100 if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
101 return None;
102 }
103
104 // One is recommended by DS-015, CANOpen, and DeviceNet
105 let sync_jump_width = core::num::NonZeroU8::new(1)?;
106
107 let seg1 = core::num::NonZeroU8::new(bs1)?;
108 let seg2 = core::num::NonZeroU8::new(bs2)?;
109 let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?;
110
111 Some(NominalBitTiming {
112 sync_jump_width,
113 prescaler: nz_prescaler,
114 seg1,
115 seg2,
116 })
117}
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
new file mode 100644
index 000000000..8f259520a
--- /dev/null
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -0,0 +1,1356 @@
1//! Crypto Accelerator (CRYP)
2#[cfg(any(cryp_v2, cryp_v3))]
3use core::cmp::min;
4use core::marker::PhantomData;
5
6use embassy_hal_internal::{into_ref, PeripheralRef};
7
8use crate::{interrupt, pac, peripherals, Peripheral};
9
10const DES_BLOCK_SIZE: usize = 8; // 64 bits
11const AES_BLOCK_SIZE: usize = 16; // 128 bits
12
13/// This trait encapsulates all cipher-specific behavior/
14pub trait Cipher<'c> {
15 /// Processing block size. Determined by the processor and the algorithm.
16 const BLOCK_SIZE: usize;
17
18 /// Indicates whether the cipher requires the application to provide padding.
19 /// If `true`, no partial blocks will be accepted (a panic will occur).
20 const REQUIRES_PADDING: bool = false;
21
22 /// Returns the symmetric key.
23 fn key(&self) -> &[u8];
24
25 /// Returns the initialization vector.
26 fn iv(&self) -> &[u8];
27
28 /// Sets the processor algorithm mode according to the associated cipher.
29 fn set_algomode(&self, p: &pac::cryp::Cryp);
30
31 /// Performs any key preparation within the processor, if necessary.
32 fn prepare_key(&self, _p: &pac::cryp::Cryp) {}
33
34 /// Performs any cipher-specific initialization.
35 fn init_phase(&self, _p: &pac::cryp::Cryp) {}
36
37 /// Called prior to processing the last data block for cipher-specific operations.
38 fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
39 return [0; 4];
40 }
41
42 /// Called after processing the last data block for cipher-specific operations.
43 fn post_final_block(
44 &self,
45 _p: &pac::cryp::Cryp,
46 _dir: Direction,
47 _int_data: &mut [u8; AES_BLOCK_SIZE],
48 _temp1: [u32; 4],
49 _padding_mask: [u8; 16],
50 ) {
51 }
52
53 /// Called prior to processing the first associated data block for cipher-specific operations.
54 fn get_header_block(&self) -> &[u8] {
55 return [0; 0].as_slice();
56 }
57}
58
59/// This trait enables restriction of ciphers to specific key sizes.
60pub trait CipherSized {}
61
62/// This trait enables restriction of initialization vectors to sizes compatibile with a cipher mode.
63pub trait IVSized {}
64
65/// This trait enables restriction of a header phase to authenticated ciphers only.
66pub trait CipherAuthenticated<const TAG_SIZE: usize> {
67 /// Defines the authentication tag size.
68 const TAG_SIZE: usize = TAG_SIZE;
69}
70
71/// TDES-ECB Cipher Mode
72pub struct TdesEcb<'c, const KEY_SIZE: usize> {
73 iv: &'c [u8; 0],
74 key: &'c [u8; KEY_SIZE],
75}
76
77impl<'c, const KEY_SIZE: usize> TdesEcb<'c, KEY_SIZE> {
78 /// Constructs a new AES-ECB cipher for a cryptographic operation.
79 pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
80 return Self { key: key, iv: &[0; 0] };
81 }
82}
83
84impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> {
85 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
86 const REQUIRES_PADDING: bool = true;
87
88 fn key(&self) -> &'c [u8] {
89 self.key
90 }
91
92 fn iv(&self) -> &'c [u8] {
93 self.iv
94 }
95
96 fn set_algomode(&self, p: &pac::cryp::Cryp) {
97 #[cfg(cryp_v1)]
98 {
99 p.cr().modify(|w| w.set_algomode(0));
100 }
101 #[cfg(any(cryp_v2, cryp_v3))]
102 {
103 p.cr().modify(|w| w.set_algomode0(0));
104 p.cr().modify(|w| w.set_algomode3(false));
105 }
106 }
107}
108
109impl<'c> CipherSized for TdesEcb<'c, { 112 / 8 }> {}
110impl<'c> CipherSized for TdesEcb<'c, { 168 / 8 }> {}
111impl<'c, const KEY_SIZE: usize> IVSized for TdesEcb<'c, KEY_SIZE> {}
112
113/// TDES-CBC Cipher Mode
114pub struct TdesCbc<'c, const KEY_SIZE: usize> {
115 iv: &'c [u8; 8],
116 key: &'c [u8; KEY_SIZE],
117}
118
119impl<'c, const KEY_SIZE: usize> TdesCbc<'c, KEY_SIZE> {
120 /// Constructs a new TDES-CBC cipher for a cryptographic operation.
121 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self {
122 return Self { key: key, iv: iv };
123 }
124}
125
126impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> {
127 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
128 const REQUIRES_PADDING: bool = true;
129
130 fn key(&self) -> &'c [u8] {
131 self.key
132 }
133
134 fn iv(&self) -> &'c [u8] {
135 self.iv
136 }
137
138 fn set_algomode(&self, p: &pac::cryp::Cryp) {
139 #[cfg(cryp_v1)]
140 {
141 p.cr().modify(|w| w.set_algomode(1));
142 }
143 #[cfg(any(cryp_v2, cryp_v3))]
144 {
145 p.cr().modify(|w| w.set_algomode0(1));
146 p.cr().modify(|w| w.set_algomode3(false));
147 }
148 }
149}
150
151impl<'c> CipherSized for TdesCbc<'c, { 112 / 8 }> {}
152impl<'c> CipherSized for TdesCbc<'c, { 168 / 8 }> {}
153impl<'c, const KEY_SIZE: usize> IVSized for TdesCbc<'c, KEY_SIZE> {}
154
155/// DES-ECB Cipher Mode
156pub struct DesEcb<'c, const KEY_SIZE: usize> {
157 iv: &'c [u8; 0],
158 key: &'c [u8; KEY_SIZE],
159}
160
161impl<'c, const KEY_SIZE: usize> DesEcb<'c, KEY_SIZE> {
162 /// Constructs a new AES-ECB cipher for a cryptographic operation.
163 pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
164 return Self { key: key, iv: &[0; 0] };
165 }
166}
167
168impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> {
169 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
170 const REQUIRES_PADDING: bool = true;
171
172 fn key(&self) -> &'c [u8] {
173 self.key
174 }
175
176 fn iv(&self) -> &'c [u8] {
177 self.iv
178 }
179
180 fn set_algomode(&self, p: &pac::cryp::Cryp) {
181 #[cfg(cryp_v1)]
182 {
183 p.cr().modify(|w| w.set_algomode(2));
184 }
185 #[cfg(any(cryp_v2, cryp_v3))]
186 {
187 p.cr().modify(|w| w.set_algomode0(2));
188 p.cr().modify(|w| w.set_algomode3(false));
189 }
190 }
191}
192
193impl<'c> CipherSized for DesEcb<'c, { 56 / 8 }> {}
194impl<'c, const KEY_SIZE: usize> IVSized for DesEcb<'c, KEY_SIZE> {}
195
196/// DES-CBC Cipher Mode
197pub struct DesCbc<'c, const KEY_SIZE: usize> {
198 iv: &'c [u8; 8],
199 key: &'c [u8; KEY_SIZE],
200}
201
202impl<'c, const KEY_SIZE: usize> DesCbc<'c, KEY_SIZE> {
203 /// Constructs a new AES-CBC cipher for a cryptographic operation.
204 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self {
205 return Self { key: key, iv: iv };
206 }
207}
208
209impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> {
210 const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
211 const REQUIRES_PADDING: bool = true;
212
213 fn key(&self) -> &'c [u8] {
214 self.key
215 }
216
217 fn iv(&self) -> &'c [u8] {
218 self.iv
219 }
220
221 fn set_algomode(&self, p: &pac::cryp::Cryp) {
222 #[cfg(cryp_v1)]
223 {
224 p.cr().modify(|w| w.set_algomode(3));
225 }
226 #[cfg(any(cryp_v2, cryp_v3))]
227 {
228 p.cr().modify(|w| w.set_algomode0(3));
229 p.cr().modify(|w| w.set_algomode3(false));
230 }
231 }
232}
233
234impl<'c> CipherSized for DesCbc<'c, { 56 / 8 }> {}
235impl<'c, const KEY_SIZE: usize> IVSized for DesCbc<'c, KEY_SIZE> {}
236
237/// AES-ECB Cipher Mode
238pub struct AesEcb<'c, const KEY_SIZE: usize> {
239 iv: &'c [u8; 0],
240 key: &'c [u8; KEY_SIZE],
241}
242
243impl<'c, const KEY_SIZE: usize> AesEcb<'c, KEY_SIZE> {
244 /// Constructs a new AES-ECB cipher for a cryptographic operation.
245 pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
246 return Self { key: key, iv: &[0; 0] };
247 }
248}
249
250impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
251 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
252 const REQUIRES_PADDING: bool = true;
253
254 fn key(&self) -> &'c [u8] {
255 self.key
256 }
257
258 fn iv(&self) -> &'c [u8] {
259 self.iv
260 }
261
262 fn prepare_key(&self, p: &pac::cryp::Cryp) {
263 #[cfg(cryp_v1)]
264 {
265 p.cr().modify(|w| w.set_algomode(7));
266 }
267 #[cfg(any(cryp_v2, cryp_v3))]
268 {
269 p.cr().modify(|w| w.set_algomode0(7));
270 p.cr().modify(|w| w.set_algomode3(false));
271 }
272 p.cr().modify(|w| w.set_crypen(true));
273 while p.sr().read().busy() {}
274 }
275
276 fn set_algomode(&self, p: &pac::cryp::Cryp) {
277 #[cfg(cryp_v1)]
278 {
279 p.cr().modify(|w| w.set_algomode(2));
280 }
281 #[cfg(any(cryp_v2, cryp_v3))]
282 {
283 p.cr().modify(|w| w.set_algomode0(2));
284 p.cr().modify(|w| w.set_algomode3(false));
285 }
286 }
287}
288
289impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {}
290impl<'c> CipherSized for AesEcb<'c, { 192 / 8 }> {}
291impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {}
292impl<'c, const KEY_SIZE: usize> IVSized for AesEcb<'c, KEY_SIZE> {}
293
294/// AES-CBC Cipher Mode
295pub struct AesCbc<'c, const KEY_SIZE: usize> {
296 iv: &'c [u8; 16],
297 key: &'c [u8; KEY_SIZE],
298}
299
300impl<'c, const KEY_SIZE: usize> AesCbc<'c, KEY_SIZE> {
301 /// Constructs a new AES-CBC cipher for a cryptographic operation.
302 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
303 return Self { key: key, iv: iv };
304 }
305}
306
307impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
308 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
309 const REQUIRES_PADDING: bool = true;
310
311 fn key(&self) -> &'c [u8] {
312 self.key
313 }
314
315 fn iv(&self) -> &'c [u8] {
316 self.iv
317 }
318
319 fn prepare_key(&self, p: &pac::cryp::Cryp) {
320 #[cfg(cryp_v1)]
321 {
322 p.cr().modify(|w| w.set_algomode(7));
323 }
324 #[cfg(any(cryp_v2, cryp_v3))]
325 {
326 p.cr().modify(|w| w.set_algomode0(7));
327 p.cr().modify(|w| w.set_algomode3(false));
328 }
329 p.cr().modify(|w| w.set_crypen(true));
330 while p.sr().read().busy() {}
331 }
332
333 fn set_algomode(&self, p: &pac::cryp::Cryp) {
334 #[cfg(cryp_v1)]
335 {
336 p.cr().modify(|w| w.set_algomode(5));
337 }
338 #[cfg(any(cryp_v2, cryp_v3))]
339 {
340 p.cr().modify(|w| w.set_algomode0(5));
341 p.cr().modify(|w| w.set_algomode3(false));
342 }
343 }
344}
345
346impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {}
347impl<'c> CipherSized for AesCbc<'c, { 192 / 8 }> {}
348impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {}
349impl<'c, const KEY_SIZE: usize> IVSized for AesCbc<'c, KEY_SIZE> {}
350
351/// AES-CTR Cipher Mode
352pub struct AesCtr<'c, const KEY_SIZE: usize> {
353 iv: &'c [u8; 16],
354 key: &'c [u8; KEY_SIZE],
355}
356
357impl<'c, const KEY_SIZE: usize> AesCtr<'c, KEY_SIZE> {
358 /// Constructs a new AES-CTR cipher for a cryptographic operation.
359 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
360 return Self { key: key, iv: iv };
361 }
362}
363
364impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
365 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
366
367 fn key(&self) -> &'c [u8] {
368 self.key
369 }
370
371 fn iv(&self) -> &'c [u8] {
372 self.iv
373 }
374
375 fn set_algomode(&self, p: &pac::cryp::Cryp) {
376 #[cfg(cryp_v1)]
377 {
378 p.cr().modify(|w| w.set_algomode(6));
379 }
380 #[cfg(any(cryp_v2, cryp_v3))]
381 {
382 p.cr().modify(|w| w.set_algomode0(6));
383 p.cr().modify(|w| w.set_algomode3(false));
384 }
385 }
386}
387
388impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {}
389impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {}
390impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {}
391impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {}
392
393#[cfg(any(cryp_v2, cryp_v3))]
394///AES-GCM Cipher Mode
395pub struct AesGcm<'c, const KEY_SIZE: usize> {
396 iv: [u8; 16],
397 key: &'c [u8; KEY_SIZE],
398}
399
400#[cfg(any(cryp_v2, cryp_v3))]
401impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
402 /// Constucts a new AES-GCM cipher for a cryptographic operation.
403 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
404 let mut new_gcm = Self { key: key, iv: [0; 16] };
405 new_gcm.iv[..12].copy_from_slice(iv);
406 new_gcm.iv[15] = 2;
407 new_gcm
408 }
409}
410
411#[cfg(any(cryp_v2, cryp_v3))]
412impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
413 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
414
415 fn key(&self) -> &'c [u8] {
416 self.key
417 }
418
419 fn iv(&self) -> &[u8] {
420 self.iv.as_slice()
421 }
422
423 fn set_algomode(&self, p: &pac::cryp::Cryp) {
424 p.cr().modify(|w| w.set_algomode0(0));
425 p.cr().modify(|w| w.set_algomode3(true));
426 }
427
428 fn init_phase(&self, p: &pac::cryp::Cryp) {
429 p.cr().modify(|w| w.set_gcm_ccmph(0));
430 p.cr().modify(|w| w.set_crypen(true));
431 while p.cr().read().crypen() {}
432 }
433
434 #[cfg(cryp_v2)]
435 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
436 //Handle special GCM partial block process.
437 if dir == Direction::Encrypt {
438 p.cr().modify(|w| w.set_crypen(false));
439 p.cr().modify(|w| w.set_algomode3(false));
440 p.cr().modify(|w| w.set_algomode0(6));
441 let iv1r = p.csgcmccmr(7).read() - 1;
442 p.init(1).ivrr().write_value(iv1r);
443 p.cr().modify(|w| w.set_crypen(true));
444 }
445 [0; 4]
446 }
447
448 #[cfg(cryp_v3)]
449 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
450 //Handle special GCM partial block process.
451 p.cr().modify(|w| w.set_npblb(padding_len as u8));
452 [0; 4]
453 }
454
455 #[cfg(cryp_v2)]
456 fn post_final_block(
457 &self,
458 p: &pac::cryp::Cryp,
459 dir: Direction,
460 int_data: &mut [u8; AES_BLOCK_SIZE],
461 _temp1: [u32; 4],
462 padding_mask: [u8; AES_BLOCK_SIZE],
463 ) {
464 if dir == Direction::Encrypt {
465 //Handle special GCM partial block process.
466 p.cr().modify(|w| w.set_crypen(false));
467 p.cr().modify(|w| w.set_algomode3(true));
468 p.cr().modify(|w| w.set_algomode0(0));
469 for i in 0..AES_BLOCK_SIZE {
470 int_data[i] = int_data[i] & padding_mask[i];
471 }
472 p.cr().modify(|w| w.set_crypen(true));
473 p.cr().modify(|w| w.set_gcm_ccmph(3));
474 let mut index = 0;
475 let end_index = Self::BLOCK_SIZE;
476 while index < end_index {
477 let mut in_word: [u8; 4] = [0; 4];
478 in_word.copy_from_slice(&int_data[index..index + 4]);
479 p.din().write_value(u32::from_ne_bytes(in_word));
480 index += 4;
481 }
482 for _ in 0..4 {
483 p.dout().read();
484 }
485 }
486 }
487}
488
489#[cfg(any(cryp_v2, cryp_v3))]
490impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {}
491#[cfg(any(cryp_v2, cryp_v3))]
492impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {}
493#[cfg(any(cryp_v2, cryp_v3))]
494impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {}
495#[cfg(any(cryp_v2, cryp_v3))]
496impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {}
497#[cfg(any(cryp_v2, cryp_v3))]
498impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {}
499
500#[cfg(any(cryp_v2, cryp_v3))]
501/// AES-GMAC Cipher Mode
502pub struct AesGmac<'c, const KEY_SIZE: usize> {
503 iv: [u8; 16],
504 key: &'c [u8; KEY_SIZE],
505}
506
507#[cfg(any(cryp_v2, cryp_v3))]
508impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
509 /// Constructs a new AES-GMAC cipher for a cryptographic operation.
510 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
511 let mut new_gmac = Self { key: key, iv: [0; 16] };
512 new_gmac.iv[..12].copy_from_slice(iv);
513 new_gmac.iv[15] = 2;
514 new_gmac
515 }
516}
517
518#[cfg(any(cryp_v2, cryp_v3))]
519impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
520 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
521
522 fn key(&self) -> &'c [u8] {
523 self.key
524 }
525
526 fn iv(&self) -> &[u8] {
527 self.iv.as_slice()
528 }
529
530 fn set_algomode(&self, p: &pac::cryp::Cryp) {
531 p.cr().modify(|w| w.set_algomode0(0));
532 p.cr().modify(|w| w.set_algomode3(true));
533 }
534
535 fn init_phase(&self, p: &pac::cryp::Cryp) {
536 p.cr().modify(|w| w.set_gcm_ccmph(0));
537 p.cr().modify(|w| w.set_crypen(true));
538 while p.cr().read().crypen() {}
539 }
540
541 #[cfg(cryp_v2)]
542 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
543 //Handle special GCM partial block process.
544 if dir == Direction::Encrypt {
545 p.cr().modify(|w| w.set_crypen(false));
546 p.cr().modify(|w| w.set_algomode3(false));
547 p.cr().modify(|w| w.set_algomode0(6));
548 let iv1r = p.csgcmccmr(7).read() - 1;
549 p.init(1).ivrr().write_value(iv1r);
550 p.cr().modify(|w| w.set_crypen(true));
551 }
552 [0; 4]
553 }
554
555 #[cfg(cryp_v3)]
556 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
557 //Handle special GCM partial block process.
558 p.cr().modify(|w| w.set_npblb(padding_len as u8));
559 [0; 4]
560 }
561
562 #[cfg(cryp_v2)]
563 fn post_final_block(
564 &self,
565 p: &pac::cryp::Cryp,
566 dir: Direction,
567 int_data: &mut [u8; AES_BLOCK_SIZE],
568 _temp1: [u32; 4],
569 padding_mask: [u8; AES_BLOCK_SIZE],
570 ) {
571 if dir == Direction::Encrypt {
572 //Handle special GCM partial block process.
573 p.cr().modify(|w| w.set_crypen(false));
574 p.cr().modify(|w| w.set_algomode3(true));
575 p.cr().modify(|w| w.set_algomode0(0));
576 for i in 0..AES_BLOCK_SIZE {
577 int_data[i] = int_data[i] & padding_mask[i];
578 }
579 p.cr().modify(|w| w.set_crypen(true));
580 p.cr().modify(|w| w.set_gcm_ccmph(3));
581 let mut index = 0;
582 let end_index = Self::BLOCK_SIZE;
583 while index < end_index {
584 let mut in_word: [u8; 4] = [0; 4];
585 in_word.copy_from_slice(&int_data[index..index + 4]);
586 p.din().write_value(u32::from_ne_bytes(in_word));
587 index += 4;
588 }
589 for _ in 0..4 {
590 p.dout().read();
591 }
592 }
593 }
594}
595
596#[cfg(any(cryp_v2, cryp_v3))]
597impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {}
598#[cfg(any(cryp_v2, cryp_v3))]
599impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {}
600#[cfg(any(cryp_v2, cryp_v3))]
601impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
602#[cfg(any(cryp_v2, cryp_v3))]
603impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {}
604#[cfg(any(cryp_v2, cryp_v3))]
605impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {}
606
607#[cfg(any(cryp_v2, cryp_v3))]
608/// AES-CCM Cipher Mode
609pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> {
610 key: &'c [u8; KEY_SIZE],
611 aad_header: [u8; 6],
612 aad_header_len: usize,
613 block0: [u8; 16],
614 ctr: [u8; 16],
615}
616
617#[cfg(any(cryp_v2, cryp_v3))]
618impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> {
619 /// Constructs a new AES-CCM cipher for a cryptographic operation.
620 pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self {
621 let mut aad_header: [u8; 6] = [0; 6];
622 let mut aad_header_len = 0;
623 let mut block0: [u8; 16] = [0; 16];
624 if aad_len != 0 {
625 if aad_len < 65280 {
626 aad_header[0] = (aad_len >> 8) as u8 & 0xFF;
627 aad_header[1] = aad_len as u8 & 0xFF;
628 aad_header_len = 2;
629 } else {
630 aad_header[0] = 0xFF;
631 aad_header[1] = 0xFE;
632 let aad_len_bytes: [u8; 4] = aad_len.to_be_bytes();
633 aad_header[2] = aad_len_bytes[0];
634 aad_header[3] = aad_len_bytes[1];
635 aad_header[4] = aad_len_bytes[2];
636 aad_header[5] = aad_len_bytes[3];
637 aad_header_len = 6;
638 }
639 }
640 let total_aad_len = aad_header_len + aad_len;
641 let mut aad_padding_len = 16 - (total_aad_len % 16);
642 if aad_padding_len == 16 {
643 aad_padding_len = 0;
644 }
645 aad_header_len += aad_padding_len;
646 let total_aad_len_padded = aad_header_len + aad_len;
647 if total_aad_len_padded > 0 {
648 block0[0] = 0x40;
649 }
650 block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3;
651 block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07;
652 block0[1..1 + iv.len()].copy_from_slice(iv);
653 let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes();
654 if iv.len() <= 11 {
655 block0[12] = payload_len_bytes[0];
656 } else if payload_len_bytes[0] > 0 {
657 panic!("Message is too large for given IV size.");
658 }
659 if iv.len() <= 12 {
660 block0[13] = payload_len_bytes[1];
661 } else if payload_len_bytes[1] > 0 {
662 panic!("Message is too large for given IV size.");
663 }
664 block0[14] = payload_len_bytes[2];
665 block0[15] = payload_len_bytes[3];
666 let mut ctr: [u8; 16] = [0; 16];
667 ctr[0] = block0[0] & 0x07;
668 ctr[1..1 + iv.len()].copy_from_slice(&block0[1..1 + iv.len()]);
669 ctr[15] = 0x01;
670
671 return Self {
672 key: key,
673 aad_header: aad_header,
674 aad_header_len: aad_header_len,
675 block0: block0,
676 ctr: ctr,
677 };
678 }
679}
680
681#[cfg(any(cryp_v2, cryp_v3))]
682impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c>
683 for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE>
684{
685 const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
686
687 fn key(&self) -> &'c [u8] {
688 self.key
689 }
690
691 fn iv(&self) -> &[u8] {
692 self.ctr.as_slice()
693 }
694
695 fn set_algomode(&self, p: &pac::cryp::Cryp) {
696 p.cr().modify(|w| w.set_algomode0(1));
697 p.cr().modify(|w| w.set_algomode3(true));
698 }
699
700 fn init_phase(&self, p: &pac::cryp::Cryp) {
701 p.cr().modify(|w| w.set_gcm_ccmph(0));
702
703 let mut index = 0;
704 let end_index = index + Self::BLOCK_SIZE;
705 // Write block in
706 while index < end_index {
707 let mut in_word: [u8; 4] = [0; 4];
708 in_word.copy_from_slice(&self.block0[index..index + 4]);
709 p.din().write_value(u32::from_ne_bytes(in_word));
710 index += 4;
711 }
712 p.cr().modify(|w| w.set_crypen(true));
713 while p.cr().read().crypen() {}
714 }
715
716 fn get_header_block(&self) -> &[u8] {
717 return &self.aad_header[0..self.aad_header_len];
718 }
719
720 #[cfg(cryp_v2)]
721 fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
722 //Handle special CCM partial block process.
723 let mut temp1 = [0; 4];
724 if dir == Direction::Decrypt {
725 p.cr().modify(|w| w.set_crypen(false));
726 let iv1temp = p.init(1).ivrr().read();
727 temp1[0] = p.csgcmccmr(0).read().swap_bytes();
728 temp1[1] = p.csgcmccmr(1).read().swap_bytes();
729 temp1[2] = p.csgcmccmr(2).read().swap_bytes();
730 temp1[3] = p.csgcmccmr(3).read().swap_bytes();
731 p.init(1).ivrr().write_value(iv1temp);
732 p.cr().modify(|w| w.set_algomode3(false));
733 p.cr().modify(|w| w.set_algomode0(6));
734 p.cr().modify(|w| w.set_crypen(true));
735 }
736 return temp1;
737 }
738
739 #[cfg(cryp_v3)]
740 fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
741 //Handle special GCM partial block process.
742 p.cr().modify(|w| w.set_npblb(padding_len as u8));
743 [0; 4]
744 }
745
746 #[cfg(cryp_v2)]
747 fn post_final_block(
748 &self,
749 p: &pac::cryp::Cryp,
750 dir: Direction,
751 int_data: &mut [u8; AES_BLOCK_SIZE],
752 temp1: [u32; 4],
753 padding_mask: [u8; 16],
754 ) {
755 if dir == Direction::Decrypt {
756 //Handle special CCM partial block process.
757 let mut temp2 = [0; 4];
758 temp2[0] = p.csgcmccmr(0).read().swap_bytes();
759 temp2[1] = p.csgcmccmr(1).read().swap_bytes();
760 temp2[2] = p.csgcmccmr(2).read().swap_bytes();
761 temp2[3] = p.csgcmccmr(3).read().swap_bytes();
762 p.cr().modify(|w| w.set_algomode3(true));
763 p.cr().modify(|w| w.set_algomode0(1));
764 p.cr().modify(|w| w.set_gcm_ccmph(3));
765 // Header phase
766 p.cr().modify(|w| w.set_gcm_ccmph(1));
767 for i in 0..AES_BLOCK_SIZE {
768 int_data[i] = int_data[i] & padding_mask[i];
769 }
770 let mut in_data: [u32; 4] = [0; 4];
771 for i in 0..in_data.len() {
772 let mut int_bytes: [u8; 4] = [0; 4];
773 int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]);
774 let int_word = u32::from_le_bytes(int_bytes);
775 in_data[i] = int_word;
776 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
777 p.din().write_value(in_data[i]);
778 }
779 }
780 }
781}
782
783#[cfg(any(cryp_v2, cryp_v3))]
784impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {}
785#[cfg(any(cryp_v2, cryp_v3))]
786impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {}
787#[cfg(any(cryp_v2, cryp_v3))]
788impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {}
789#[cfg(any(cryp_v2, cryp_v3))]
790impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {}
791#[cfg(any(cryp_v2, cryp_v3))]
792impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {}
793#[cfg(any(cryp_v2, cryp_v3))]
794impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {}
795#[cfg(any(cryp_v2, cryp_v3))]
796impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {}
797#[cfg(any(cryp_v2, cryp_v3))]
798impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {}
799#[cfg(any(cryp_v2, cryp_v3))]
800impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {}
801#[cfg(any(cryp_v2, cryp_v3))]
802impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {}
803#[cfg(any(cryp_v2, cryp_v3))]
804impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {}
805#[cfg(any(cryp_v2, cryp_v3))]
806impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {}
807#[cfg(any(cryp_v2, cryp_v3))]
808impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {}
809#[cfg(any(cryp_v2, cryp_v3))]
810impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {}
811#[cfg(any(cryp_v2, cryp_v3))]
812impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {}
813#[cfg(any(cryp_v2, cryp_v3))]
814impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {}
815#[cfg(any(cryp_v2, cryp_v3))]
816impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {}
817
818#[allow(dead_code)]
819/// Holds the state information for a cipher operation.
820/// Allows suspending/resuming of cipher operations.
821pub struct Context<'c, C: Cipher<'c> + CipherSized> {
822 phantom_data: PhantomData<&'c C>,
823 cipher: &'c C,
824 dir: Direction,
825 last_block_processed: bool,
826 header_processed: bool,
827 aad_complete: bool,
828 cr: u32,
829 iv: [u32; 4],
830 csgcmccm: [u32; 8],
831 csgcm: [u32; 8],
832 header_len: u64,
833 payload_len: u64,
834 aad_buffer: [u8; 16],
835 aad_buffer_len: usize,
836}
837
838/// Selects whether the crypto processor operates in encryption or decryption mode.
839#[derive(PartialEq, Clone, Copy)]
840pub enum Direction {
841 /// Encryption mode
842 Encrypt,
843 /// Decryption mode
844 Decrypt,
845}
846
847/// Crypto Accelerator Driver
848pub struct Cryp<'d, T: Instance> {
849 _peripheral: PeripheralRef<'d, T>,
850}
851
852impl<'d, T: Instance> Cryp<'d, T> {
853 /// Create a new CRYP driver.
854 pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
855 T::enable_and_reset();
856 into_ref!(peri);
857 let instance = Self { _peripheral: peri };
858 instance
859 }
860
861 /// Start a new cipher operation.
862 /// Key size must be 128, 192, or 256 bits.
863 /// Initialization vector must only be supplied if necessary.
864 /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode.
865 pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> {
866 let mut ctx: Context<'c, C> = Context {
867 dir,
868 last_block_processed: false,
869 cr: 0,
870 iv: [0; 4],
871 csgcmccm: [0; 8],
872 csgcm: [0; 8],
873 aad_complete: false,
874 header_len: 0,
875 payload_len: 0,
876 cipher: cipher,
877 phantom_data: PhantomData,
878 header_processed: false,
879 aad_buffer: [0; 16],
880 aad_buffer_len: 0,
881 };
882
883 T::regs().cr().modify(|w| w.set_crypen(false));
884
885 let key = ctx.cipher.key();
886
887 if key.len() == (128 / 8) {
888 T::regs().cr().modify(|w| w.set_keysize(0));
889 } else if key.len() == (192 / 8) {
890 T::regs().cr().modify(|w| w.set_keysize(1));
891 } else if key.len() == (256 / 8) {
892 T::regs().cr().modify(|w| w.set_keysize(2));
893 }
894
895 self.load_key(key);
896
897 // Set data type to 8-bit. This will match software implementations.
898 T::regs().cr().modify(|w| w.set_datatype(2));
899
900 ctx.cipher.prepare_key(&T::regs());
901
902 ctx.cipher.set_algomode(&T::regs());
903
904 // Set encrypt/decrypt
905 if dir == Direction::Encrypt {
906 T::regs().cr().modify(|w| w.set_algodir(false));
907 } else {
908 T::regs().cr().modify(|w| w.set_algodir(true));
909 }
910
911 // Load the IV into the registers.
912 let iv = ctx.cipher.iv();
913 let mut full_iv: [u8; 16] = [0; 16];
914 full_iv[0..iv.len()].copy_from_slice(iv);
915 let mut iv_idx = 0;
916 let mut iv_word: [u8; 4] = [0; 4];
917 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
918 iv_idx += 4;
919 T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word));
920 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
921 iv_idx += 4;
922 T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
923 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
924 iv_idx += 4;
925 T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
926 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
927 T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
928
929 // Flush in/out FIFOs
930 T::regs().cr().modify(|w| w.fflush());
931
932 ctx.cipher.init_phase(&T::regs());
933
934 self.store_context(&mut ctx);
935
936 ctx
937 }
938
939 #[cfg(any(cryp_v2, cryp_v3))]
940 /// Controls the header phase of cipher processing.
941 /// This function is only valid for GCM, CCM, and GMAC modes.
942 /// It only needs to be called if using one of these modes and there is associated data.
943 /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`.
944 /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block.
945 /// When supplying the last block of AAD, `last_aad_block` must be `true`.
946 pub fn aad_blocking<
947 'c,
948 const TAG_SIZE: usize,
949 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
950 >(
951 &self,
952 ctx: &mut Context<'c, C>,
953 aad: &[u8],
954 last_aad_block: bool,
955 ) {
956 self.load_context(ctx);
957
958 // Perform checks for correctness.
959 if ctx.aad_complete {
960 panic!("Cannot update AAD after starting payload!")
961 }
962
963 ctx.header_len += aad.len() as u64;
964
965 // Header phase
966 T::regs().cr().modify(|w| w.set_crypen(false));
967 T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
968 T::regs().cr().modify(|w| w.set_crypen(true));
969
970 // First write the header B1 block if not yet written.
971 if !ctx.header_processed {
972 ctx.header_processed = true;
973 let header = ctx.cipher.get_header_block();
974 ctx.aad_buffer[0..header.len()].copy_from_slice(header);
975 ctx.aad_buffer_len += header.len();
976 }
977
978 // Fill the header block to make a full block.
979 let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len);
980 ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]);
981 ctx.aad_buffer_len += len_to_copy;
982 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
983 let mut aad_len_remaining = aad.len() - len_to_copy;
984
985 if ctx.aad_buffer_len < C::BLOCK_SIZE {
986 // The buffer isn't full and this is the last buffer, so process it as is (already padded).
987 if last_aad_block {
988 let mut index = 0;
989 let end_index = C::BLOCK_SIZE;
990 // Write block in
991 while index < end_index {
992 let mut in_word: [u8; 4] = [0; 4];
993 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
994 T::regs().din().write_value(u32::from_ne_bytes(in_word));
995 index += 4;
996 }
997 // Block until input FIFO is empty.
998 while !T::regs().sr().read().ifem() {}
999
1000 // Switch to payload phase.
1001 ctx.aad_complete = true;
1002 T::regs().cr().modify(|w| w.set_crypen(false));
1003 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1004 T::regs().cr().modify(|w| w.fflush());
1005 } else {
1006 // Just return because we don't yet have a full block to process.
1007 return;
1008 }
1009 } else {
1010 // Load the full block from the buffer.
1011 let mut index = 0;
1012 let end_index = C::BLOCK_SIZE;
1013 // Write block in
1014 while index < end_index {
1015 let mut in_word: [u8; 4] = [0; 4];
1016 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
1017 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1018 index += 4;
1019 }
1020 // Block until input FIFO is empty.
1021 while !T::regs().sr().read().ifem() {}
1022 }
1023
1024 // Handle a partial block that is passed in.
1025 ctx.aad_buffer_len = 0;
1026 let leftovers = aad_len_remaining % C::BLOCK_SIZE;
1027 ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]);
1028 ctx.aad_buffer_len += leftovers;
1029 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1030 aad_len_remaining -= leftovers;
1031 assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0);
1032
1033 // Load full data blocks into core.
1034 let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
1035 for block in 0..num_full_blocks {
1036 let mut index = len_to_copy + (block * C::BLOCK_SIZE);
1037 let end_index = index + C::BLOCK_SIZE;
1038 // Write block in
1039 while index < end_index {
1040 let mut in_word: [u8; 4] = [0; 4];
1041 in_word.copy_from_slice(&aad[index..index + 4]);
1042 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1043 index += 4;
1044 }
1045 // Block until input FIFO is empty.
1046 while !T::regs().sr().read().ifem() {}
1047 }
1048
1049 if last_aad_block {
1050 if leftovers > 0 {
1051 let mut index = 0;
1052 let end_index = C::BLOCK_SIZE;
1053 // Write block in
1054 while index < end_index {
1055 let mut in_word: [u8; 4] = [0; 4];
1056 in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
1057 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1058 index += 4;
1059 }
1060 // Block until input FIFO is empty.
1061 while !T::regs().sr().read().ifem() {}
1062 }
1063 // Switch to payload phase.
1064 ctx.aad_complete = true;
1065 T::regs().cr().modify(|w| w.set_crypen(false));
1066 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1067 T::regs().cr().modify(|w| w.fflush());
1068 }
1069
1070 self.store_context(ctx);
1071 }
1072
1073 /// Performs encryption/decryption on the provided context.
1074 /// The context determines algorithm, mode, and state of the crypto accelerator.
1075 /// When the last piece of data is supplied, `last_block` should be `true`.
1076 /// This function panics under various mismatches of parameters.
1077 /// Input and output buffer lengths must match.
1078 /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
1079 /// Padding or ciphertext stealing must be managed by the application for these modes.
1080 /// Data must also be a multiple of block size unless `last_block` is `true`.
1081 pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(
1082 &self,
1083 ctx: &mut Context<'c, C>,
1084 input: &[u8],
1085 output: &mut [u8],
1086 last_block: bool,
1087 ) {
1088 self.load_context(ctx);
1089
1090 let last_block_remainder = input.len() % C::BLOCK_SIZE;
1091
1092 // Perform checks for correctness.
1093 if !ctx.aad_complete && ctx.header_len > 0 {
1094 panic!("Additional associated data must be processed first!");
1095 } else if !ctx.aad_complete {
1096 #[cfg(any(cryp_v2, cryp_v3))]
1097 {
1098 ctx.aad_complete = true;
1099 T::regs().cr().modify(|w| w.set_crypen(false));
1100 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1101 T::regs().cr().modify(|w| w.fflush());
1102 T::regs().cr().modify(|w| w.set_crypen(true));
1103 }
1104 }
1105 if ctx.last_block_processed {
1106 panic!("The last block has already been processed!");
1107 }
1108 if input.len() > output.len() {
1109 panic!("Output buffer length must match input length.");
1110 }
1111 if !last_block {
1112 if last_block_remainder != 0 {
1113 panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
1114 }
1115 }
1116 if C::REQUIRES_PADDING {
1117 if last_block_remainder != 0 {
1118 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE);
1119 }
1120 }
1121 if last_block {
1122 ctx.last_block_processed = true;
1123 }
1124
1125 // Load data into core, block by block.
1126 let num_full_blocks = input.len() / C::BLOCK_SIZE;
1127 for block in 0..num_full_blocks {
1128 let mut index = block * C::BLOCK_SIZE;
1129 let end_index = index + C::BLOCK_SIZE;
1130 // Write block in
1131 while index < end_index {
1132 let mut in_word: [u8; 4] = [0; 4];
1133 in_word.copy_from_slice(&input[index..index + 4]);
1134 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1135 index += 4;
1136 }
1137 let mut index = block * C::BLOCK_SIZE;
1138 let end_index = index + C::BLOCK_SIZE;
1139 // Block until there is output to read.
1140 while !T::regs().sr().read().ofne() {}
1141 // Read block out
1142 while index < end_index {
1143 let out_word: u32 = T::regs().dout().read();
1144 output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1145 index += 4;
1146 }
1147 }
1148
1149 // Handle the final block, which is incomplete.
1150 if last_block_remainder > 0 {
1151 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1152 let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len);
1153
1154 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1155 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1156 last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
1157 let mut index = 0;
1158 let end_index = C::BLOCK_SIZE;
1159 // Write block in
1160 while index < end_index {
1161 let mut in_word: [u8; 4] = [0; 4];
1162 in_word.copy_from_slice(&last_block[index..index + 4]);
1163 T::regs().din().write_value(u32::from_ne_bytes(in_word));
1164 index += 4;
1165 }
1166 let mut index = 0;
1167 let end_index = C::BLOCK_SIZE;
1168 // Block until there is output to read.
1169 while !T::regs().sr().read().ofne() {}
1170 // Read block out
1171 while index < end_index {
1172 let out_word: u32 = T::regs().dout().read();
1173 intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1174 index += 4;
1175 }
1176
1177 // Handle the last block depending on mode.
1178 let output_len = output.len();
1179 output[output_len - last_block_remainder..output_len]
1180 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
1181
1182 let mut mask: [u8; 16] = [0; 16];
1183 mask[..last_block_remainder].fill(0xFF);
1184 ctx.cipher
1185 .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask);
1186 }
1187
1188 ctx.payload_len += input.len() as u64;
1189
1190 self.store_context(ctx);
1191 }
1192
1193 #[cfg(any(cryp_v2, cryp_v3))]
1194 /// This function only needs to be called for GCM, CCM, and GMAC modes to
1195 /// generate an authentication tag.
1196 pub fn finish_blocking<
1197 'c,
1198 const TAG_SIZE: usize,
1199 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
1200 >(
1201 &self,
1202 mut ctx: Context<'c, C>,
1203 ) -> [u8; TAG_SIZE] {
1204 self.load_context(&mut ctx);
1205
1206 T::regs().cr().modify(|w| w.set_crypen(false));
1207 T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
1208 T::regs().cr().modify(|w| w.set_crypen(true));
1209
1210 let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32;
1211 let headerlen2: u32 = (ctx.header_len * 8) as u32;
1212 let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32;
1213 let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
1214
1215 #[cfg(cryp_v2)]
1216 {
1217 T::regs().din().write_value(headerlen1.swap_bytes());
1218 T::regs().din().write_value(headerlen2.swap_bytes());
1219 T::regs().din().write_value(payloadlen1.swap_bytes());
1220 T::regs().din().write_value(payloadlen2.swap_bytes());
1221 }
1222
1223 #[cfg(cryp_v3)]
1224 {
1225 T::regs().din().write_value(headerlen1);
1226 T::regs().din().write_value(headerlen2);
1227 T::regs().din().write_value(payloadlen1);
1228 T::regs().din().write_value(payloadlen2);
1229 }
1230
1231 while !T::regs().sr().read().ofne() {}
1232
1233 let mut full_tag: [u8; 16] = [0; 16];
1234 full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1235 full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1236 full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1237 full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
1238 let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
1239 tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
1240
1241 T::regs().cr().modify(|w| w.set_crypen(false));
1242
1243 tag
1244 }
1245
1246 fn load_key(&self, key: &[u8]) {
1247 // Load the key into the registers.
1248 let mut keyidx = 0;
1249 let mut keyword: [u8; 4] = [0; 4];
1250 let keylen = key.len() * 8;
1251 if keylen > 192 {
1252 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1253 keyidx += 4;
1254 T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword));
1255 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1256 keyidx += 4;
1257 T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword));
1258 }
1259 if keylen > 128 {
1260 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1261 keyidx += 4;
1262 T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword));
1263 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1264 keyidx += 4;
1265 T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword));
1266 }
1267 if keylen > 64 {
1268 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1269 keyidx += 4;
1270 T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword));
1271 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1272 keyidx += 4;
1273 T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword));
1274 }
1275 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
1276 keyidx += 4;
1277 T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword));
1278 keyword = [0; 4];
1279 keyword[0..key.len() - keyidx].copy_from_slice(&key[keyidx..key.len()]);
1280 T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword));
1281 }
1282
1283 fn store_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &mut Context<'c, C>) {
1284 // Wait for data block processing to finish.
1285 while !T::regs().sr().read().ifem() {}
1286 while T::regs().sr().read().ofne() {}
1287 while T::regs().sr().read().busy() {}
1288
1289 // Disable crypto processor.
1290 T::regs().cr().modify(|w| w.set_crypen(false));
1291
1292 // Save the peripheral state.
1293 ctx.cr = T::regs().cr().read().0;
1294 ctx.iv[0] = T::regs().init(0).ivlr().read();
1295 ctx.iv[1] = T::regs().init(0).ivrr().read();
1296 ctx.iv[2] = T::regs().init(1).ivlr().read();
1297 ctx.iv[3] = T::regs().init(1).ivrr().read();
1298
1299 #[cfg(any(cryp_v2, cryp_v3))]
1300 for i in 0..8 {
1301 ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read();
1302 ctx.csgcm[i] = T::regs().csgcmr(i).read();
1303 }
1304 }
1305
1306 fn load_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &Context<'c, C>) {
1307 // Reload state registers.
1308 T::regs().cr().write(|w| w.0 = ctx.cr);
1309 T::regs().init(0).ivlr().write_value(ctx.iv[0]);
1310 T::regs().init(0).ivrr().write_value(ctx.iv[1]);
1311 T::regs().init(1).ivlr().write_value(ctx.iv[2]);
1312 T::regs().init(1).ivrr().write_value(ctx.iv[3]);
1313
1314 #[cfg(any(cryp_v2, cryp_v3))]
1315 for i in 0..8 {
1316 T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]);
1317 T::regs().csgcmr(i).write_value(ctx.csgcm[i]);
1318 }
1319 self.load_key(ctx.cipher.key());
1320
1321 // Prepare key if applicable.
1322 ctx.cipher.prepare_key(&T::regs());
1323 T::regs().cr().write(|w| w.0 = ctx.cr);
1324
1325 // Enable crypto processor.
1326 T::regs().cr().modify(|w| w.set_crypen(true));
1327 }
1328}
1329
1330pub(crate) mod sealed {
1331 use super::*;
1332
1333 pub trait Instance {
1334 fn regs() -> pac::cryp::Cryp;
1335 }
1336}
1337
1338/// CRYP instance trait.
1339pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send {
1340 /// Interrupt for this CRYP instance.
1341 type Interrupt: interrupt::typelevel::Interrupt;
1342}
1343
1344foreach_interrupt!(
1345 ($inst:ident, cryp, CRYP, GLOBAL, $irq:ident) => {
1346 impl Instance for peripherals::$inst {
1347 type Interrupt = crate::interrupt::typelevel::$irq;
1348 }
1349
1350 impl sealed::Instance for peripherals::$inst {
1351 fn regs() -> crate::pac::cryp::Cryp {
1352 crate::pac::$inst
1353 }
1354 }
1355 };
1356);
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 31dedf06e..60f9404c2 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -504,29 +504,6 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
504 504
505foreach_peripheral!( 505foreach_peripheral!(
506 (dac, $inst:ident) => { 506 (dac, $inst:ident) => {
507 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
508 #[cfg(any(rcc_h7, rcc_h7rm0433))]
509 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
510 fn frequency() -> crate::time::Hertz {
511 critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 })
512 }
513
514 fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
515 // TODO: Increment refcount?
516 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
517 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
518 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
519 }
520
521 fn disable_with_cs(_cs: critical_section::CriticalSection) {
522 // TODO: Decrement refcount?
523 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
524 }
525 }
526
527 #[cfg(any(rcc_h7, rcc_h7rm0433))]
528 impl crate::rcc::RccPeripheral for peripherals::$inst {}
529
530 impl crate::dac::sealed::Instance for peripherals::$inst { 507 impl crate::dac::sealed::Instance for peripherals::$inst {
531 fn regs() -> &'static crate::pac::dac::Dac { 508 fn regs() -> &'static crate::pac::dac::Dac {
532 &crate::pac::$inst 509 &crate::pac::$inst
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 4d02284b2..826b04a4b 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -394,19 +394,7 @@ where
394 394
395 /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer. 395 /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer.
396 /// The implication is that the input buffer size must be exactly the size of the captured frame. 396 /// The implication is that the input buffer size must be exactly the size of the captured frame.
397 ///
398 /// Note that when `buffer.len() > 0xffff` the capture future requires some real-time guarantees to be upheld
399 /// (must be polled fast enough so the buffers get switched before data is overwritten).
400 /// It is therefore recommended that it is run on higher priority executor.
401 pub async fn capture(&mut self, buffer: &mut [u32]) -> Result<(), Error> { 397 pub async fn capture(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
402 if buffer.len() <= 0xffff {
403 return self.capture_small(buffer).await;
404 } else {
405 return self.capture_giant(buffer).await;
406 }
407 }
408
409 async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
410 let r = self.inner.regs(); 398 let r = self.inner.regs();
411 let src = r.dr().as_ptr() as *mut u32; 399 let src = r.dr().as_ptr() as *mut u32;
412 let request = self.dma.request(); 400 let request = self.dma.request();
@@ -441,116 +429,6 @@ where
441 429
442 result 430 result
443 } 431 }
444
445 #[cfg(not(dma))]
446 async fn capture_giant(&mut self, _buffer: &mut [u32]) -> Result<(), Error> {
447 panic!("capturing to buffers larger than 0xffff is only supported on DMA for now, not on BDMA or GPDMA.");
448 }
449
450 #[cfg(dma)]
451 async fn capture_giant(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
452 use crate::dma::TransferOptions;
453
454 let data_len = buffer.len();
455 let chunk_estimate = data_len / 0xffff;
456
457 let mut chunks = chunk_estimate + 1;
458 while data_len % chunks != 0 {
459 chunks += 1;
460 }
461
462 let chunk_size = data_len / chunks;
463
464 let mut remaining_chunks = chunks - 2;
465
466 let mut m0ar = buffer.as_mut_ptr();
467 let mut m1ar = unsafe { buffer.as_mut_ptr().add(chunk_size) };
468
469 let channel = &mut self.dma;
470 let request = channel.request();
471
472 let r = self.inner.regs();
473 let src = r.dr().as_ptr() as *mut u32;
474
475 let mut transfer = unsafe {
476 crate::dma::DoubleBuffered::new_read(
477 &mut self.dma,
478 request,
479 src,
480 m0ar,
481 m1ar,
482 chunk_size,
483 TransferOptions::default(),
484 )
485 };
486
487 let mut last_chunk_set_for_transfer = false;
488 let mut buffer0_last_accessible = false;
489 let dma_result = poll_fn(|cx| {
490 transfer.set_waker(cx.waker());
491
492 let buffer0_currently_accessible = transfer.is_buffer0_accessible();
493
494 // check if the accessible buffer changed since last poll
495 if buffer0_last_accessible == buffer0_currently_accessible {
496 return Poll::Pending;
497 }
498 buffer0_last_accessible = !buffer0_last_accessible;
499
500 if remaining_chunks != 0 {
501 if remaining_chunks % 2 == 0 && buffer0_currently_accessible {
502 m0ar = unsafe { m0ar.add(2 * chunk_size) };
503 unsafe { transfer.set_buffer0(m0ar) }
504 remaining_chunks -= 1;
505 } else if !buffer0_currently_accessible {
506 m1ar = unsafe { m1ar.add(2 * chunk_size) };
507 unsafe { transfer.set_buffer1(m1ar) };
508 remaining_chunks -= 1;
509 }
510 } else {
511 if buffer0_currently_accessible {
512 unsafe { transfer.set_buffer0(buffer.as_mut_ptr()) }
513 } else {
514 unsafe { transfer.set_buffer1(buffer.as_mut_ptr()) }
515 }
516 if last_chunk_set_for_transfer {
517 transfer.request_stop();
518 return Poll::Ready(());
519 }
520 last_chunk_set_for_transfer = true;
521 }
522 Poll::Pending
523 });
524
525 Self::clear_interrupt_flags();
526 Self::enable_irqs();
527
528 let result = poll_fn(|cx| {
529 STATE.waker.register(cx.waker());
530
531 let ris = crate::pac::DCMI.ris().read();
532 if ris.err_ris() {
533 crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
534 Poll::Ready(Err(Error::PeripheralError))
535 } else if ris.ovr_ris() {
536 crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
537 Poll::Ready(Err(Error::Overrun))
538 } else if ris.frame_ris() {
539 crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
540 Poll::Ready(Ok(()))
541 } else {
542 Poll::Pending
543 }
544 });
545
546 Self::toggle(true);
547
548 let (_, result) = embassy_futures::join::join(dma_result, result).await;
549
550 Self::toggle(false);
551
552 result
553 }
554} 432}
555 433
556mod sealed { 434mod sealed {
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
deleted file mode 100644
index a2b83716d..000000000
--- a/embassy-stm32/src/dma/bdma.rs
+++ /dev/null
@@ -1,733 +0,0 @@
1//! Basic Direct Memory Acccess (BDMA)
2
3use core::future::Future;
4use core::pin::Pin;
5use core::sync::atomic::{fence, AtomicUsize, Ordering};
6use core::task::{Context, Poll, Waker};
7
8use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker;
10
11use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer};
12use super::word::{Word, WordSize};
13use super::Dir;
14use crate::_generated::BDMA_CHANNEL_COUNT;
15use crate::interrupt::typelevel::Interrupt;
16use crate::interrupt::Priority;
17use crate::pac;
18use crate::pac::bdma::{regs, vals};
19
20/// BDMA transfer options.
21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[non_exhaustive]
24pub struct TransferOptions {
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.
30 pub circular: bool,
31 /// Enable half transfer interrupt
32 pub half_transfer_ir: bool,
33 /// Enable transfer complete interrupt
34 pub complete_transfer_ir: bool,
35}
36
37impl Default for TransferOptions {
38 fn default() -> Self {
39 Self {
40 circular: false,
41 half_transfer_ir: false,
42 complete_transfer_ir: true,
43 }
44 }
45}
46
47impl From<WordSize> for vals::Size {
48 fn from(raw: WordSize) -> Self {
49 match raw {
50 WordSize::OneByte => Self::BITS8,
51 WordSize::TwoBytes => Self::BITS16,
52 WordSize::FourBytes => Self::BITS32,
53 }
54 }
55}
56
57impl From<Dir> for vals::Dir {
58 fn from(raw: Dir) -> Self {
59 match raw {
60 Dir::MemoryToPeripheral => Self::FROMMEMORY,
61 Dir::PeripheralToMemory => Self::FROMPERIPHERAL,
62 }
63 }
64}
65
66struct State {
67 ch_wakers: [AtomicWaker; BDMA_CHANNEL_COUNT],
68 complete_count: [AtomicUsize; BDMA_CHANNEL_COUNT],
69}
70
71impl State {
72 const fn new() -> Self {
73 const ZERO: AtomicUsize = AtomicUsize::new(0);
74 const AW: AtomicWaker = AtomicWaker::new();
75 Self {
76 ch_wakers: [AW; BDMA_CHANNEL_COUNT],
77 complete_count: [ZERO; BDMA_CHANNEL_COUNT],
78 }
79 }
80}
81
82static STATE: State = State::new();
83
84/// safety: must be called only once
85pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
86 foreach_interrupt! {
87 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
88 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
89 crate::interrupt::typelevel::$irq::enable();
90 };
91 }
92 crate::_generated::init_bdma();
93}
94
95foreach_dma_channel! {
96 ($channel_peri:ident, BDMA1, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
97 // BDMA1 in H7 doesn't use DMAMUX, which breaks
98 };
99 ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
100 impl sealed::Channel for crate::peripherals::$channel_peri {
101 fn regs(&self) -> pac::bdma::Dma {
102 pac::$dma_peri
103 }
104 fn num(&self) -> usize {
105 $channel_num
106 }
107 fn index(&self) -> usize {
108 $index
109 }
110 fn on_irq() {
111 unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) }
112 }
113 }
114
115 impl Channel for crate::peripherals::$channel_peri {}
116 };
117}
118
119/// Safety: Must be called with a matching set of parameters for a valid dma channel
120pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index: usize) {
121 let isr = dma.isr().read();
122 let cr = dma.ch(channel_num).cr();
123
124 if isr.teif(channel_num) {
125 panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
126 }
127
128 if isr.htif(channel_num) && cr.read().htie() {
129 // Acknowledge half transfer complete interrupt
130 dma.ifcr().write(|w| w.set_htif(channel_num, true));
131 } else if isr.tcif(channel_num) && cr.read().tcie() {
132 // Acknowledge transfer complete interrupt
133 dma.ifcr().write(|w| w.set_tcif(channel_num, true));
134 #[cfg(not(armv6m))]
135 STATE.complete_count[index].fetch_add(1, Ordering::Release);
136 #[cfg(armv6m)]
137 critical_section::with(|_| {
138 let x = STATE.complete_count[index].load(Ordering::Relaxed);
139 STATE.complete_count[index].store(x + 1, Ordering::Release);
140 })
141 } else {
142 return;
143 }
144
145 STATE.ch_wakers[index].wake();
146}
147
148/// DMA request type alias.
149#[cfg(any(bdma_v2, dmamux))]
150pub type Request = u8;
151/// DMA request type alias.
152#[cfg(not(any(bdma_v2, dmamux)))]
153pub type Request = ();
154
155/// DMA channel.
156#[cfg(dmamux)]
157pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
158/// DMA channel.
159#[cfg(not(dmamux))]
160pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
161
162pub(crate) mod sealed {
163 use super::*;
164
165 pub trait Channel {
166 fn regs(&self) -> pac::bdma::Dma;
167 fn num(&self) -> usize;
168 fn index(&self) -> usize;
169 fn on_irq();
170 }
171}
172
173/// DMA transfer.
174#[must_use = "futures do nothing unless you `.await` or poll them"]
175pub struct Transfer<'a, C: Channel> {
176 channel: PeripheralRef<'a, C>,
177}
178
179impl<'a, C: Channel> Transfer<'a, C> {
180 /// Create a new read DMA transfer (peripheral to memory).
181 pub unsafe fn new_read<W: Word>(
182 channel: impl Peripheral<P = C> + 'a,
183 request: Request,
184 peri_addr: *mut W,
185 buf: &'a mut [W],
186 options: TransferOptions,
187 ) -> Self {
188 Self::new_read_raw(channel, request, peri_addr, buf, options)
189 }
190
191 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
192 pub unsafe fn new_read_raw<W: Word>(
193 channel: impl Peripheral<P = C> + 'a,
194 request: Request,
195 peri_addr: *mut W,
196 buf: *mut [W],
197 options: TransferOptions,
198 ) -> Self {
199 into_ref!(channel);
200
201 let (ptr, len) = super::slice_ptr_parts_mut(buf);
202 assert!(len > 0 && len <= 0xFFFF);
203
204 Self::new_inner(
205 channel,
206 request,
207 Dir::PeripheralToMemory,
208 peri_addr as *const u32,
209 ptr as *mut u32,
210 len,
211 true,
212 W::size(),
213 options,
214 )
215 }
216
217 /// Create a new write DMA transfer (memory to peripheral).
218 pub unsafe fn new_write<W: Word>(
219 channel: impl Peripheral<P = C> + 'a,
220 request: Request,
221 buf: &'a [W],
222 peri_addr: *mut W,
223 options: TransferOptions,
224 ) -> Self {
225 Self::new_write_raw(channel, request, buf, peri_addr, options)
226 }
227
228 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
229 pub unsafe fn new_write_raw<W: Word>(
230 channel: impl Peripheral<P = C> + 'a,
231 request: Request,
232 buf: *const [W],
233 peri_addr: *mut W,
234 options: TransferOptions,
235 ) -> Self {
236 into_ref!(channel);
237
238 let (ptr, len) = super::slice_ptr_parts(buf);
239 assert!(len > 0 && len <= 0xFFFF);
240
241 Self::new_inner(
242 channel,
243 request,
244 Dir::MemoryToPeripheral,
245 peri_addr as *const u32,
246 ptr as *mut u32,
247 len,
248 true,
249 W::size(),
250 options,
251 )
252 }
253
254 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
255 pub unsafe fn new_write_repeated<W: Word>(
256 channel: impl Peripheral<P = C> + 'a,
257 request: Request,
258 repeated: &'a W,
259 count: usize,
260 peri_addr: *mut W,
261 options: TransferOptions,
262 ) -> Self {
263 into_ref!(channel);
264
265 Self::new_inner(
266 channel,
267 request,
268 Dir::MemoryToPeripheral,
269 peri_addr as *const u32,
270 repeated as *const W as *mut u32,
271 count,
272 false,
273 W::size(),
274 options,
275 )
276 }
277
278 unsafe fn new_inner(
279 channel: PeripheralRef<'a, C>,
280 _request: Request,
281 dir: Dir,
282 peri_addr: *const u32,
283 mem_addr: *mut u32,
284 mem_len: usize,
285 incr_mem: bool,
286 data_size: WordSize,
287 options: TransferOptions,
288 ) -> Self {
289 let ch = channel.regs().ch(channel.num());
290
291 // "Preceding reads and writes cannot be moved past subsequent writes."
292 fence(Ordering::SeqCst);
293
294 #[cfg(bdma_v2)]
295 critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request)));
296
297 let mut this = Self { channel };
298 this.clear_irqs();
299 STATE.complete_count[this.channel.index()].store(0, Ordering::Release);
300
301 #[cfg(dmamux)]
302 super::dmamux::configure_dmamux(&mut *this.channel, _request);
303
304 ch.par().write_value(peri_addr as u32);
305 ch.mar().write_value(mem_addr as u32);
306 ch.ndtr().write(|w| w.set_ndt(mem_len as u16));
307 ch.cr().write(|w| {
308 w.set_psize(data_size.into());
309 w.set_msize(data_size.into());
310 w.set_minc(incr_mem);
311 w.set_dir(dir.into());
312 w.set_teie(true);
313 w.set_tcie(options.complete_transfer_ir);
314 w.set_htie(options.half_transfer_ir);
315 w.set_circ(options.circular);
316 if options.circular {
317 debug!("Setting circular mode");
318 }
319 w.set_pl(vals::Pl::VERYHIGH);
320 w.set_en(true);
321 });
322
323 this
324 }
325
326 fn clear_irqs(&mut self) {
327 self.channel.regs().ifcr().write(|w| {
328 w.set_tcif(self.channel.num(), true);
329 w.set_teif(self.channel.num(), true);
330 });
331 }
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.
336 pub fn request_stop(&mut self) {
337 let ch = self.channel.regs().ch(self.channel.num());
338
339 // Disable the channel. Keep the IEs enabled so the irqs still fire.
340 ch.cr().write(|w| {
341 w.set_teie(true);
342 w.set_tcie(true);
343 });
344 }
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).
350 pub fn is_running(&mut self) -> bool {
351 let ch = self.channel.regs().ch(self.channel.num());
352 let en = ch.cr().read().en();
353 let circular = ch.cr().read().circ();
354 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
355 en && (circular || !tcif)
356 }
357
358 /// Get the total remaining transfers for the channel.
359 ///
360 /// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop).
361 pub fn get_remaining_transfers(&self) -> u16 {
362 let ch = self.channel.regs().ch(self.channel.num());
363 ch.ndtr().read().ndt()
364 }
365
366 /// Blocking wait until the transfer finishes.
367 pub fn blocking_wait(mut self) {
368 while self.is_running() {}
369 self.request_stop();
370
371 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
372 fence(Ordering::SeqCst);
373
374 core::mem::forget(self);
375 }
376}
377
378impl<'a, C: Channel> Drop for Transfer<'a, C> {
379 fn drop(&mut self) {
380 self.request_stop();
381 while self.is_running() {}
382
383 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
384 fence(Ordering::SeqCst);
385 }
386}
387
388impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
389impl<'a, C: Channel> Future for Transfer<'a, C> {
390 type Output = ();
391 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
392 STATE.ch_wakers[self.channel.index()].register(cx.waker());
393
394 if self.is_running() {
395 Poll::Pending
396 } else {
397 Poll::Ready(())
398 }
399 }
400}
401
402// ==============================
403
404struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
405
406impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
407 fn get_remaining_transfers(&self) -> usize {
408 let ch = self.0.regs().ch(self.0.num());
409 ch.ndtr().read().ndt() as usize
410 }
411
412 fn get_complete_count(&self) -> usize {
413 STATE.complete_count[self.0.index()].load(Ordering::Acquire)
414 }
415
416 fn reset_complete_count(&mut self) -> usize {
417 #[cfg(not(armv6m))]
418 return STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel);
419 #[cfg(armv6m)]
420 return critical_section::with(|_| {
421 let x = STATE.complete_count[self.0.index()].load(Ordering::Acquire);
422 STATE.complete_count[self.0.index()].store(0, Ordering::Release);
423 x
424 });
425 }
426
427 fn set_waker(&mut self, waker: &Waker) {
428 STATE.ch_wakers[self.0.index()].register(waker);
429 }
430}
431
432/// Ringbuffer for reading data using DMA circular mode.
433pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
434 cr: regs::Cr,
435 channel: PeripheralRef<'a, C>,
436 ringbuf: ReadableDmaRingBuffer<'a, W>,
437}
438
439impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
440 /// Create a new ring buffer.
441 pub unsafe fn new(
442 channel: impl Peripheral<P = C> + 'a,
443 _request: Request,
444 peri_addr: *mut W,
445 buffer: &'a mut [W],
446 _options: TransferOptions,
447 ) -> Self {
448 into_ref!(channel);
449
450 let len = buffer.len();
451 assert!(len > 0 && len <= 0xFFFF);
452
453 let dir = Dir::PeripheralToMemory;
454 let data_size = W::size();
455
456 let channel_number = channel.num();
457 let dma = channel.regs();
458
459 // "Preceding reads and writes cannot be moved past subsequent writes."
460 fence(Ordering::SeqCst);
461
462 #[cfg(bdma_v2)]
463 critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request)));
464
465 let mut w = regs::Cr(0);
466 w.set_psize(data_size.into());
467 w.set_msize(data_size.into());
468 w.set_minc(true);
469 w.set_dir(dir.into());
470 w.set_teie(true);
471 w.set_htie(true);
472 w.set_tcie(true);
473 w.set_circ(true);
474 w.set_pl(vals::Pl::VERYHIGH);
475 w.set_en(true);
476
477 let buffer_ptr = buffer.as_mut_ptr();
478 let mut this = Self {
479 channel,
480 cr: w,
481 ringbuf: ReadableDmaRingBuffer::new(buffer),
482 };
483 this.clear_irqs();
484
485 #[cfg(dmamux)]
486 super::dmamux::configure_dmamux(&mut *this.channel, _request);
487
488 let ch = dma.ch(channel_number);
489 ch.par().write_value(peri_addr as u32);
490 ch.mar().write_value(buffer_ptr as u32);
491 ch.ndtr().write(|w| w.set_ndt(len as u16));
492
493 this
494 }
495
496 /// Start the ring buffer operation.
497 ///
498 /// You must call this after creating it for it to work.
499 pub fn start(&mut self) {
500 let ch = self.channel.regs().ch(self.channel.num());
501 ch.cr().write_value(self.cr)
502 }
503
504 /// Clear all data in the ring buffer.
505 pub fn clear(&mut self) {
506 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
507 }
508
509 /// Read elements from the ring buffer
510 /// Return a tuple of the length read and the length remaining in the buffer
511 /// If not all of the elements were read, then there will be some elements in the buffer remaining
512 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
513 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
514 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
515 self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
516 }
517
518 /// Read an exact number of elements from the ringbuffer.
519 ///
520 /// Returns the remaining number of elements available for immediate reading.
521 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
522 ///
523 /// Async/Wake Behavior:
524 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
525 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
526 /// ring buffer was created with a buffer of size 'N':
527 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
528 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
529 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
530 self.ringbuf
531 .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
532 .await
533 }
534
535 /// The capacity of the ringbuffer.
536 pub const fn capacity(&self) -> usize {
537 self.ringbuf.cap()
538 }
539
540 /// Set a waker to be woken when at least one byte is received.
541 pub fn set_waker(&mut self, waker: &Waker) {
542 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
543 }
544
545 fn clear_irqs(&mut self) {
546 let dma = self.channel.regs();
547 dma.ifcr().write(|w| {
548 w.set_htif(self.channel.num(), true);
549 w.set_tcif(self.channel.num(), true);
550 w.set_teif(self.channel.num(), true);
551 });
552 }
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.
557 pub fn request_stop(&mut self) {
558 let ch = self.channel.regs().ch(self.channel.num());
559
560 // Disable the channel. Keep the IEs enabled so the irqs still fire.
561 // If the channel is enabled and transfer is not completed, we need to perform
562 // two separate write access to the CR register to disable the channel.
563 ch.cr().write(|w| {
564 w.set_teie(true);
565 w.set_htie(true);
566 w.set_tcie(true);
567 });
568 }
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).
574 pub fn is_running(&mut self) -> bool {
575 let ch = self.channel.regs().ch(self.channel.num());
576 ch.cr().read().en()
577 }
578}
579
580impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
581 fn drop(&mut self) {
582 self.request_stop();
583 while self.is_running() {}
584
585 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
586 fence(Ordering::SeqCst);
587 }
588}
589
590/// Ringbuffer for writing data using DMA circular mode.
591pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
592 cr: regs::Cr,
593 channel: PeripheralRef<'a, C>,
594 ringbuf: WritableDmaRingBuffer<'a, W>,
595}
596
597impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
598 /// Create a new ring buffer.
599 pub unsafe fn new(
600 channel: impl Peripheral<P = C> + 'a,
601 _request: Request,
602 peri_addr: *mut W,
603 buffer: &'a mut [W],
604 _options: TransferOptions,
605 ) -> Self {
606 into_ref!(channel);
607
608 let len = buffer.len();
609 assert!(len > 0 && len <= 0xFFFF);
610
611 let dir = Dir::MemoryToPeripheral;
612 let data_size = W::size();
613
614 let channel_number = channel.num();
615 let dma = channel.regs();
616
617 // "Preceding reads and writes cannot be moved past subsequent writes."
618 fence(Ordering::SeqCst);
619
620 #[cfg(bdma_v2)]
621 critical_section::with(|_| channel.regs().cselr().modify(|w| w.set_cs(channel.num(), _request)));
622
623 let mut w = regs::Cr(0);
624 w.set_psize(data_size.into());
625 w.set_msize(data_size.into());
626 w.set_minc(true);
627 w.set_dir(dir.into());
628 w.set_teie(true);
629 w.set_htie(true);
630 w.set_tcie(true);
631 w.set_circ(true);
632 w.set_pl(vals::Pl::VERYHIGH);
633 w.set_en(true);
634
635 let buffer_ptr = buffer.as_mut_ptr();
636 let mut this = Self {
637 channel,
638 cr: w,
639 ringbuf: WritableDmaRingBuffer::new(buffer),
640 };
641 this.clear_irqs();
642
643 #[cfg(dmamux)]
644 super::dmamux::configure_dmamux(&mut *this.channel, _request);
645
646 let ch = dma.ch(channel_number);
647 ch.par().write_value(peri_addr as u32);
648 ch.mar().write_value(buffer_ptr as u32);
649 ch.ndtr().write(|w| w.set_ndt(len as u16));
650
651 this
652 }
653
654 /// Start the ring buffer operation.
655 ///
656 /// You must call this after creating it for it to work.
657 pub fn start(&mut self) {
658 let ch = self.channel.regs().ch(self.channel.num());
659 ch.cr().write_value(self.cr)
660 }
661
662 /// Clear all data in the ring buffer.
663 pub fn clear(&mut self) {
664 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
665 }
666
667 /// Write elements to the ring buffer
668 /// Return a tuple of the length written and the length remaining in the buffer
669 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
670 self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
671 }
672
673 /// Write an exact number of elements to the ringbuffer.
674 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
675 self.ringbuf
676 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
677 .await
678 }
679
680 /// The capacity of the ringbuffer.
681 pub const fn capacity(&self) -> usize {
682 self.ringbuf.cap()
683 }
684
685 /// Set a waker to be woken when at least one byte is sent.
686 pub fn set_waker(&mut self, waker: &Waker) {
687 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
688 }
689
690 fn clear_irqs(&mut self) {
691 let dma = self.channel.regs();
692 dma.ifcr().write(|w| {
693 w.set_htif(self.channel.num(), true);
694 w.set_tcif(self.channel.num(), true);
695 w.set_teif(self.channel.num(), true);
696 });
697 }
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.
702 pub fn request_stop(&mut self) {
703 let ch = self.channel.regs().ch(self.channel.num());
704
705 // Disable the channel. Keep the IEs enabled so the irqs still fire.
706 // If the channel is enabled and transfer is not completed, we need to perform
707 // two separate write access to the CR register to disable the channel.
708 ch.cr().write(|w| {
709 w.set_teie(true);
710 w.set_htie(true);
711 w.set_tcie(true);
712 });
713 }
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).
719 pub fn is_running(&mut self) -> bool {
720 let ch = self.channel.regs().ch(self.channel.num());
721 ch.cr().read().en()
722 }
723}
724
725impl<'a, C: Channel, W: Word> Drop for WritableRingBuffer<'a, C, W> {
726 fn drop(&mut self) {
727 self.request_stop();
728 while self.is_running() {}
729
730 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
731 fence(Ordering::SeqCst);
732 }
733}
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
deleted file mode 100644
index 16d02f273..000000000
--- a/embassy-stm32/src/dma/dma.rs
+++ /dev/null
@@ -1,1005 +0,0 @@
1use core::future::Future;
2use core::marker::PhantomData;
3use core::pin::Pin;
4use core::sync::atomic::{fence, AtomicUsize, Ordering};
5use core::task::{Context, Poll, Waker};
6
7use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker;
9
10use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer};
11use super::word::{Word, WordSize};
12use super::Dir;
13use crate::_generated::DMA_CHANNEL_COUNT;
14use crate::interrupt::typelevel::Interrupt;
15use crate::interrupt::Priority;
16use crate::pac::dma::{regs, vals};
17use crate::{interrupt, pac};
18
19/// DMA transfer options.
20#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22#[non_exhaustive]
23pub struct TransferOptions {
24 /// Peripheral burst transfer configuration
25 pub pburst: Burst,
26 /// Memory burst transfer configuration
27 pub mburst: Burst,
28 /// Flow control configuration
29 pub flow_ctrl: FlowControl,
30 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
31 pub fifo_threshold: Option<FifoThreshold>,
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.
37 pub circular: bool,
38 /// Enable half transfer interrupt
39 pub half_transfer_ir: bool,
40 /// Enable transfer complete interrupt
41 pub complete_transfer_ir: bool,
42}
43
44impl Default for TransferOptions {
45 fn default() -> Self {
46 Self {
47 pburst: Burst::Single,
48 mburst: Burst::Single,
49 flow_ctrl: FlowControl::Dma,
50 fifo_threshold: None,
51 circular: false,
52 half_transfer_ir: false,
53 complete_transfer_ir: true,
54 }
55 }
56}
57
58impl From<WordSize> for vals::Size {
59 fn from(raw: WordSize) -> Self {
60 match raw {
61 WordSize::OneByte => Self::BITS8,
62 WordSize::TwoBytes => Self::BITS16,
63 WordSize::FourBytes => Self::BITS32,
64 }
65 }
66}
67
68impl From<Dir> for vals::Dir {
69 fn from(raw: Dir) -> Self {
70 match raw {
71 Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL,
72 Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY,
73 }
74 }
75}
76
77/// DMA transfer burst setting.
78#[derive(Debug, Copy, Clone, PartialEq, Eq)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub enum Burst {
81 /// Single transfer
82 Single,
83 /// Incremental burst of 4 beats
84 Incr4,
85 /// Incremental burst of 8 beats
86 Incr8,
87 /// Incremental burst of 16 beats
88 Incr16,
89}
90
91impl From<Burst> for vals::Burst {
92 fn from(burst: Burst) -> Self {
93 match burst {
94 Burst::Single => vals::Burst::SINGLE,
95 Burst::Incr4 => vals::Burst::INCR4,
96 Burst::Incr8 => vals::Burst::INCR8,
97 Burst::Incr16 => vals::Burst::INCR16,
98 }
99 }
100}
101
102/// DMA flow control setting.
103#[derive(Debug, Copy, Clone, PartialEq, Eq)]
104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
105pub enum FlowControl {
106 /// Flow control by DMA
107 Dma,
108 /// Flow control by peripheral
109 Peripheral,
110}
111
112impl From<FlowControl> for vals::Pfctrl {
113 fn from(flow: FlowControl) -> Self {
114 match flow {
115 FlowControl::Dma => vals::Pfctrl::DMA,
116 FlowControl::Peripheral => vals::Pfctrl::PERIPHERAL,
117 }
118 }
119}
120
121/// DMA FIFO threshold.
122#[derive(Debug, Copy, Clone, PartialEq, Eq)]
123#[cfg_attr(feature = "defmt", derive(defmt::Format))]
124pub enum FifoThreshold {
125 /// 1/4 full FIFO
126 Quarter,
127 /// 1/2 full FIFO
128 Half,
129 /// 3/4 full FIFO
130 ThreeQuarters,
131 /// Full FIFO
132 Full,
133}
134
135impl From<FifoThreshold> for vals::Fth {
136 fn from(value: FifoThreshold) -> Self {
137 match value {
138 FifoThreshold::Quarter => vals::Fth::QUARTER,
139 FifoThreshold::Half => vals::Fth::HALF,
140 FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS,
141 FifoThreshold::Full => vals::Fth::FULL,
142 }
143 }
144}
145
146struct State {
147 ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT],
148 complete_count: [AtomicUsize; DMA_CHANNEL_COUNT],
149}
150
151impl State {
152 const fn new() -> Self {
153 const ZERO: AtomicUsize = AtomicUsize::new(0);
154 const AW: AtomicWaker = AtomicWaker::new();
155 Self {
156 ch_wakers: [AW; DMA_CHANNEL_COUNT],
157 complete_count: [ZERO; DMA_CHANNEL_COUNT],
158 }
159 }
160}
161
162static STATE: State = State::new();
163
164/// safety: must be called only once
165pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
166 foreach_interrupt! {
167 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
168 interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
169 interrupt::typelevel::$irq::enable();
170 };
171 }
172 crate::_generated::init_dma();
173}
174
175foreach_dma_channel! {
176 ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => {
177 impl sealed::Channel for crate::peripherals::$channel_peri {
178 fn regs(&self) -> pac::dma::Dma {
179 pac::$dma_peri
180 }
181 fn num(&self) -> usize {
182 $channel_num
183 }
184 fn index(&self) -> usize {
185 $index
186 }
187 fn on_irq() {
188 unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) }
189 }
190 }
191
192 impl Channel for crate::peripherals::$channel_peri {}
193 };
194}
195
196/// Safety: Must be called with a matching set of parameters for a valid dma channel
197pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: usize) {
198 let cr = dma.st(channel_num).cr();
199 let isr = dma.isr(channel_num / 4).read();
200
201 if isr.teif(channel_num % 4) {
202 panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
203 }
204
205 if isr.htif(channel_num % 4) && cr.read().htie() {
206 // Acknowledge half transfer complete interrupt
207 dma.ifcr(channel_num / 4).write(|w| w.set_htif(channel_num % 4, true));
208 } else if isr.tcif(channel_num % 4) && cr.read().tcie() {
209 // Acknowledge transfer complete interrupt
210 dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
211 STATE.complete_count[index].fetch_add(1, Ordering::Release);
212 } else {
213 return;
214 }
215
216 STATE.ch_wakers[index].wake();
217}
218
219/// DMA request type alias. (also known as DMA channel number in some chips)
220#[cfg(any(dma_v2, dmamux))]
221pub type Request = u8;
222/// DMA request type alias. (also known as DMA channel number in some chips)
223#[cfg(not(any(dma_v2, dmamux)))]
224pub type Request = ();
225
226/// DMA channel.
227#[cfg(dmamux)]
228pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
229/// DMA channel.
230#[cfg(not(dmamux))]
231pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
232
233pub(crate) mod sealed {
234 use super::*;
235
236 pub trait Channel {
237 fn regs(&self) -> pac::dma::Dma;
238 fn num(&self) -> usize;
239 fn index(&self) -> usize;
240 fn on_irq();
241 }
242}
243
244/// DMA transfer.
245#[must_use = "futures do nothing unless you `.await` or poll them"]
246pub struct Transfer<'a, C: Channel> {
247 channel: PeripheralRef<'a, C>,
248}
249
250impl<'a, C: Channel> Transfer<'a, C> {
251 /// Create a new read DMA transfer (peripheral to memory).
252 pub unsafe fn new_read<W: Word>(
253 channel: impl Peripheral<P = C> + 'a,
254 request: Request,
255 peri_addr: *mut W,
256 buf: &'a mut [W],
257 options: TransferOptions,
258 ) -> Self {
259 Self::new_read_raw(channel, request, peri_addr, buf, options)
260 }
261
262 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
263 pub unsafe fn new_read_raw<W: Word>(
264 channel: impl Peripheral<P = C> + 'a,
265 request: Request,
266 peri_addr: *mut W,
267 buf: *mut [W],
268 options: TransferOptions,
269 ) -> Self {
270 into_ref!(channel);
271
272 let (ptr, len) = super::slice_ptr_parts_mut(buf);
273 assert!(len > 0 && len <= 0xFFFF);
274
275 Self::new_inner(
276 channel,
277 request,
278 Dir::PeripheralToMemory,
279 peri_addr as *const u32,
280 ptr as *mut u32,
281 len,
282 true,
283 W::size(),
284 options,
285 )
286 }
287
288 /// Create a new write DMA transfer (memory to peripheral).
289 pub unsafe fn new_write<W: Word>(
290 channel: impl Peripheral<P = C> + 'a,
291 request: Request,
292 buf: &'a [W],
293 peri_addr: *mut W,
294 options: TransferOptions,
295 ) -> Self {
296 Self::new_write_raw(channel, request, buf, peri_addr, options)
297 }
298
299 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
300 pub unsafe fn new_write_raw<W: Word>(
301 channel: impl Peripheral<P = C> + 'a,
302 request: Request,
303 buf: *const [W],
304 peri_addr: *mut W,
305 options: TransferOptions,
306 ) -> Self {
307 into_ref!(channel);
308
309 let (ptr, len) = super::slice_ptr_parts(buf);
310 assert!(len > 0 && len <= 0xFFFF);
311
312 Self::new_inner(
313 channel,
314 request,
315 Dir::MemoryToPeripheral,
316 peri_addr as *const u32,
317 ptr as *mut u32,
318 len,
319 true,
320 W::size(),
321 options,
322 )
323 }
324
325 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
326 pub unsafe fn new_write_repeated<W: Word>(
327 channel: impl Peripheral<P = C> + 'a,
328 request: Request,
329 repeated: &'a W,
330 count: usize,
331 peri_addr: *mut W,
332 options: TransferOptions,
333 ) -> Self {
334 into_ref!(channel);
335
336 Self::new_inner(
337 channel,
338 request,
339 Dir::MemoryToPeripheral,
340 peri_addr as *const u32,
341 repeated as *const W as *mut u32,
342 count,
343 false,
344 W::size(),
345 options,
346 )
347 }
348
349 unsafe fn new_inner(
350 channel: PeripheralRef<'a, C>,
351 _request: Request,
352 dir: Dir,
353 peri_addr: *const u32,
354 mem_addr: *mut u32,
355 mem_len: usize,
356 incr_mem: bool,
357 data_size: WordSize,
358 options: TransferOptions,
359 ) -> Self {
360 let ch = channel.regs().st(channel.num());
361
362 // "Preceding reads and writes cannot be moved past subsequent writes."
363 fence(Ordering::SeqCst);
364
365 let mut this = Self { channel };
366 this.clear_irqs();
367
368 #[cfg(dmamux)]
369 super::dmamux::configure_dmamux(&mut *this.channel, _request);
370
371 ch.par().write_value(peri_addr as u32);
372 ch.m0ar().write_value(mem_addr as u32);
373 ch.ndtr().write_value(regs::Ndtr(mem_len as _));
374 ch.fcr().write(|w| {
375 if let Some(fth) = options.fifo_threshold {
376 // FIFO mode
377 w.set_dmdis(vals::Dmdis::DISABLED);
378 w.set_fth(fth.into());
379 } else {
380 // Direct mode
381 w.set_dmdis(vals::Dmdis::ENABLED);
382 }
383 });
384 ch.cr().write(|w| {
385 w.set_dir(dir.into());
386 w.set_msize(data_size.into());
387 w.set_psize(data_size.into());
388 w.set_pl(vals::Pl::VERYHIGH);
389 w.set_minc(incr_mem);
390 w.set_pinc(false);
391 w.set_teie(true);
392 w.set_tcie(options.complete_transfer_ir);
393 w.set_circ(options.circular);
394 if options.circular {
395 debug!("Setting circular mode");
396 }
397 #[cfg(dma_v1)]
398 w.set_trbuff(true);
399
400 #[cfg(dma_v2)]
401 w.set_chsel(_request);
402
403 w.set_pburst(options.pburst.into());
404 w.set_mburst(options.mburst.into());
405 w.set_pfctrl(options.flow_ctrl.into());
406
407 w.set_en(true);
408 });
409
410 this
411 }
412
413 fn clear_irqs(&mut self) {
414 let isrn = self.channel.num() / 4;
415 let isrbit = self.channel.num() % 4;
416
417 self.channel.regs().ifcr(isrn).write(|w| {
418 w.set_tcif(isrbit, true);
419 w.set_teif(isrbit, true);
420 });
421 }
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.
426 pub fn request_stop(&mut self) {
427 let ch = self.channel.regs().st(self.channel.num());
428
429 // Disable the channel. Keep the IEs enabled so the irqs still fire.
430 ch.cr().write(|w| {
431 w.set_teie(true);
432 w.set_tcie(true);
433 });
434 }
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).
440 pub fn is_running(&mut self) -> bool {
441 let ch = self.channel.regs().st(self.channel.num());
442 ch.cr().read().en()
443 }
444
445 /// Gets the total remaining transfers for the channel
446 /// Note: this will be zero for transfers that completed without cancellation.
447 pub fn get_remaining_transfers(&self) -> u16 {
448 let ch = self.channel.regs().st(self.channel.num());
449 ch.ndtr().read().ndt()
450 }
451
452 /// Blocking wait until the transfer finishes.
453 pub fn blocking_wait(mut self) {
454 while self.is_running() {}
455
456 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
457 fence(Ordering::SeqCst);
458
459 core::mem::forget(self);
460 }
461}
462
463impl<'a, C: Channel> Drop for Transfer<'a, C> {
464 fn drop(&mut self) {
465 self.request_stop();
466 while self.is_running() {}
467
468 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
469 fence(Ordering::SeqCst);
470 }
471}
472
473impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
474impl<'a, C: Channel> Future for Transfer<'a, C> {
475 type Output = ();
476 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
477 STATE.ch_wakers[self.channel.index()].register(cx.waker());
478
479 if self.is_running() {
480 Poll::Pending
481 } else {
482 Poll::Ready(())
483 }
484 }
485}
486
487// ==================================
488
489/// Double-buffered DMA transfer.
490pub struct DoubleBuffered<'a, C: Channel, W: Word> {
491 channel: PeripheralRef<'a, C>,
492 _phantom: PhantomData<W>,
493}
494
495impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
496 /// Create a new read DMA transfer (peripheral to memory).
497 pub unsafe fn new_read(
498 channel: impl Peripheral<P = C> + 'a,
499 _request: Request,
500 peri_addr: *mut W,
501 buf0: *mut W,
502 buf1: *mut W,
503 len: usize,
504 options: TransferOptions,
505 ) -> Self {
506 into_ref!(channel);
507 assert!(len > 0 && len <= 0xFFFF);
508
509 let dir = Dir::PeripheralToMemory;
510 let data_size = W::size();
511
512 let channel_number = channel.num();
513 let dma = channel.regs();
514
515 // "Preceding reads and writes cannot be moved past subsequent writes."
516 fence(Ordering::SeqCst);
517
518 let mut this = Self {
519 channel,
520 _phantom: PhantomData,
521 };
522 this.clear_irqs();
523
524 #[cfg(dmamux)]
525 super::dmamux::configure_dmamux(&mut *this.channel, _request);
526
527 let ch = dma.st(channel_number);
528 ch.par().write_value(peri_addr as u32);
529 ch.m0ar().write_value(buf0 as u32);
530 ch.m1ar().write_value(buf1 as u32);
531 ch.ndtr().write_value(regs::Ndtr(len as _));
532 ch.fcr().write(|w| {
533 if let Some(fth) = options.fifo_threshold {
534 // FIFO mode
535 w.set_dmdis(vals::Dmdis::DISABLED);
536 w.set_fth(fth.into());
537 } else {
538 // Direct mode
539 w.set_dmdis(vals::Dmdis::ENABLED);
540 }
541 });
542 ch.cr().write(|w| {
543 w.set_dir(dir.into());
544 w.set_msize(data_size.into());
545 w.set_psize(data_size.into());
546 w.set_pl(vals::Pl::VERYHIGH);
547 w.set_minc(true);
548 w.set_pinc(false);
549 w.set_teie(true);
550 w.set_tcie(true);
551 #[cfg(dma_v1)]
552 w.set_trbuff(true);
553
554 #[cfg(dma_v2)]
555 w.set_chsel(_request);
556
557 w.set_pburst(options.pburst.into());
558 w.set_mburst(options.mburst.into());
559 w.set_pfctrl(options.flow_ctrl.into());
560
561 w.set_en(true);
562 });
563
564 this
565 }
566
567 fn clear_irqs(&mut self) {
568 let channel_number = self.channel.num();
569 let dma = self.channel.regs();
570 let isrn = channel_number / 4;
571 let isrbit = channel_number % 4;
572
573 dma.ifcr(isrn).write(|w| {
574 w.set_htif(isrbit, true);
575 w.set_tcif(isrbit, true);
576 w.set_teif(isrbit, true);
577 });
578 }
579
580 /// Set the first buffer address.
581 ///
582 /// You may call this while DMA is transferring the other buffer.
583 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
584 let ch = self.channel.regs().st(self.channel.num());
585 ch.m0ar().write_value(buffer as _);
586 }
587
588 /// Set the second buffer address.
589 ///
590 /// You may call this while DMA is transferring the other buffer.
591 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) {
592 let ch = self.channel.regs().st(self.channel.num());
593 ch.m1ar().write_value(buffer as _);
594 }
595
596 /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now)
597 pub fn is_buffer0_accessible(&mut self) -> bool {
598 let ch = self.channel.regs().st(self.channel.num());
599 ch.cr().read().ct() == vals::Ct::MEMORY1
600 }
601
602 /// Set a waker to be woken when one of the buffers is being transferred.
603 pub fn set_waker(&mut self, waker: &Waker) {
604 STATE.ch_wakers[self.channel.index()].register(waker);
605 }
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.
610 pub fn request_stop(&mut self) {
611 let ch = self.channel.regs().st(self.channel.num());
612
613 // Disable the channel. Keep the IEs enabled so the irqs still fire.
614 ch.cr().write(|w| {
615 w.set_teie(true);
616 w.set_tcie(true);
617 });
618 }
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).
624 pub fn is_running(&mut self) -> bool {
625 let ch = self.channel.regs().st(self.channel.num());
626 ch.cr().read().en()
627 }
628
629 /// Gets the total remaining transfers for the channel
630 /// Note: this will be zero for transfers that completed without cancellation.
631 pub fn get_remaining_transfers(&self) -> u16 {
632 let ch = self.channel.regs().st(self.channel.num());
633 ch.ndtr().read().ndt()
634 }
635}
636
637impl<'a, C: Channel, W: Word> Drop for DoubleBuffered<'a, C, W> {
638 fn drop(&mut self) {
639 self.request_stop();
640 while self.is_running() {}
641
642 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
643 fence(Ordering::SeqCst);
644 }
645}
646
647// ==============================
648
649struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
650
651impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
652 fn get_remaining_transfers(&self) -> usize {
653 let ch = self.0.regs().st(self.0.num());
654 ch.ndtr().read().ndt() as usize
655 }
656
657 fn get_complete_count(&self) -> usize {
658 STATE.complete_count[self.0.index()].load(Ordering::Acquire)
659 }
660
661 fn reset_complete_count(&mut self) -> usize {
662 STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
663 }
664
665 fn set_waker(&mut self, waker: &Waker) {
666 STATE.ch_wakers[self.0.index()].register(waker);
667 }
668}
669
670/// Ringbuffer for receiving data using DMA circular mode.
671pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
672 cr: regs::Cr,
673 channel: PeripheralRef<'a, C>,
674 ringbuf: ReadableDmaRingBuffer<'a, W>,
675}
676
677impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
678 /// Create a new ring buffer.
679 pub unsafe fn new(
680 channel: impl Peripheral<P = C> + 'a,
681 _request: Request,
682 peri_addr: *mut W,
683 buffer: &'a mut [W],
684 options: TransferOptions,
685 ) -> Self {
686 into_ref!(channel);
687
688 let len = buffer.len();
689 assert!(len > 0 && len <= 0xFFFF);
690
691 let dir = Dir::PeripheralToMemory;
692 let data_size = W::size();
693
694 let channel_number = channel.num();
695 let dma = channel.regs();
696
697 // "Preceding reads and writes cannot be moved past subsequent writes."
698 fence(Ordering::SeqCst);
699
700 let mut w = regs::Cr(0);
701 w.set_dir(dir.into());
702 w.set_msize(data_size.into());
703 w.set_psize(data_size.into());
704 w.set_pl(vals::Pl::VERYHIGH);
705 w.set_minc(true);
706 w.set_pinc(false);
707 w.set_teie(true);
708 w.set_htie(options.half_transfer_ir);
709 w.set_tcie(true);
710 w.set_circ(true);
711 #[cfg(dma_v1)]
712 w.set_trbuff(true);
713 #[cfg(dma_v2)]
714 w.set_chsel(_request);
715 w.set_pburst(options.pburst.into());
716 w.set_mburst(options.mburst.into());
717 w.set_pfctrl(options.flow_ctrl.into());
718 w.set_en(true);
719
720 let buffer_ptr = buffer.as_mut_ptr();
721 let mut this = Self {
722 channel,
723 cr: w,
724 ringbuf: ReadableDmaRingBuffer::new(buffer),
725 };
726 this.clear_irqs();
727
728 #[cfg(dmamux)]
729 super::dmamux::configure_dmamux(&mut *this.channel, _request);
730
731 let ch = dma.st(channel_number);
732 ch.par().write_value(peri_addr as u32);
733 ch.m0ar().write_value(buffer_ptr as u32);
734 ch.ndtr().write_value(regs::Ndtr(len as _));
735 ch.fcr().write(|w| {
736 if let Some(fth) = options.fifo_threshold {
737 // FIFO mode
738 w.set_dmdis(vals::Dmdis::DISABLED);
739 w.set_fth(fth.into());
740 } else {
741 // Direct mode
742 w.set_dmdis(vals::Dmdis::ENABLED);
743 }
744 });
745
746 this
747 }
748
749 /// Start the ring buffer operation.
750 ///
751 /// You must call this after creating it for it to work.
752 pub fn start(&mut self) {
753 let ch = self.channel.regs().st(self.channel.num());
754 ch.cr().write_value(self.cr);
755 }
756
757 /// Clear all data in the ring buffer.
758 pub fn clear(&mut self) {
759 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
760 }
761
762 /// Read elements from the ring buffer
763 /// Return a tuple of the length read and the length remaining in the buffer
764 /// If not all of the elements were read, then there will be some elements in the buffer remaining
765 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
766 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
767 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
768 self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
769 }
770
771 /// Read an exact number of elements from the ringbuffer.
772 ///
773 /// Returns the remaining number of elements available for immediate reading.
774 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
775 ///
776 /// Async/Wake Behavior:
777 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
778 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
779 /// ring buffer was created with a buffer of size 'N':
780 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
781 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
782 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
783 self.ringbuf
784 .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
785 .await
786 }
787
788 /// The capacity of the ringbuffer
789 pub const fn capacity(&self) -> usize {
790 self.ringbuf.cap()
791 }
792
793 /// Set a waker to be woken when at least one byte is received.
794 pub fn set_waker(&mut self, waker: &Waker) {
795 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
796 }
797
798 fn clear_irqs(&mut self) {
799 let channel_number = self.channel.num();
800 let dma = self.channel.regs();
801 let isrn = channel_number / 4;
802 let isrbit = channel_number % 4;
803
804 dma.ifcr(isrn).write(|w| {
805 w.set_htif(isrbit, true);
806 w.set_tcif(isrbit, true);
807 w.set_teif(isrbit, true);
808 });
809 }
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.
814 pub fn request_stop(&mut self) {
815 let ch = self.channel.regs().st(self.channel.num());
816
817 // Disable the channel. Keep the IEs enabled so the irqs still fire.
818 ch.cr().write(|w| {
819 w.set_teie(true);
820 w.set_htie(true);
821 w.set_tcie(true);
822 });
823 }
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).
829 pub fn is_running(&mut self) -> bool {
830 let ch = self.channel.regs().st(self.channel.num());
831 ch.cr().read().en()
832 }
833}
834
835impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
836 fn drop(&mut self) {
837 self.request_stop();
838 while self.is_running() {}
839
840 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
841 fence(Ordering::SeqCst);
842 }
843}
844
845/// Ringbuffer for writing data using DMA circular mode.
846pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
847 cr: regs::Cr,
848 channel: PeripheralRef<'a, C>,
849 ringbuf: WritableDmaRingBuffer<'a, W>,
850}
851
852impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
853 /// Create a new ring buffer.
854 pub unsafe fn new(
855 channel: impl Peripheral<P = C> + 'a,
856 _request: Request,
857 peri_addr: *mut W,
858 buffer: &'a mut [W],
859 options: TransferOptions,
860 ) -> Self {
861 into_ref!(channel);
862
863 let len = buffer.len();
864 assert!(len > 0 && len <= 0xFFFF);
865
866 let dir = Dir::MemoryToPeripheral;
867 let data_size = W::size();
868
869 let channel_number = channel.num();
870 let dma = channel.regs();
871
872 // "Preceding reads and writes cannot be moved past subsequent writes."
873 fence(Ordering::SeqCst);
874
875 let mut w = regs::Cr(0);
876 w.set_dir(dir.into());
877 w.set_msize(data_size.into());
878 w.set_psize(data_size.into());
879 w.set_pl(vals::Pl::VERYHIGH);
880 w.set_minc(true);
881 w.set_pinc(false);
882 w.set_teie(true);
883 w.set_htie(options.half_transfer_ir);
884 w.set_tcie(true);
885 w.set_circ(true);
886 #[cfg(dma_v1)]
887 w.set_trbuff(true);
888 #[cfg(dma_v2)]
889 w.set_chsel(_request);
890 w.set_pburst(options.pburst.into());
891 w.set_mburst(options.mburst.into());
892 w.set_pfctrl(options.flow_ctrl.into());
893 w.set_en(true);
894
895 let buffer_ptr = buffer.as_mut_ptr();
896 let mut this = Self {
897 channel,
898 cr: w,
899 ringbuf: WritableDmaRingBuffer::new(buffer),
900 };
901 this.clear_irqs();
902
903 #[cfg(dmamux)]
904 super::dmamux::configure_dmamux(&mut *this.channel, _request);
905
906 let ch = dma.st(channel_number);
907 ch.par().write_value(peri_addr as u32);
908 ch.m0ar().write_value(buffer_ptr as u32);
909 ch.ndtr().write_value(regs::Ndtr(len as _));
910 ch.fcr().write(|w| {
911 if let Some(fth) = options.fifo_threshold {
912 // FIFO mode
913 w.set_dmdis(vals::Dmdis::DISABLED);
914 w.set_fth(fth.into());
915 } else {
916 // Direct mode
917 w.set_dmdis(vals::Dmdis::ENABLED);
918 }
919 });
920
921 this
922 }
923
924 /// Start the ring buffer operation.
925 ///
926 /// You must call this after creating it for it to work.
927 pub fn start(&mut self) {
928 let ch = self.channel.regs().st(self.channel.num());
929 ch.cr().write_value(self.cr);
930 }
931
932 /// Clear all data in the ring buffer.
933 pub fn clear(&mut self) {
934 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
935 }
936
937 /// Write elements from the ring buffer
938 /// Return a tuple of the length written and the length remaining in the buffer
939 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
940 self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
941 }
942
943 /// Write an exact number of elements to the ringbuffer.
944 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
945 self.ringbuf
946 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
947 .await
948 }
949
950 /// The capacity of the ringbuffer
951 pub const fn capacity(&self) -> usize {
952 self.ringbuf.cap()
953 }
954
955 /// Set a waker to be woken when at least one byte is received.
956 pub fn set_waker(&mut self, waker: &Waker) {
957 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
958 }
959
960 fn clear_irqs(&mut self) {
961 let channel_number = self.channel.num();
962 let dma = self.channel.regs();
963 let isrn = channel_number / 4;
964 let isrbit = channel_number % 4;
965
966 dma.ifcr(isrn).write(|w| {
967 w.set_htif(isrbit, true);
968 w.set_tcif(isrbit, true);
969 w.set_teif(isrbit, true);
970 });
971 }
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.
976 pub fn request_stop(&mut self) {
977 let ch = self.channel.regs().st(self.channel.num());
978
979 // Disable the channel. Keep the IEs enabled so the irqs still fire.
980 ch.cr().write(|w| {
981 w.set_teie(true);
982 w.set_htie(true);
983 w.set_tcie(true);
984 });
985 }
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).
991 pub fn is_running(&mut self) -> bool {
992 let ch = self.channel.regs().st(self.channel.num());
993 ch.cr().read().en()
994 }
995}
996
997impl<'a, C: Channel, W: Word> Drop for WritableRingBuffer<'a, C, W> {
998 fn drop(&mut self) {
999 self.request_stop();
1000 while self.is_running() {}
1001
1002 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
1003 fence(Ordering::SeqCst);
1004 }
1005}
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
new file mode 100644
index 000000000..08aba2795
--- /dev/null
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -0,0 +1,913 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::sync::atomic::{fence, AtomicUsize, Ordering};
4use core::task::{Context, Poll, Waker};
5
6use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker;
8
9use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer};
10use super::word::{Word, WordSize};
11use super::{AnyChannel, Channel, Dir, Request, STATE};
12use crate::interrupt::typelevel::Interrupt;
13use crate::interrupt::Priority;
14use crate::pac;
15
16pub(crate) struct ChannelInfo {
17 pub(crate) dma: DmaInfo,
18 pub(crate) num: usize,
19 #[cfg(dmamux)]
20 pub(crate) dmamux: super::DmamuxInfo,
21}
22
23#[derive(Clone, Copy)]
24pub(crate) enum DmaInfo {
25 #[cfg(dma)]
26 Dma(pac::dma::Dma),
27 #[cfg(bdma)]
28 Bdma(pac::bdma::Dma),
29}
30
31/// DMA transfer options.
32#[derive(Debug, Copy, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34#[non_exhaustive]
35pub struct TransferOptions {
36 /// Peripheral burst transfer configuration
37 #[cfg(dma)]
38 pub pburst: Burst,
39 /// Memory burst transfer configuration
40 #[cfg(dma)]
41 pub mburst: Burst,
42 /// Flow control configuration
43 #[cfg(dma)]
44 pub flow_ctrl: FlowControl,
45 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
46 #[cfg(dma)]
47 pub fifo_threshold: Option<FifoThreshold>,
48 /// Enable circular DMA
49 ///
50 /// Note:
51 /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task.
52 /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever.
53 pub circular: bool,
54 /// Enable half transfer interrupt
55 pub half_transfer_ir: bool,
56 /// Enable transfer complete interrupt
57 pub complete_transfer_ir: bool,
58}
59
60impl Default for TransferOptions {
61 fn default() -> Self {
62 Self {
63 #[cfg(dma)]
64 pburst: Burst::Single,
65 #[cfg(dma)]
66 mburst: Burst::Single,
67 #[cfg(dma)]
68 flow_ctrl: FlowControl::Dma,
69 #[cfg(dma)]
70 fifo_threshold: None,
71 circular: false,
72 half_transfer_ir: false,
73 complete_transfer_ir: true,
74 }
75 }
76}
77
78#[cfg(dma)]
79pub use dma_only::*;
80#[cfg(dma)]
81mod dma_only {
82 use pac::dma::vals;
83
84 use super::*;
85
86 impl From<WordSize> for vals::Size {
87 fn from(raw: WordSize) -> Self {
88 match raw {
89 WordSize::OneByte => Self::BITS8,
90 WordSize::TwoBytes => Self::BITS16,
91 WordSize::FourBytes => Self::BITS32,
92 }
93 }
94 }
95
96 impl From<Dir> for vals::Dir {
97 fn from(raw: Dir) -> Self {
98 match raw {
99 Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL,
100 Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY,
101 }
102 }
103 }
104
105 /// DMA transfer burst setting.
106 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
107 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
108 pub enum Burst {
109 /// Single transfer
110 Single,
111 /// Incremental burst of 4 beats
112 Incr4,
113 /// Incremental burst of 8 beats
114 Incr8,
115 /// Incremental burst of 16 beats
116 Incr16,
117 }
118
119 impl From<Burst> for vals::Burst {
120 fn from(burst: Burst) -> Self {
121 match burst {
122 Burst::Single => vals::Burst::SINGLE,
123 Burst::Incr4 => vals::Burst::INCR4,
124 Burst::Incr8 => vals::Burst::INCR8,
125 Burst::Incr16 => vals::Burst::INCR16,
126 }
127 }
128 }
129
130 /// DMA flow control setting.
131 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
132 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
133 pub enum FlowControl {
134 /// Flow control by DMA
135 Dma,
136 /// Flow control by peripheral
137 Peripheral,
138 }
139
140 impl From<FlowControl> for vals::Pfctrl {
141 fn from(flow: FlowControl) -> Self {
142 match flow {
143 FlowControl::Dma => vals::Pfctrl::DMA,
144 FlowControl::Peripheral => vals::Pfctrl::PERIPHERAL,
145 }
146 }
147 }
148
149 /// DMA FIFO threshold.
150 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
151 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
152 pub enum FifoThreshold {
153 /// 1/4 full FIFO
154 Quarter,
155 /// 1/2 full FIFO
156 Half,
157 /// 3/4 full FIFO
158 ThreeQuarters,
159 /// Full FIFO
160 Full,
161 }
162
163 impl From<FifoThreshold> for vals::Fth {
164 fn from(value: FifoThreshold) -> Self {
165 match value {
166 FifoThreshold::Quarter => vals::Fth::QUARTER,
167 FifoThreshold::Half => vals::Fth::HALF,
168 FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS,
169 FifoThreshold::Full => vals::Fth::FULL,
170 }
171 }
172 }
173}
174
175#[cfg(bdma)]
176mod bdma_only {
177 use pac::bdma::vals;
178
179 use super::*;
180
181 impl From<WordSize> for vals::Size {
182 fn from(raw: WordSize) -> Self {
183 match raw {
184 WordSize::OneByte => Self::BITS8,
185 WordSize::TwoBytes => Self::BITS16,
186 WordSize::FourBytes => Self::BITS32,
187 }
188 }
189 }
190
191 impl From<Dir> for vals::Dir {
192 fn from(raw: Dir) -> Self {
193 match raw {
194 Dir::MemoryToPeripheral => Self::FROMMEMORY,
195 Dir::PeripheralToMemory => Self::FROMPERIPHERAL,
196 }
197 }
198 }
199}
200
201pub(crate) struct ChannelState {
202 waker: AtomicWaker,
203 complete_count: AtomicUsize,
204}
205
206impl ChannelState {
207 pub(crate) const NEW: Self = Self {
208 waker: AtomicWaker::new(),
209 complete_count: AtomicUsize::new(0),
210 };
211}
212
213/// safety: must be called only once
214pub(crate) unsafe fn init(
215 cs: critical_section::CriticalSection,
216 #[cfg(dma)] dma_priority: Priority,
217 #[cfg(bdma)] bdma_priority: Priority,
218) {
219 foreach_interrupt! {
220 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
221 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority);
222 crate::interrupt::typelevel::$irq::enable();
223 };
224 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
225 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority);
226 crate::interrupt::typelevel::$irq::enable();
227 };
228 }
229 crate::_generated::init_dma();
230 crate::_generated::init_bdma();
231}
232
233impl AnyChannel {
234 /// Safety: Must be called with a matching set of parameters for a valid dma channel
235 pub(crate) unsafe fn on_irq(&self) {
236 let info = self.info();
237 let state = &STATE[self.id as usize];
238 match self.info().dma {
239 #[cfg(dma)]
240 DmaInfo::Dma(r) => {
241 let cr = r.st(info.num).cr();
242 let isr = r.isr(info.num / 4).read();
243
244 if isr.teif(info.num % 4) {
245 panic!("DMA: error on DMA@{:08x} channel {}", r.as_ptr() as u32, info.num);
246 }
247
248 if isr.htif(info.num % 4) && cr.read().htie() {
249 // Acknowledge half transfer complete interrupt
250 r.ifcr(info.num / 4).write(|w| w.set_htif(info.num % 4, true));
251 } else if isr.tcif(info.num % 4) && cr.read().tcie() {
252 // Acknowledge transfer complete interrupt
253 r.ifcr(info.num / 4).write(|w| w.set_tcif(info.num % 4, true));
254 state.complete_count.fetch_add(1, Ordering::Release);
255 } else {
256 return;
257 }
258
259 state.waker.wake();
260 }
261 #[cfg(bdma)]
262 DmaInfo::Bdma(r) => {
263 let isr = r.isr().read();
264 let cr = r.ch(info.num).cr();
265
266 if isr.teif(info.num) {
267 panic!("DMA: error on BDMA@{:08x} channel {}", r.as_ptr() as u32, info.num);
268 }
269
270 if isr.htif(info.num) && cr.read().htie() {
271 // Acknowledge half transfer complete interrupt
272 r.ifcr().write(|w| w.set_htif(info.num, true));
273 } else if isr.tcif(info.num) && cr.read().tcie() {
274 // Acknowledge transfer complete interrupt
275 r.ifcr().write(|w| w.set_tcif(info.num, true));
276 #[cfg(not(armv6m))]
277 state.complete_count.fetch_add(1, Ordering::Release);
278 #[cfg(armv6m)]
279 critical_section::with(|_| {
280 let x = state.complete_count.load(Ordering::Relaxed);
281 state.complete_count.store(x + 1, Ordering::Release);
282 })
283 } else {
284 return;
285 }
286
287 state.waker.wake();
288 }
289 }
290 }
291
292 unsafe fn configure(
293 &self,
294 _request: Request,
295 dir: Dir,
296 peri_addr: *const u32,
297 mem_addr: *mut u32,
298 mem_len: usize,
299 incr_mem: bool,
300 data_size: WordSize,
301 options: TransferOptions,
302 ) {
303 let info = self.info();
304
305 #[cfg(dmamux)]
306 super::dmamux::configure_dmamux(&info.dmamux, _request);
307
308 assert!(mem_len > 0 && mem_len <= 0xFFFF);
309
310 match self.info().dma {
311 #[cfg(dma)]
312 DmaInfo::Dma(r) => {
313 let ch = r.st(info.num);
314
315 // "Preceding reads and writes cannot be moved past subsequent writes."
316 fence(Ordering::SeqCst);
317
318 self.clear_irqs();
319
320 ch.par().write_value(peri_addr as u32);
321 ch.m0ar().write_value(mem_addr as u32);
322 ch.ndtr().write_value(pac::dma::regs::Ndtr(mem_len as _));
323 ch.fcr().write(|w| {
324 if let Some(fth) = options.fifo_threshold {
325 // FIFO mode
326 w.set_dmdis(pac::dma::vals::Dmdis::DISABLED);
327 w.set_fth(fth.into());
328 } else {
329 // Direct mode
330 w.set_dmdis(pac::dma::vals::Dmdis::ENABLED);
331 }
332 });
333 ch.cr().write(|w| {
334 w.set_dir(dir.into());
335 w.set_msize(data_size.into());
336 w.set_psize(data_size.into());
337 w.set_pl(pac::dma::vals::Pl::VERYHIGH);
338 w.set_minc(incr_mem);
339 w.set_pinc(false);
340 w.set_teie(true);
341 w.set_htie(options.half_transfer_ir);
342 w.set_tcie(options.complete_transfer_ir);
343 w.set_circ(options.circular);
344 #[cfg(dma_v1)]
345 w.set_trbuff(true);
346 #[cfg(dma_v2)]
347 w.set_chsel(_request);
348 w.set_pburst(options.pburst.into());
349 w.set_mburst(options.mburst.into());
350 w.set_pfctrl(options.flow_ctrl.into());
351 w.set_en(false); // don't start yet
352 });
353 }
354 #[cfg(bdma)]
355 DmaInfo::Bdma(r) => {
356 #[cfg(bdma_v2)]
357 critical_section::with(|_| r.cselr().modify(|w| w.set_cs(info.num, _request)));
358
359 let state: &ChannelState = &STATE[self.id as usize];
360 let ch = r.ch(info.num);
361
362 state.complete_count.store(0, Ordering::Release);
363 self.clear_irqs();
364
365 ch.par().write_value(peri_addr as u32);
366 ch.mar().write_value(mem_addr as u32);
367 ch.ndtr().write(|w| w.set_ndt(mem_len as u16));
368 ch.cr().write(|w| {
369 w.set_psize(data_size.into());
370 w.set_msize(data_size.into());
371 w.set_minc(incr_mem);
372 w.set_dir(dir.into());
373 w.set_teie(true);
374 w.set_tcie(options.complete_transfer_ir);
375 w.set_htie(options.half_transfer_ir);
376 w.set_circ(options.circular);
377 w.set_pl(pac::bdma::vals::Pl::VERYHIGH);
378 w.set_en(false); // don't start yet
379 });
380 }
381 }
382 }
383
384 fn start(&self) {
385 let info = self.info();
386 match self.info().dma {
387 #[cfg(dma)]
388 DmaInfo::Dma(r) => {
389 let ch = r.st(info.num);
390 ch.cr().modify(|w| w.set_en(true))
391 }
392 #[cfg(bdma)]
393 DmaInfo::Bdma(r) => {
394 let ch = r.ch(info.num);
395 ch.cr().modify(|w| w.set_en(true));
396 }
397 }
398 }
399
400 fn clear_irqs(&self) {
401 let info = self.info();
402 match self.info().dma {
403 #[cfg(dma)]
404 DmaInfo::Dma(r) => {
405 let isrn = info.num / 4;
406 let isrbit = info.num % 4;
407
408 r.ifcr(isrn).write(|w| {
409 w.set_htif(isrbit, true);
410 w.set_tcif(isrbit, true);
411 w.set_teif(isrbit, true);
412 });
413 }
414 #[cfg(bdma)]
415 DmaInfo::Bdma(r) => {
416 r.ifcr().write(|w| {
417 w.set_htif(info.num, true);
418 w.set_tcif(info.num, true);
419 w.set_teif(info.num, true);
420 });
421 }
422 }
423 }
424
425 fn request_stop(&self) {
426 let info = self.info();
427 match self.info().dma {
428 #[cfg(dma)]
429 DmaInfo::Dma(r) => {
430 // Disable the channel. Keep the IEs enabled so the irqs still fire.
431 r.st(info.num).cr().write(|w| {
432 w.set_teie(true);
433 w.set_tcie(true);
434 });
435 }
436 #[cfg(bdma)]
437 DmaInfo::Bdma(r) => {
438 // Disable the channel. Keep the IEs enabled so the irqs still fire.
439 r.ch(info.num).cr().write(|w| {
440 w.set_teie(true);
441 w.set_tcie(true);
442 });
443 }
444 }
445 }
446
447 fn is_running(&self) -> bool {
448 let info = self.info();
449 match self.info().dma {
450 #[cfg(dma)]
451 DmaInfo::Dma(r) => r.st(info.num).cr().read().en(),
452 #[cfg(bdma)]
453 DmaInfo::Bdma(r) => {
454 let state: &ChannelState = &STATE[self.id as usize];
455 let ch = r.ch(info.num);
456 let en = ch.cr().read().en();
457 let circular = ch.cr().read().circ();
458 let tcif = state.complete_count.load(Ordering::Acquire) != 0;
459 en && (circular || !tcif)
460 }
461 }
462 }
463
464 fn get_remaining_transfers(&self) -> u16 {
465 let info = self.info();
466 match self.info().dma {
467 #[cfg(dma)]
468 DmaInfo::Dma(r) => r.st(info.num).ndtr().read().ndt(),
469 #[cfg(bdma)]
470 DmaInfo::Bdma(r) => r.ch(info.num).ndtr().read().ndt(),
471 }
472 }
473}
474
475/// DMA transfer.
476#[must_use = "futures do nothing unless you `.await` or poll them"]
477pub struct Transfer<'a> {
478 channel: PeripheralRef<'a, AnyChannel>,
479}
480
481impl<'a> Transfer<'a> {
482 /// Create a new read DMA transfer (peripheral to memory).
483 pub unsafe fn new_read<W: Word>(
484 channel: impl Peripheral<P = impl Channel> + 'a,
485 request: Request,
486 peri_addr: *mut W,
487 buf: &'a mut [W],
488 options: TransferOptions,
489 ) -> Self {
490 Self::new_read_raw(channel, request, peri_addr, buf, options)
491 }
492
493 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
494 pub unsafe fn new_read_raw<W: Word>(
495 channel: impl Peripheral<P = impl Channel> + 'a,
496 request: Request,
497 peri_addr: *mut W,
498 buf: *mut [W],
499 options: TransferOptions,
500 ) -> Self {
501 into_ref!(channel);
502
503 let (ptr, len) = super::slice_ptr_parts_mut(buf);
504 assert!(len > 0 && len <= 0xFFFF);
505
506 Self::new_inner(
507 channel.map_into(),
508 request,
509 Dir::PeripheralToMemory,
510 peri_addr as *const u32,
511 ptr as *mut u32,
512 len,
513 true,
514 W::size(),
515 options,
516 )
517 }
518
519 /// Create a new write DMA transfer (memory to peripheral).
520 pub unsafe fn new_write<W: Word>(
521 channel: impl Peripheral<P = impl Channel> + 'a,
522 request: Request,
523 buf: &'a [W],
524 peri_addr: *mut W,
525 options: TransferOptions,
526 ) -> Self {
527 Self::new_write_raw(channel, request, buf, peri_addr, options)
528 }
529
530 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
531 pub unsafe fn new_write_raw<W: Word>(
532 channel: impl Peripheral<P = impl Channel> + 'a,
533 request: Request,
534 buf: *const [W],
535 peri_addr: *mut W,
536 options: TransferOptions,
537 ) -> Self {
538 into_ref!(channel);
539
540 let (ptr, len) = super::slice_ptr_parts(buf);
541 assert!(len > 0 && len <= 0xFFFF);
542
543 Self::new_inner(
544 channel.map_into(),
545 request,
546 Dir::MemoryToPeripheral,
547 peri_addr as *const u32,
548 ptr as *mut u32,
549 len,
550 true,
551 W::size(),
552 options,
553 )
554 }
555
556 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
557 pub unsafe fn new_write_repeated<W: Word>(
558 channel: impl Peripheral<P = impl Channel> + 'a,
559 request: Request,
560 repeated: &'a W,
561 count: usize,
562 peri_addr: *mut W,
563 options: TransferOptions,
564 ) -> Self {
565 into_ref!(channel);
566
567 Self::new_inner(
568 channel.map_into(),
569 request,
570 Dir::MemoryToPeripheral,
571 peri_addr as *const u32,
572 repeated as *const W as *mut u32,
573 count,
574 false,
575 W::size(),
576 options,
577 )
578 }
579
580 unsafe fn new_inner(
581 channel: PeripheralRef<'a, AnyChannel>,
582 _request: Request,
583 dir: Dir,
584 peri_addr: *const u32,
585 mem_addr: *mut u32,
586 mem_len: usize,
587 incr_mem: bool,
588 data_size: WordSize,
589 options: TransferOptions,
590 ) -> Self {
591 channel.configure(
592 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, data_size, options,
593 );
594 channel.start();
595
596 Self { channel }
597 }
598
599 /// Request the transfer to stop.
600 ///
601 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
602 pub fn request_stop(&mut self) {
603 self.channel.request_stop()
604 }
605
606 /// Return whether this transfer is still running.
607 ///
608 /// If this returns `false`, it can be because either the transfer finished, or
609 /// it was requested to stop early with [`request_stop`](Self::request_stop).
610 pub fn is_running(&mut self) -> bool {
611 self.channel.is_running()
612 }
613
614 /// Gets the total remaining transfers for the channel
615 /// Note: this will be zero for transfers that completed without cancellation.
616 pub fn get_remaining_transfers(&self) -> u16 {
617 self.channel.get_remaining_transfers()
618 }
619
620 /// Blocking wait until the transfer finishes.
621 pub fn blocking_wait(mut self) {
622 while self.is_running() {}
623
624 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
625 fence(Ordering::SeqCst);
626
627 core::mem::forget(self);
628 }
629}
630
631impl<'a> Drop for Transfer<'a> {
632 fn drop(&mut self) {
633 self.request_stop();
634 while self.is_running() {}
635
636 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
637 fence(Ordering::SeqCst);
638 }
639}
640
641impl<'a> Unpin for Transfer<'a> {}
642impl<'a> Future for Transfer<'a> {
643 type Output = ();
644 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
645 let state: &ChannelState = &STATE[self.channel.id as usize];
646
647 state.waker.register(cx.waker());
648
649 if self.is_running() {
650 Poll::Pending
651 } else {
652 Poll::Ready(())
653 }
654 }
655}
656
657// ==============================
658
659struct DmaCtrlImpl<'a>(PeripheralRef<'a, AnyChannel>);
660
661impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
662 fn get_remaining_transfers(&self) -> usize {
663 self.0.get_remaining_transfers() as _
664 }
665
666 fn get_complete_count(&self) -> usize {
667 STATE[self.0.id as usize].complete_count.load(Ordering::Acquire)
668 }
669
670 fn reset_complete_count(&mut self) -> usize {
671 let state = &STATE[self.0.id as usize];
672 #[cfg(not(armv6m))]
673 return state.complete_count.swap(0, Ordering::AcqRel);
674 #[cfg(armv6m)]
675 return critical_section::with(|_| {
676 let x = state.complete_count.load(Ordering::Acquire);
677 state.complete_count.store(0, Ordering::Release);
678 x
679 });
680 }
681
682 fn set_waker(&mut self, waker: &Waker) {
683 STATE[self.0.id as usize].waker.register(waker);
684 }
685}
686
687/// Ringbuffer for receiving data using DMA circular mode.
688pub struct ReadableRingBuffer<'a, W: Word> {
689 channel: PeripheralRef<'a, AnyChannel>,
690 ringbuf: ReadableDmaRingBuffer<'a, W>,
691}
692
693impl<'a, W: Word> ReadableRingBuffer<'a, W> {
694 /// Create a new ring buffer.
695 pub unsafe fn new(
696 channel: impl Peripheral<P = impl Channel> + 'a,
697 _request: Request,
698 peri_addr: *mut W,
699 buffer: &'a mut [W],
700 mut options: TransferOptions,
701 ) -> Self {
702 into_ref!(channel);
703 let channel: PeripheralRef<'a, AnyChannel> = channel.map_into();
704
705 let buffer_ptr = buffer.as_mut_ptr();
706 let len = buffer.len();
707 let dir = Dir::PeripheralToMemory;
708 let data_size = W::size();
709
710 options.complete_transfer_ir = true;
711 options.circular = true;
712
713 channel.configure(
714 _request,
715 dir,
716 peri_addr as *mut u32,
717 buffer_ptr as *mut u32,
718 len,
719 true,
720 data_size,
721 options,
722 );
723
724 Self {
725 channel,
726 ringbuf: ReadableDmaRingBuffer::new(buffer),
727 }
728 }
729
730 /// Start the ring buffer operation.
731 ///
732 /// You must call this after creating it for it to work.
733 pub fn start(&mut self) {
734 self.channel.start()
735 }
736
737 /// Clear all data in the ring buffer.
738 pub fn clear(&mut self) {
739 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
740 }
741
742 /// Read elements from the ring buffer
743 /// Return a tuple of the length read and the length remaining in the buffer
744 /// If not all of the elements were read, then there will be some elements in the buffer remaining
745 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
746 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
747 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
748 self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
749 }
750
751 /// Read an exact number of elements from the ringbuffer.
752 ///
753 /// Returns the remaining number of elements available for immediate reading.
754 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
755 ///
756 /// Async/Wake Behavior:
757 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
758 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
759 /// ring buffer was created with a buffer of size 'N':
760 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
761 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
762 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
763 self.ringbuf
764 .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
765 .await
766 }
767
768 /// The capacity of the ringbuffer
769 pub const fn capacity(&self) -> usize {
770 self.ringbuf.cap()
771 }
772
773 /// Set a waker to be woken when at least one byte is received.
774 pub fn set_waker(&mut self, waker: &Waker) {
775 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
776 }
777
778 /// Request DMA to stop.
779 ///
780 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
781 pub fn request_stop(&mut self) {
782 self.channel.request_stop()
783 }
784
785 /// Return whether DMA is still running.
786 ///
787 /// If this returns `false`, it can be because either the transfer finished, or
788 /// it was requested to stop early with [`request_stop`](Self::request_stop).
789 pub fn is_running(&mut self) -> bool {
790 self.channel.is_running()
791 }
792}
793
794impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
795 fn drop(&mut self) {
796 self.request_stop();
797 while self.is_running() {}
798
799 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
800 fence(Ordering::SeqCst);
801 }
802}
803
804/// Ringbuffer for writing data using DMA circular mode.
805pub struct WritableRingBuffer<'a, W: Word> {
806 channel: PeripheralRef<'a, AnyChannel>,
807 ringbuf: WritableDmaRingBuffer<'a, W>,
808}
809
810impl<'a, W: Word> WritableRingBuffer<'a, W> {
811 /// Create a new ring buffer.
812 pub unsafe fn new(
813 channel: impl Peripheral<P = impl Channel> + 'a,
814 _request: Request,
815 peri_addr: *mut W,
816 buffer: &'a mut [W],
817 mut options: TransferOptions,
818 ) -> Self {
819 into_ref!(channel);
820 let channel: PeripheralRef<'a, AnyChannel> = channel.map_into();
821
822 let len = buffer.len();
823 let dir = Dir::MemoryToPeripheral;
824 let data_size = W::size();
825 let buffer_ptr = buffer.as_mut_ptr();
826
827 options.complete_transfer_ir = true;
828 options.circular = true;
829
830 channel.configure(
831 _request,
832 dir,
833 peri_addr as *mut u32,
834 buffer_ptr as *mut u32,
835 len,
836 true,
837 data_size,
838 options,
839 );
840
841 Self {
842 channel,
843 ringbuf: WritableDmaRingBuffer::new(buffer),
844 }
845 }
846
847 /// Start the ring buffer operation.
848 ///
849 /// You must call this after creating it for it to work.
850 pub fn start(&mut self) {
851 self.channel.start()
852 }
853
854 /// Clear all data in the ring buffer.
855 pub fn clear(&mut self) {
856 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
857 }
858
859 /// Write elements directly to the raw buffer.
860 /// This can be used to fill the buffer before starting the DMA transfer.
861 #[allow(dead_code)]
862 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
863 self.ringbuf.write_immediate(buf)
864 }
865
866 /// Write elements from the ring buffer
867 /// Return a tuple of the length written and the length remaining in the buffer
868 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
869 self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
870 }
871
872 /// Write an exact number of elements to the ringbuffer.
873 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
874 self.ringbuf
875 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
876 .await
877 }
878
879 /// The capacity of the ringbuffer
880 pub const fn capacity(&self) -> usize {
881 self.ringbuf.cap()
882 }
883
884 /// Set a waker to be woken when at least one byte is received.
885 pub fn set_waker(&mut self, waker: &Waker) {
886 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
887 }
888
889 /// Request DMA to stop.
890 ///
891 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
892 pub fn request_stop(&mut self) {
893 self.channel.request_stop()
894 }
895
896 /// Return whether DMA is still running.
897 ///
898 /// If this returns `false`, it can be because either the transfer finished, or
899 /// it was requested to stop early with [`request_stop`](Self::request_stop).
900 pub fn is_running(&mut self) -> bool {
901 self.channel.is_running()
902 }
903}
904
905impl<'a, W: Word> Drop for WritableRingBuffer<'a, W> {
906 fn drop(&mut self) {
907 self.request_stop();
908 while self.is_running() {}
909
910 // "Subsequent reads and writes cannot be moved ahead of preceding reads."
911 fence(Ordering::SeqCst);
912 }
913}
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
index 9cd494724..1e9ab5944 100644
--- a/embassy-stm32/src/dma/dmamux.rs
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -1,9 +1,14 @@
1#![macro_use] 1#![macro_use]
2 2
3use crate::{pac, peripherals}; 3use crate::pac;
4 4
5pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { 5pub(crate) struct DmamuxInfo {
6 let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); 6 pub(crate) mux: pac::dmamux::Dmamux,
7 pub(crate) num: usize,
8}
9
10pub(crate) fn configure_dmamux(info: &DmamuxInfo, request: u8) {
11 let ch_mux_regs = info.mux.ccr(info.num);
7 ch_mux_regs.write(|reg| { 12 ch_mux_regs.write(|reg| {
8 reg.set_nbreq(0); 13 reg.set_nbreq(0);
9 reg.set_dmareq_id(request); 14 reg.set_dmareq_id(request);
@@ -15,11 +20,7 @@ pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) {
15} 20}
16 21
17pub(crate) mod dmamux_sealed { 22pub(crate) mod dmamux_sealed {
18 use super::*; 23 pub trait MuxChannel {}
19 pub trait MuxChannel {
20 fn mux_regs(&self) -> pac::dmamux::Dmamux;
21 fn mux_num(&self) -> usize;
22 }
23} 24}
24 25
25/// DMAMUX1 instance. 26/// DMAMUX1 instance.
@@ -34,18 +35,11 @@ pub trait MuxChannel: dmamux_sealed::MuxChannel {
34 type Mux; 35 type Mux;
35} 36}
36 37
37foreach_dma_channel! { 38macro_rules! dmamux_channel_impl {
38 ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $index:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { 39 ($channel_peri:ident, $dmamux:ident) => {
39 impl dmamux_sealed::MuxChannel for peripherals::$channel_peri { 40 impl crate::dma::dmamux_sealed::MuxChannel for crate::peripherals::$channel_peri {}
40 fn mux_regs(&self) -> pac::dmamux::Dmamux { 41 impl crate::dma::MuxChannel for crate::peripherals::$channel_peri {
41 pac::$dmamux 42 type Mux = crate::dma::$dmamux;
42 }
43 fn mux_num(&self) -> usize {
44 $dmamux_channel
45 }
46 }
47 impl MuxChannel for peripherals::$channel_peri {
48 type Mux = $dmamux;
49 } 43 }
50 }; 44 };
51} 45}
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index 34b2426b9..ef03970ef 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -9,13 +9,17 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use super::word::{Word, WordSize}; 11use super::word::{Word, WordSize};
12use super::Dir; 12use super::{AnyChannel, Channel, Dir, Request, STATE};
13use crate::_generated::GPDMA_CHANNEL_COUNT;
14use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
15use crate::interrupt::Priority; 14use crate::interrupt::Priority;
16use crate::pac; 15use crate::pac;
17use crate::pac::gpdma::vals; 16use crate::pac::gpdma::vals;
18 17
18pub(crate) struct ChannelInfo {
19 pub(crate) dma: pac::gpdma::Gpdma,
20 pub(crate) num: usize,
21}
22
19/// GPDMA transfer options. 23/// GPDMA transfer options.
20#[derive(Debug, Copy, Clone, PartialEq, Eq)] 24#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))] 25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -38,21 +42,16 @@ impl From<WordSize> for vals::ChTr1Dw {
38 } 42 }
39} 43}
40 44
41struct State { 45pub(crate) struct ChannelState {
42 ch_wakers: [AtomicWaker; GPDMA_CHANNEL_COUNT], 46 waker: AtomicWaker,
43} 47}
44 48
45impl State { 49impl ChannelState {
46 const fn new() -> Self { 50 pub(crate) const NEW: Self = Self {
47 const AW: AtomicWaker = AtomicWaker::new(); 51 waker: AtomicWaker::new(),
48 Self { 52 };
49 ch_wakers: [AW; GPDMA_CHANNEL_COUNT],
50 }
51 }
52} 53}
53 54
54static STATE: State = State::new();
55
56/// safety: must be called only once 55/// safety: must be called only once
57pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) { 56pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
58 foreach_interrupt! { 57 foreach_interrupt! {
@@ -64,87 +63,50 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: P
64 crate::_generated::init_gpdma(); 63 crate::_generated::init_gpdma();
65} 64}
66 65
67foreach_dma_channel! { 66impl AnyChannel {
68 ($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => { 67 /// Safety: Must be called with a matching set of parameters for a valid dma channel
69 impl sealed::Channel for crate::peripherals::$channel_peri { 68 pub(crate) unsafe fn on_irq(&self) {
70 fn regs(&self) -> pac::gpdma::Gpdma { 69 let info = self.info();
71 pac::$dma_peri 70 let state = &STATE[self.id as usize];
72 }
73 fn num(&self) -> usize {
74 $channel_num
75 }
76 fn index(&self) -> usize {
77 $index
78 }
79 fn on_irq() {
80 unsafe { on_irq_inner(pac::$dma_peri, $channel_num, $index) }
81 }
82 }
83
84 impl Channel for crate::peripherals::$channel_peri {}
85 };
86}
87
88/// Safety: Must be called with a matching set of parameters for a valid dma channel
89pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, index: usize) {
90 let ch = dma.ch(channel_num);
91 let sr = ch.sr().read();
92
93 if sr.dtef() {
94 panic!(
95 "DMA: data transfer error on DMA@{:08x} channel {}",
96 dma.as_ptr() as u32,
97 channel_num
98 );
99 }
100 if sr.usef() {
101 panic!(
102 "DMA: user settings error on DMA@{:08x} channel {}",
103 dma.as_ptr() as u32,
104 channel_num
105 );
106 }
107
108 if sr.suspf() || sr.tcf() {
109 // disable all xxIEs to prevent the irq from firing again.
110 ch.cr().write(|_| {});
111
112 // Wake the future. It'll look at tcf and see it's set.
113 STATE.ch_wakers[index].wake();
114 }
115}
116 71
117/// DMA request type alias. (also known as DMA channel number in some chips) 72 let ch = info.dma.ch(info.num);
118pub type Request = u8; 73 let sr = ch.sr().read();
119 74
120/// DMA channel. 75 if sr.dtef() {
121#[cfg(dmamux)] 76 panic!(
122pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 77 "DMA: data transfer error on DMA@{:08x} channel {}",
123/// DMA channel. 78 info.dma.as_ptr() as u32,
124#[cfg(not(dmamux))] 79 info.num
125pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 80 );
81 }
82 if sr.usef() {
83 panic!(
84 "DMA: user settings error on DMA@{:08x} channel {}",
85 info.dma.as_ptr() as u32,
86 info.num
87 );
88 }
126 89
127pub(crate) mod sealed { 90 if sr.suspf() || sr.tcf() {
128 use super::*; 91 // disable all xxIEs to prevent the irq from firing again.
92 ch.cr().write(|_| {});
129 93
130 pub trait Channel { 94 // Wake the future. It'll look at tcf and see it's set.
131 fn regs(&self) -> pac::gpdma::Gpdma; 95 state.waker.wake();
132 fn num(&self) -> usize; 96 }
133 fn index(&self) -> usize;
134 fn on_irq();
135 } 97 }
136} 98}
137 99
138/// DMA transfer. 100/// DMA transfer.
139#[must_use = "futures do nothing unless you `.await` or poll them"] 101#[must_use = "futures do nothing unless you `.await` or poll them"]
140pub struct Transfer<'a, C: Channel> { 102pub struct Transfer<'a> {
141 channel: PeripheralRef<'a, C>, 103 channel: PeripheralRef<'a, AnyChannel>,
142} 104}
143 105
144impl<'a, C: Channel> Transfer<'a, C> { 106impl<'a> Transfer<'a> {
145 /// Create a new read DMA transfer (peripheral to memory). 107 /// Create a new read DMA transfer (peripheral to memory).
146 pub unsafe fn new_read<W: Word>( 108 pub unsafe fn new_read<W: Word>(
147 channel: impl Peripheral<P = C> + 'a, 109 channel: impl Peripheral<P = impl Channel> + 'a,
148 request: Request, 110 request: Request,
149 peri_addr: *mut W, 111 peri_addr: *mut W,
150 buf: &'a mut [W], 112 buf: &'a mut [W],
@@ -155,7 +117,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
155 117
156 /// Create a new read DMA transfer (peripheral to memory), using raw pointers. 118 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
157 pub unsafe fn new_read_raw<W: Word>( 119 pub unsafe fn new_read_raw<W: Word>(
158 channel: impl Peripheral<P = C> + 'a, 120 channel: impl Peripheral<P = impl Channel> + 'a,
159 request: Request, 121 request: Request,
160 peri_addr: *mut W, 122 peri_addr: *mut W,
161 buf: *mut [W], 123 buf: *mut [W],
@@ -167,7 +129,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
167 assert!(len > 0 && len <= 0xFFFF); 129 assert!(len > 0 && len <= 0xFFFF);
168 130
169 Self::new_inner( 131 Self::new_inner(
170 channel, 132 channel.map_into(),
171 request, 133 request,
172 Dir::PeripheralToMemory, 134 Dir::PeripheralToMemory,
173 peri_addr as *const u32, 135 peri_addr as *const u32,
@@ -181,7 +143,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
181 143
182 /// Create a new write DMA transfer (memory to peripheral). 144 /// Create a new write DMA transfer (memory to peripheral).
183 pub unsafe fn new_write<W: Word>( 145 pub unsafe fn new_write<W: Word>(
184 channel: impl Peripheral<P = C> + 'a, 146 channel: impl Peripheral<P = impl Channel> + 'a,
185 request: Request, 147 request: Request,
186 buf: &'a [W], 148 buf: &'a [W],
187 peri_addr: *mut W, 149 peri_addr: *mut W,
@@ -192,7 +154,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
192 154
193 /// Create a new write DMA transfer (memory to peripheral), using raw pointers. 155 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
194 pub unsafe fn new_write_raw<W: Word>( 156 pub unsafe fn new_write_raw<W: Word>(
195 channel: impl Peripheral<P = C> + 'a, 157 channel: impl Peripheral<P = impl Channel> + 'a,
196 request: Request, 158 request: Request,
197 buf: *const [W], 159 buf: *const [W],
198 peri_addr: *mut W, 160 peri_addr: *mut W,
@@ -204,7 +166,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
204 assert!(len > 0 && len <= 0xFFFF); 166 assert!(len > 0 && len <= 0xFFFF);
205 167
206 Self::new_inner( 168 Self::new_inner(
207 channel, 169 channel.map_into(),
208 request, 170 request,
209 Dir::MemoryToPeripheral, 171 Dir::MemoryToPeripheral,
210 peri_addr as *const u32, 172 peri_addr as *const u32,
@@ -218,7 +180,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
218 180
219 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. 181 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
220 pub unsafe fn new_write_repeated<W: Word>( 182 pub unsafe fn new_write_repeated<W: Word>(
221 channel: impl Peripheral<P = C> + 'a, 183 channel: impl Peripheral<P = impl Channel> + 'a,
222 request: Request, 184 request: Request,
223 repeated: &'a W, 185 repeated: &'a W,
224 count: usize, 186 count: usize,
@@ -228,7 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
228 into_ref!(channel); 190 into_ref!(channel);
229 191
230 Self::new_inner( 192 Self::new_inner(
231 channel, 193 channel.map_into(),
232 request, 194 request,
233 Dir::MemoryToPeripheral, 195 Dir::MemoryToPeripheral,
234 peri_addr as *const u32, 196 peri_addr as *const u32,
@@ -241,7 +203,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
241 } 203 }
242 204
243 unsafe fn new_inner( 205 unsafe fn new_inner(
244 channel: PeripheralRef<'a, C>, 206 channel: PeripheralRef<'a, AnyChannel>,
245 request: Request, 207 request: Request,
246 dir: Dir, 208 dir: Dir,
247 peri_addr: *const u32, 209 peri_addr: *const u32,
@@ -251,7 +213,8 @@ impl<'a, C: Channel> Transfer<'a, C> {
251 data_size: WordSize, 213 data_size: WordSize,
252 _options: TransferOptions, 214 _options: TransferOptions,
253 ) -> Self { 215 ) -> Self {
254 let ch = channel.regs().ch(channel.num()); 216 let info = channel.info();
217 let ch = info.dma.ch(info.num);
255 218
256 // "Preceding reads and writes cannot be moved past subsequent writes." 219 // "Preceding reads and writes cannot be moved past subsequent writes."
257 fence(Ordering::SeqCst); 220 fence(Ordering::SeqCst);
@@ -259,7 +222,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
259 let this = Self { channel }; 222 let this = Self { channel };
260 223
261 #[cfg(dmamux)] 224 #[cfg(dmamux)]
262 super::dmamux::configure_dmamux(&mut *this.channel, request); 225 super::dmamux::configure_dmamux(&*this.channel, request);
263 226
264 ch.cr().write(|w| w.set_reset(true)); 227 ch.cr().write(|w| w.set_reset(true));
265 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs 228 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs
@@ -311,10 +274,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
311 /// 274 ///
312 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. 275 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
313 pub fn request_stop(&mut self) { 276 pub fn request_stop(&mut self) {
314 let ch = self.channel.regs().ch(self.channel.num()); 277 let info = self.channel.info();
315 ch.cr().modify(|w| { 278 let ch = info.dma.ch(info.num);
316 w.set_susp(true); 279
317 }) 280 ch.cr().modify(|w| w.set_susp(true))
318 } 281 }
319 282
320 /// Return whether this transfer is still running. 283 /// Return whether this transfer is still running.
@@ -322,7 +285,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
322 /// If this returns `false`, it can be because either the transfer finished, or 285 /// 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). 286 /// it was requested to stop early with [`request_stop`](Self::request_stop).
324 pub fn is_running(&mut self) -> bool { 287 pub fn is_running(&mut self) -> bool {
325 let ch = self.channel.regs().ch(self.channel.num()); 288 let info = self.channel.info();
289 let ch = info.dma.ch(info.num);
290
326 let sr = ch.sr().read(); 291 let sr = ch.sr().read();
327 !sr.tcf() && !sr.suspf() 292 !sr.tcf() && !sr.suspf()
328 } 293 }
@@ -330,7 +295,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
330 /// Gets the total remaining transfers for the channel 295 /// Gets the total remaining transfers for the channel
331 /// Note: this will be zero for transfers that completed without cancellation. 296 /// Note: this will be zero for transfers that completed without cancellation.
332 pub fn get_remaining_transfers(&self) -> u16 { 297 pub fn get_remaining_transfers(&self) -> u16 {
333 let ch = self.channel.regs().ch(self.channel.num()); 298 let info = self.channel.info();
299 let ch = info.dma.ch(info.num);
300
334 ch.br1().read().bndt() 301 ch.br1().read().bndt()
335 } 302 }
336 303
@@ -345,7 +312,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
345 } 312 }
346} 313}
347 314
348impl<'a, C: Channel> Drop for Transfer<'a, C> { 315impl<'a> Drop for Transfer<'a> {
349 fn drop(&mut self) { 316 fn drop(&mut self) {
350 self.request_stop(); 317 self.request_stop();
351 while self.is_running() {} 318 while self.is_running() {}
@@ -355,11 +322,12 @@ impl<'a, C: Channel> Drop for Transfer<'a, C> {
355 } 322 }
356} 323}
357 324
358impl<'a, C: Channel> Unpin for Transfer<'a, C> {} 325impl<'a> Unpin for Transfer<'a> {}
359impl<'a, C: Channel> Future for Transfer<'a, C> { 326impl<'a> Future for Transfer<'a> {
360 type Output = (); 327 type Output = ();
361 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 328 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
362 STATE.ch_wakers[self.channel.index()].register(cx.waker()); 329 let state = &STATE[self.channel.id as usize];
330 state.waker.register(cx.waker());
363 331
364 if self.is_running() { 332 if self.is_running() {
365 Poll::Pending 333 Poll::Pending
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 38945ac33..960483f34 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -1,19 +1,10 @@
1//! Direct Memory Access (DMA) 1//! Direct Memory Access (DMA)
2#![macro_use]
2 3
3#[cfg(dma)] 4#[cfg(any(bdma, dma))]
4pub(crate) mod dma; 5mod dma_bdma;
5#[cfg(dma)] 6#[cfg(any(bdma, dma))]
6pub use dma::*; 7pub use dma_bdma::*;
7
8// stm32h7 has both dma and bdma. In that case, we export dma as "main" dma,
9// and bdma as "secondary", under `embassy_stm32::dma::bdma`.
10#[cfg(all(bdma, dma))]
11pub mod bdma;
12
13#[cfg(all(bdma, not(dma)))]
14pub(crate) mod bdma;
15#[cfg(all(bdma, not(dma)))]
16pub use bdma::*;
17 8
18#[cfg(gpdma)] 9#[cfg(gpdma)]
19pub(crate) mod gpdma; 10pub(crate) mod gpdma;
@@ -22,16 +13,16 @@ pub use gpdma::*;
22 13
23#[cfg(dmamux)] 14#[cfg(dmamux)]
24mod dmamux; 15mod dmamux;
16#[cfg(dmamux)]
17pub use dmamux::*;
25 18
26pub(crate) mod ringbuffer; 19pub(crate) mod ringbuffer;
27pub mod word; 20pub mod word;
28 21
29use core::mem; 22use core::mem;
30 23
31use embassy_hal_internal::impl_peripheral; 24use embassy_hal_internal::{impl_peripheral, Peripheral};
32 25
33#[cfg(dmamux)]
34pub use self::dmamux::*;
35use crate::interrupt::Priority; 26use crate::interrupt::Priority;
36 27
37#[derive(Debug, Copy, Clone, PartialEq, Eq)] 28#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -41,6 +32,80 @@ enum Dir {
41 PeripheralToMemory, 32 PeripheralToMemory,
42} 33}
43 34
35/// DMA request type alias. (also known as DMA channel number in some chips)
36#[cfg(any(dma_v2, bdma_v2, gpdma, dmamux))]
37pub type Request = u8;
38/// DMA request type alias. (also known as DMA channel number in some chips)
39#[cfg(not(any(dma_v2, bdma_v2, gpdma, dmamux)))]
40pub type Request = ();
41
42pub(crate) mod sealed {
43 pub trait Channel {
44 fn id(&self) -> u8;
45 }
46 pub trait ChannelInterrupt {
47 unsafe fn on_irq();
48 }
49}
50
51/// DMA channel.
52pub trait Channel: sealed::Channel + Peripheral<P = Self> + Into<AnyChannel> + 'static {
53 /// Type-erase (degrade) this pin into an `AnyChannel`.
54 ///
55 /// This converts DMA channel singletons (`DMA1_CH3`, `DMA2_CH1`, ...), which
56 /// are all different types, into the same type. It is useful for
57 /// creating arrays of channels, or avoiding generics.
58 #[inline]
59 fn degrade(self) -> AnyChannel {
60 AnyChannel { id: self.id() }
61 }
62}
63
64macro_rules! dma_channel_impl {
65 ($channel_peri:ident, $index:expr) => {
66 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
67 fn id(&self) -> u8 {
68 $index
69 }
70 }
71 impl crate::dma::sealed::ChannelInterrupt for crate::peripherals::$channel_peri {
72 unsafe fn on_irq() {
73 crate::dma::AnyChannel { id: $index }.on_irq();
74 }
75 }
76
77 impl crate::dma::Channel for crate::peripherals::$channel_peri {}
78
79 impl From<crate::peripherals::$channel_peri> for crate::dma::AnyChannel {
80 fn from(x: crate::peripherals::$channel_peri) -> Self {
81 crate::dma::Channel::degrade(x)
82 }
83 }
84 };
85}
86
87/// Type-erased DMA channel.
88pub struct AnyChannel {
89 pub(crate) id: u8,
90}
91impl_peripheral!(AnyChannel);
92
93impl AnyChannel {
94 fn info(&self) -> &ChannelInfo {
95 &crate::_generated::DMA_CHANNELS[self.id as usize]
96 }
97}
98
99impl sealed::Channel for AnyChannel {
100 fn id(&self) -> u8 {
101 self.id
102 }
103}
104impl Channel for AnyChannel {}
105
106const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len();
107static STATE: [ChannelState; CHANNEL_COUNT] = [ChannelState::NEW; CHANNEL_COUNT];
108
44/// "No DMA" placeholder. 109/// "No DMA" placeholder.
45/// 110///
46/// You may pass this in place of a real DMA channel when creating a driver 111/// You may pass this in place of a real DMA channel when creating a driver
@@ -70,10 +135,14 @@ pub(crate) unsafe fn init(
70 #[cfg(dma)] dma_priority: Priority, 135 #[cfg(dma)] dma_priority: Priority,
71 #[cfg(gpdma)] gpdma_priority: Priority, 136 #[cfg(gpdma)] gpdma_priority: Priority,
72) { 137) {
73 #[cfg(bdma)] 138 #[cfg(any(dma, bdma))]
74 bdma::init(cs, bdma_priority); 139 dma_bdma::init(
75 #[cfg(dma)] 140 cs,
76 dma::init(cs, dma_priority); 141 #[cfg(dma)]
142 dma_priority,
143 #[cfg(bdma)]
144 bdma_priority,
145 );
77 #[cfg(gpdma)] 146 #[cfg(gpdma)]
78 gpdma::init(cs, gpdma_priority); 147 gpdma::init(cs, gpdma_priority);
79 #[cfg(dmamux)] 148 #[cfg(dmamux)]
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs
index c9f7a3026..23f1d67d5 100644
--- a/embassy-stm32/src/dma/ringbuffer.rs
+++ b/embassy-stm32/src/dma/ringbuffer.rs
@@ -37,6 +37,7 @@ pub struct ReadableDmaRingBuffer<'a, W: Word> {
37} 37}
38 38
39#[derive(Debug, PartialEq)] 39#[derive(Debug, PartialEq)]
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub struct OverrunError; 41pub struct OverrunError;
41 42
42pub trait DmaCtrl { 43pub trait DmaCtrl {
@@ -263,6 +264,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
263 self.cap() - dma.get_remaining_transfers() 264 self.cap() - dma.get_remaining_transfers()
264 } 265 }
265 266
267 /// Write elements directly to the buffer. This must be done before the DMA is started
268 /// or after the buffer has been cleared using `clear()`.
269 pub fn write_immediate(&mut self, buffer: &[W]) -> Result<(usize, usize), OverrunError> {
270 if self.end != 0 {
271 return Err(OverrunError);
272 }
273 let written = self.copy_from(buffer, 0..self.cap());
274 self.end = written % self.cap();
275 Ok((written, self.cap() - written))
276 }
277
266 /// Write an exact number of elements to the ringbuffer. 278 /// Write an exact number of elements to the ringbuffer.
267 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> { 279 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> {
268 let mut written_data = 0; 280 let mut written_data = 0;
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 448405507..71fe09c3f 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -13,6 +13,7 @@ use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14 14
15pub use self::_version::{InterruptHandler, *}; 15pub use self::_version::{InterruptHandler, *};
16use crate::rcc::RccPeripheral;
16 17
17#[allow(unused)] 18#[allow(unused)]
18const MTU: usize = 1514; 19const MTU: usize = 1514;
@@ -183,7 +184,7 @@ pub(crate) mod sealed {
183} 184}
184 185
185/// Ethernet instance. 186/// Ethernet instance.
186pub trait Instance: sealed::Instance + Send + 'static {} 187pub trait Instance: sealed::Instance + RccPeripheral + Send + 'static {}
187 188
188impl sealed::Instance for crate::peripherals::ETH { 189impl sealed::Instance for crate::peripherals::ETH {
189 fn regs() -> crate::pac::eth::Eth { 190 fn regs() -> crate::pac::eth::Eth {
@@ -192,12 +193,19 @@ impl sealed::Instance for crate::peripherals::ETH {
192} 193}
193impl Instance for crate::peripherals::ETH {} 194impl Instance for crate::peripherals::ETH {}
194 195
196pin_trait!(RXClkPin, Instance);
197pin_trait!(TXClkPin, Instance);
195pin_trait!(RefClkPin, Instance); 198pin_trait!(RefClkPin, Instance);
196pin_trait!(MDIOPin, Instance); 199pin_trait!(MDIOPin, Instance);
197pin_trait!(MDCPin, Instance); 200pin_trait!(MDCPin, Instance);
201pin_trait!(RXDVPin, Instance);
198pin_trait!(CRSPin, Instance); 202pin_trait!(CRSPin, Instance);
199pin_trait!(RXD0Pin, Instance); 203pin_trait!(RXD0Pin, Instance);
200pin_trait!(RXD1Pin, Instance); 204pin_trait!(RXD1Pin, Instance);
205pin_trait!(RXD2Pin, Instance);
206pin_trait!(RXD3Pin, Instance);
201pin_trait!(TXD0Pin, Instance); 207pin_trait!(TXD0Pin, Instance);
202pin_trait!(TXD1Pin, Instance); 208pin_trait!(TXD1Pin, Instance);
209pin_trait!(TXD2Pin, Instance);
210pin_trait!(TXD3Pin, Instance);
203pin_trait!(TXEnPin, Instance); 211pin_trait!(TXEnPin, Instance);
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 2ce5b3927..e5b7b0452 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -20,6 +20,7 @@ use crate::pac::AFIO;
20#[cfg(any(eth_v1b, eth_v1c))] 20#[cfg(any(eth_v1b, eth_v1c))]
21use crate::pac::SYSCFG; 21use crate::pac::SYSCFG;
22use crate::pac::{ETH, RCC}; 22use crate::pac::{ETH, RCC};
23use crate::rcc::sealed::RccPeripheral;
23use crate::{interrupt, Peripheral}; 24use crate::{interrupt, Peripheral};
24 25
25/// Interrupt handler. 26/// Interrupt handler.
@@ -191,8 +192,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
191 192
192 // TODO MTU size setting not found for v1 ethernet, check if correct 193 // TODO MTU size setting not found for v1 ethernet, check if correct
193 194
194 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 195 let hclk = <T as RccPeripheral>::frequency();
195 let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
196 let hclk_mhz = hclk.0 / 1_000_000; 196 let hclk_mhz = hclk.0 / 1_000_000;
197 197
198 // Set the MDC clock frequency in the range 1MHz - 2.5MHz 198 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 01ea8e574..645bfdb14 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -129,7 +129,7 @@ impl<'a> TDesRing<'a> {
129 129
130/// Receive Descriptor representation 130/// Receive Descriptor representation
131/// 131///
132/// * rdes0: recieve buffer address 132/// * rdes0: receive buffer address
133/// * rdes1: 133/// * rdes1:
134/// * rdes2: 134/// * rdes2:
135/// * rdes3: OWN and Status 135/// * rdes3: OWN and Status
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 59745cba0..8d69561d4 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -11,6 +11,7 @@ use crate::gpio::sealed::{AFType, Pin as _};
11use crate::gpio::{AnyPin, Speed}; 11use crate::gpio::{AnyPin, Speed};
12use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
13use crate::pac::ETH; 13use crate::pac::ETH;
14use crate::rcc::sealed::RccPeripheral;
14use crate::{interrupt, Peripheral}; 15use crate::{interrupt, Peripheral};
15 16
16/// Interrupt handler. 17/// Interrupt handler.
@@ -39,12 +40,18 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
39 _peri: PeripheralRef<'d, T>, 40 _peri: PeripheralRef<'d, T>,
40 pub(crate) tx: TDesRing<'d>, 41 pub(crate) tx: TDesRing<'d>,
41 pub(crate) rx: RDesRing<'d>, 42 pub(crate) rx: RDesRing<'d>,
42 pins: [PeripheralRef<'d, AnyPin>; 9], 43 pins: Pins<'d>,
43 pub(crate) phy: P, 44 pub(crate) phy: P,
44 pub(crate) station_management: EthernetStationManagement<T>, 45 pub(crate) station_management: EthernetStationManagement<T>,
45 pub(crate) mac_addr: [u8; 6], 46 pub(crate) mac_addr: [u8; 6],
46} 47}
47 48
49/// Pins of ethernet driver.
50enum Pins<'d> {
51 Rmii([PeripheralRef<'d, AnyPin>; 9]),
52 Mii([PeripheralRef<'d, AnyPin>; 14]),
53}
54
48macro_rules! config_pins { 55macro_rules! config_pins {
49 ($($pin:ident),*) => { 56 ($($pin:ident),*) => {
50 critical_section::with(|_| { 57 critical_section::with(|_| {
@@ -57,11 +64,11 @@ macro_rules! config_pins {
57} 64}
58 65
59impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { 66impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
60 /// Create a new Ethernet driver. 67 /// Create a new RMII ethernet driver using 9 pins.
61 pub fn new<const TX: usize, const RX: usize>( 68 pub fn new<const TX: usize, const RX: usize>(
62 queue: &'d mut PacketQueue<TX, RX>, 69 queue: &'d mut PacketQueue<TX, RX>,
63 peri: impl Peripheral<P = T> + 'd, 70 peri: impl Peripheral<P = T> + 'd,
64 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 71 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
65 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 72 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
66 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 73 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
67 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 74 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@@ -74,8 +81,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
74 phy: P, 81 phy: P,
75 mac_addr: [u8; 6], 82 mac_addr: [u8; 6],
76 ) -> Self { 83 ) -> Self {
77 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
78
79 // Enable the necessary Clocks 84 // Enable the necessary Clocks
80 #[cfg(not(rcc_h5))] 85 #[cfg(not(rcc_h5))]
81 critical_section::with(|_| { 86 critical_section::with(|_| {
@@ -85,7 +90,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
85 w.set_eth1rxen(true); 90 w.set_eth1rxen(true);
86 }); 91 });
87 92
88 // RMII
89 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); 93 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
90 }); 94 });
91 95
@@ -99,14 +103,110 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
99 w.set_ethrxen(true); 103 w.set_ethrxen(true);
100 }); 104 });
101 105
102 // RMII
103 crate::pac::SYSCFG 106 crate::pac::SYSCFG
104 .pmcr() 107 .pmcr()
105 .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); 108 .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
106 }); 109 });
107 110
111 into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
108 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 112 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
109 113
114 let pins = Pins::Rmii([
115 ref_clk.map_into(),
116 mdio.map_into(),
117 mdc.map_into(),
118 crs.map_into(),
119 rx_d0.map_into(),
120 rx_d1.map_into(),
121 tx_d0.map_into(),
122 tx_d1.map_into(),
123 tx_en.map_into(),
124 ]);
125
126 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
127 }
128
129 /// Create a new MII ethernet driver using 14 pins.
130 pub fn new_mii<const TX: usize, const RX: usize>(
131 queue: &'d mut PacketQueue<TX, RX>,
132 peri: impl Peripheral<P = T> + 'd,
133 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
134 rx_clk: impl Peripheral<P = impl RXClkPin<T>> + 'd,
135 tx_clk: impl Peripheral<P = impl TXClkPin<T>> + 'd,
136 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
137 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
138 rxdv: impl Peripheral<P = impl RXDVPin<T>> + 'd,
139 rx_d0: impl Peripheral<P = impl RXD0Pin<T>> + 'd,
140 rx_d1: impl Peripheral<P = impl RXD1Pin<T>> + 'd,
141 rx_d2: impl Peripheral<P = impl RXD2Pin<T>> + 'd,
142 rx_d3: impl Peripheral<P = impl RXD3Pin<T>> + 'd,
143 tx_d0: impl Peripheral<P = impl TXD0Pin<T>> + 'd,
144 tx_d1: impl Peripheral<P = impl TXD1Pin<T>> + 'd,
145 tx_d2: impl Peripheral<P = impl TXD2Pin<T>> + 'd,
146 tx_d3: impl Peripheral<P = impl TXD3Pin<T>> + 'd,
147 tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
148 phy: P,
149 mac_addr: [u8; 6],
150 ) -> Self {
151 // Enable necessary clocks.
152 #[cfg(not(rcc_h5))]
153 critical_section::with(|_| {
154 crate::pac::RCC.ahb1enr().modify(|w| {
155 w.set_eth1macen(true);
156 w.set_eth1txen(true);
157 w.set_eth1rxen(true);
158 });
159
160 crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b000));
161 });
162
163 #[cfg(rcc_h5)]
164 critical_section::with(|_| {
165 crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
166
167 crate::pac::RCC.ahb1enr().modify(|w| {
168 w.set_ethen(true);
169 w.set_ethtxen(true);
170 w.set_ethrxen(true);
171 });
172
173 // TODO: This is for RMII - what would MII need here?
174 crate::pac::SYSCFG
175 .pmcr()
176 .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
177 });
178
179 into_ref!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
180 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
181
182 let pins = Pins::Mii([
183 rx_clk.map_into(),
184 tx_clk.map_into(),
185 mdio.map_into(),
186 mdc.map_into(),
187 rxdv.map_into(),
188 rx_d0.map_into(),
189 rx_d1.map_into(),
190 rx_d2.map_into(),
191 rx_d3.map_into(),
192 tx_d0.map_into(),
193 tx_d1.map_into(),
194 tx_d2.map_into(),
195 tx_d3.map_into(),
196 tx_en.map_into(),
197 ]);
198
199 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
200 }
201
202 fn new_inner<const TX: usize, const RX: usize>(
203 queue: &'d mut PacketQueue<TX, RX>,
204 peri: impl Peripheral<P = T> + 'd,
205 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
206 pins: Pins<'d>,
207 phy: P,
208 mac_addr: [u8; 6],
209 ) -> Self {
110 let dma = ETH.ethernet_dma(); 210 let dma = ETH.ethernet_dma();
111 let mac = ETH.ethernet_mac(); 211 let mac = ETH.ethernet_mac();
112 let mtl = ETH.ethernet_mtl(); 212 let mtl = ETH.ethernet_mtl();
@@ -165,8 +265,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
165 w.set_rbsz(RX_BUFFER_SIZE as u16); 265 w.set_rbsz(RX_BUFFER_SIZE as u16);
166 }); 266 });
167 267
168 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 268 let hclk = <T as RccPeripheral>::frequency();
169 let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
170 let hclk_mhz = hclk.0 / 1_000_000; 269 let hclk_mhz = hclk.0 / 1_000_000;
171 270
172 // Set the MDC clock frequency in the range 1MHz - 2.5MHz 271 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
@@ -182,24 +281,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
182 } 281 }
183 }; 282 };
184 283
185 let pins = [
186 ref_clk.map_into(),
187 mdio.map_into(),
188 mdc.map_into(),
189 crs.map_into(),
190 rx_d0.map_into(),
191 rx_d1.map_into(),
192 tx_d0.map_into(),
193 tx_d1.map_into(),
194 tx_en.map_into(),
195 ];
196
197 let mut this = Self { 284 let mut this = Self {
198 _peri: peri, 285 _peri: peri.into_ref(),
199 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 286 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
200 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 287 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
201 pins, 288 pins,
202 phy: phy, 289 phy,
203 station_management: EthernetStationManagement { 290 station_management: EthernetStationManagement {
204 peri: PhantomData, 291 peri: PhantomData,
205 clock_range: clock_range, 292 clock_range: clock_range,
@@ -302,7 +389,10 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
302 dma.dmacrx_cr().modify(|w| w.set_sr(false)); 389 dma.dmacrx_cr().modify(|w| w.set_sr(false));
303 390
304 critical_section::with(|_| { 391 critical_section::with(|_| {
305 for pin in self.pins.iter_mut() { 392 for pin in match self.pins {
393 Pins::Rmii(ref mut pins) => pins.iter_mut(),
394 Pins::Mii(ref mut pins) => pins.iter_mut(),
395 } {
306 pin.set_as_disconnected(); 396 pin.set_as_disconnected();
307 } 397 }
308 }) 398 })
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 2821435ef..bd10ba158 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -5,10 +5,10 @@ use core::marker::PhantomData;
5use core::pin::Pin; 5use core::pin::Pin;
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::impl_peripheral; 8use embassy_hal_internal::{impl_peripheral, into_ref};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin}; 11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull};
12use crate::pac::exti::regs::Lines; 12use crate::pac::exti::regs::Lines;
13use crate::pac::EXTI; 13use crate::pac::EXTI;
14use crate::{interrupt, pac, peripherals, Peripheral}; 14use crate::{interrupt, pac, peripherals, Peripheral};
@@ -93,16 +93,27 @@ impl Iterator for BitIter {
93/// EXTI channel, which is a limited resource. 93/// EXTI channel, which is a limited resource.
94/// 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. 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.
96pub struct ExtiInput<'d, T: GpioPin> { 96pub struct ExtiInput<'d> {
97 pin: Input<'d, T>, 97 pin: Input<'d>,
98} 98}
99 99
100impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} 100impl<'d> Unpin for ExtiInput<'d> {}
101 101
102impl<'d, T: GpioPin> ExtiInput<'d, T> { 102impl<'d> ExtiInput<'d> {
103 /// Create an EXTI input. 103 /// Create an EXTI input.
104 pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self { 104 pub fn new<T: GpioPin>(
105 Self { pin } 105 pin: impl Peripheral<P = T> + 'd,
106 ch: impl Peripheral<P = T::ExtiChannel> + 'd,
107 pull: Pull,
108 ) -> Self {
109 into_ref!(pin, ch);
110
111 // Needed if using AnyPin+AnyChannel.
112 assert_eq!(pin.pin(), ch.number());
113
114 Self {
115 pin: Input::new(pin, pull),
116 }
106 } 117 }
107 118
108 /// Get whether the pin is high. 119 /// Get whether the pin is high.
@@ -162,7 +173,7 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
162 } 173 }
163} 174}
164 175
165impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T> { 176impl<'d> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d> {
166 type Error = Infallible; 177 type Error = Infallible;
167 178
168 fn is_high(&self) -> Result<bool, Self::Error> { 179 fn is_high(&self) -> Result<bool, Self::Error> {
@@ -174,11 +185,11 @@ impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T>
174 } 185 }
175} 186}
176 187
177impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> { 188impl<'d> embedded_hal_1::digital::ErrorType for ExtiInput<'d> {
178 type Error = Infallible; 189 type Error = Infallible;
179} 190}
180 191
181impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { 192impl<'d> embedded_hal_1::digital::InputPin for ExtiInput<'d> {
182 fn is_high(&mut self) -> Result<bool, Self::Error> { 193 fn is_high(&mut self) -> Result<bool, Self::Error> {
183 Ok((*self).is_high()) 194 Ok((*self).is_high())
184 } 195 }
@@ -188,7 +199,7 @@ impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> {
188 } 199 }
189} 200}
190 201
191impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for ExtiInput<'d, T> { 202impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> {
192 async fn wait_for_high(&mut self) -> Result<(), Self::Error> { 203 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
193 self.wait_for_high().await; 204 self.wait_for_high().await;
194 Ok(()) 205 Ok(())
@@ -326,7 +337,7 @@ pub(crate) mod sealed {
326/// EXTI channel trait. 337/// EXTI channel trait.
327pub trait Channel: sealed::Channel + Sized { 338pub trait Channel: sealed::Channel + Sized {
328 /// Get the EXTI channel number. 339 /// Get the EXTI channel number.
329 fn number(&self) -> usize; 340 fn number(&self) -> u8;
330 341
331 /// Type-erase (degrade) this channel into an `AnyChannel`. 342 /// Type-erase (degrade) this channel into an `AnyChannel`.
332 /// 343 ///
@@ -350,8 +361,8 @@ pub struct AnyChannel {
350impl_peripheral!(AnyChannel); 361impl_peripheral!(AnyChannel);
351impl sealed::Channel for AnyChannel {} 362impl sealed::Channel for AnyChannel {}
352impl Channel for AnyChannel { 363impl Channel for AnyChannel {
353 fn number(&self) -> usize { 364 fn number(&self) -> u8 {
354 self.number as usize 365 self.number
355 } 366 }
356} 367}
357 368
@@ -359,8 +370,8 @@ macro_rules! impl_exti {
359 ($type:ident, $number:expr) => { 370 ($type:ident, $number:expr) => {
360 impl sealed::Channel for peripherals::$type {} 371 impl sealed::Channel for peripherals::$type {}
361 impl Channel for peripherals::$type { 372 impl Channel for peripherals::$type {
362 fn number(&self) -> usize { 373 fn number(&self) -> u8 {
363 $number as usize 374 $number
364 } 375 }
365 } 376 }
366 }; 377 };
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
new file mode 100644
index 000000000..db05bef5d
--- /dev/null
+++ b/embassy-stm32/src/flash/h50.rs
@@ -0,0 +1,124 @@
1/// STM32H50 series flash impl. See RM0492
2use core::{
3 ptr::write_volatile,
4 sync::atomic::{fence, Ordering},
5};
6
7use cortex_m::interrupt;
8use pac::flash::regs::Nssr;
9use pac::flash::vals::Bksel;
10
11use super::{Error, FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
12use crate::pac;
13
14pub(crate) const fn is_default_layout() -> bool {
15 true
16}
17
18pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
19 &FLASH_REGIONS
20}
21
22pub(crate) unsafe fn lock() {
23 pac::FLASH.nscr().modify(|w| w.set_lock(true));
24}
25
26pub(crate) unsafe fn unlock() {
27 while busy() {}
28
29 if pac::FLASH.nscr().read().lock() {
30 pac::FLASH.nskeyr().write_value(0x4567_0123);
31 pac::FLASH.nskeyr().write_value(0xCDEF_89AB);
32 }
33}
34
35pub(crate) unsafe fn enable_blocking_write() {
36 assert_eq!(0, WRITE_SIZE % 4);
37 pac::FLASH.nscr().write(|w| w.set_pg(true));
38}
39
40pub(crate) unsafe fn disable_blocking_write() {
41 pac::FLASH.nscr().write(|w| w.set_pg(false));
42}
43
44pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
45 let mut address = start_address;
46 for val in buf.chunks(4) {
47 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
48 address += val.len() as u32;
49
50 // prevents parallelism errors
51 fence(Ordering::SeqCst);
52 }
53
54 wait_ready_blocking()
55}
56
57pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
58 assert!(sector.bank != FlashBank::Otp);
59 assert!(sector.index_in_bank < 8);
60
61 while busy() {}
62
63 interrupt::free(|_| {
64 pac::FLASH.nscr().modify(|w| {
65 w.set_bksel(match sector.bank {
66 FlashBank::Bank1 => Bksel::B_0X0,
67 FlashBank::Bank2 => Bksel::B_0X1,
68 _ => unreachable!(),
69 });
70 w.set_snb(sector.index_in_bank);
71 w.set_ser(true);
72 w.set_strt(true);
73 })
74 });
75
76 let ret = wait_ready_blocking();
77 pac::FLASH.nscr().modify(|w| w.set_ser(false));
78 ret
79}
80
81pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
82 loop {
83 let sr = pac::FLASH.nssr().read();
84
85 if !sr_busy(sr) {
86 if sr.wrperr() {
87 return Err(Error::Protected);
88 }
89 if sr.pgserr() {
90 return Err(Error::Seq);
91 }
92 if sr.strberr() {
93 // writing several times to the same byte in the write buffer
94 return Err(Error::Prog);
95 }
96 if sr.incerr() {
97 // attempting write operation before completion of previous
98 // write operation
99 return Err(Error::Seq);
100 }
101
102 return Ok(());
103 }
104 }
105}
106
107pub(crate) unsafe fn clear_all_err() {
108 pac::FLASH.nsccr().modify(|w| {
109 w.set_clr_wrperr(true);
110 w.set_clr_pgserr(true);
111 w.set_clr_strberr(true);
112 w.set_clr_incerr(true);
113 })
114}
115
116fn sr_busy(sr: Nssr) -> bool {
117 // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE
118 sr.bsy() || sr.dbne() || sr.wbne()
119}
120
121fn busy() -> bool {
122 let sr = pac::FLASH.nssr().read();
123 sr_busy(sr)
124}
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index ae395d568..743925e17 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -77,12 +77,12 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
77 } 77 }
78 } 78 }
79 79
80 bank.cr().write(|w| w.set_pg(false));
81
82 cortex_m::asm::isb(); 80 cortex_m::asm::isb();
83 cortex_m::asm::dsb(); 81 cortex_m::asm::dsb();
84 fence(Ordering::SeqCst); 82 fence(Ordering::SeqCst);
85 83
84 bank.cr().write(|w| w.set_pg(false));
85
86 res.unwrap() 86 res.unwrap()
87} 87}
88 88
@@ -100,6 +100,10 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
100 w.set_start(true); 100 w.set_start(true);
101 }); 101 });
102 102
103 cortex_m::asm::isb();
104 cortex_m::asm::dsb();
105 fence(Ordering::SeqCst);
106
103 let ret: Result<(), Error> = blocking_wait_ready(bank); 107 let ret: Result<(), Error> = blocking_wait_ready(bank);
104 bank.cr().modify(|w| w.set_ser(false)); 108 bank.cr().modify(|w| w.set_ser(false));
105 bank_clear_all_err(bank); 109 bank_clear_all_err(bank);
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 47232f4a4..1d8031e82 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -101,10 +101,12 @@ pub enum FlashBank {
101#[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")] 101#[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")]
102#[cfg_attr(flash_h7, path = "h7.rs")] 102#[cfg_attr(flash_h7, path = "h7.rs")]
103#[cfg_attr(flash_h7ab, path = "h7.rs")] 103#[cfg_attr(flash_h7ab, path = "h7.rs")]
104#[cfg_attr(flash_u5, path = "u5.rs")]
105#[cfg_attr(flash_h50, path = "h50.rs")]
104#[cfg_attr( 106#[cfg_attr(
105 not(any( 107 not(any(
106 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, 108 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0,
107 flash_g4, flash_h7, flash_h7ab 109 flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50
108 )), 110 )),
109 path = "other.rs" 111 path = "other.rs"
110)] 112)]
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
new file mode 100644
index 000000000..3787082f9
--- /dev/null
+++ b/embassy-stm32/src/flash/u5.rs
@@ -0,0 +1,105 @@
1use core::convert::TryInto;
2use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering};
4
5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error;
7use crate::pac;
8
9pub(crate) const fn is_default_layout() -> bool {
10 true
11}
12
13pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14 &FLASH_REGIONS
15}
16
17pub(crate) unsafe fn lock() {
18 pac::FLASH.seccr().modify(|w| w.set_lock(true));
19}
20
21pub(crate) unsafe fn unlock() {
22 if pac::FLASH.seccr().read().lock() {
23 pac::FLASH.seckeyr().write_value(0x4567_0123);
24 pac::FLASH.seckeyr().write_value(0xCDEF_89AB);
25 }
26}
27
28pub(crate) unsafe fn enable_blocking_write() {
29 assert_eq!(0, WRITE_SIZE % 4);
30
31 pac::FLASH.seccr().write(|w| {
32 w.set_pg(pac::flash::vals::SeccrPg::B_0X1);
33 });
34}
35
36pub(crate) unsafe fn disable_blocking_write() {
37 pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0));
38}
39
40pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
41 let mut address = start_address;
42 for val in buf.chunks(4) {
43 write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
44 address += val.len() as u32;
45
46 // prevents parallelism errors
47 fence(Ordering::SeqCst);
48 }
49
50 blocking_wait_ready()
51}
52
53pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
54 pac::FLASH.seccr().modify(|w| {
55 w.set_per(pac::flash::vals::SeccrPer::B_0X1);
56 w.set_pnb(sector.index_in_bank)
57 });
58
59 pac::FLASH.seccr().modify(|w| {
60 w.set_strt(true);
61 });
62
63 let ret: Result<(), Error> = blocking_wait_ready();
64 pac::FLASH
65 .seccr()
66 .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0));
67 clear_all_err();
68 ret
69}
70
71pub(crate) unsafe fn clear_all_err() {
72 // read and write back the same value.
73 // This clears all "write 1 to clear" bits.
74 pac::FLASH.secsr().modify(|_| {});
75}
76
77unsafe fn blocking_wait_ready() -> Result<(), Error> {
78 loop {
79 let sr = pac::FLASH.secsr().read();
80
81 if !sr.bsy() {
82 if sr.pgserr() {
83 return Err(Error::Seq);
84 }
85
86 if sr.sizerr() {
87 return Err(Error::Size);
88 }
89
90 if sr.pgaerr() {
91 return Err(Error::Unaligned);
92 }
93
94 if sr.wrperr() {
95 return Err(Error::Protected);
96 }
97
98 if sr.progerr() {
99 return Err(Error::Prog);
100 }
101
102 return Ok(());
103 }
104 }
105}
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index 873c8a70c..9d731a512 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -36,8 +36,10 @@ where
36 // fmc v1 and v2 does not have the fmcen bit 36 // fmc v1 and v2 does not have the fmcen bit
37 // fsmc v1, v2 and v3 does not have the fmcen bit 37 // fsmc v1, v2 and v3 does not have the fmcen bit
38 // This is a "not" because it is expected that all future versions have this bit 38 // This is a "not" because it is expected that all future versions have this bit
39 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] 39 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))]
40 T::REGS.bcr1().modify(|r| r.set_fmcen(true)); 40 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
41 #[cfg(any(fmc_v4))]
42 T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
41 } 43 }
42 44
43 /// Get the kernel clock currently in use for this FMC instance. 45 /// Get the kernel clock currently in use for this FMC instance.
@@ -60,8 +62,10 @@ where
60 // fmc v1 and v2 does not have the fmcen bit 62 // fmc v1 and v2 does not have the fmcen bit
61 // fsmc v1, v2 and v3 does not have the fmcen bit 63 // fsmc v1, v2 and v3 does not have the fmcen bit
62 // This is a "not" because it is expected that all future versions have this bit 64 // This is a "not" because it is expected that all future versions have this bit
63 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] 65 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))]
64 T::REGS.bcr1().modify(|r| r.set_fmcen(true)); 66 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
67 #[cfg(any(fmc_v4))]
68 T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
65 } 69 }
66 70
67 fn source_clock_hz(&self) -> u32 { 71 fn source_clock_hz(&self) -> u32 {
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 7eb70496f..00e3e1727 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -6,6 +6,7 @@ use core::convert::Infallible;
6use critical_section::CriticalSection; 6use critical_section::CriticalSection;
7use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 7use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
8 8
9use self::sealed::Pin as _;
9use crate::pac::gpio::{self, vals}; 10use crate::pac::gpio::{self, vals};
10use crate::{pac, peripherals, Peripheral}; 11use crate::{pac, peripherals, Peripheral};
11 12
@@ -14,41 +15,21 @@ use crate::{pac, peripherals, Peripheral};
14/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain 15/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
15/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output 16/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
16/// mode. 17/// mode.
17pub struct Flex<'d, T: Pin> { 18pub struct Flex<'d> {
18 pub(crate) pin: PeripheralRef<'d, T>, 19 pub(crate) pin: PeripheralRef<'d, AnyPin>,
19} 20}
20 21
21impl<'d, T: Pin> Flex<'d, T> { 22impl<'d> Flex<'d> {
22 /// Wrap the pin in a `Flex`. 23 /// Wrap the pin in a `Flex`.
23 /// 24 ///
24 /// The pin remains disconnected. The initial output level is unspecified, but can be changed 25 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
25 /// before the pin is put into output mode. 26 /// before the pin is put into output mode.
26 /// 27 ///
27 #[inline] 28 #[inline]
28 pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { 29 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self {
29 into_ref!(pin); 30 into_ref!(pin);
30 // Pin will be in disconnected state. 31 // Pin will be in disconnected state.
31 Self { pin } 32 Self { pin: pin.map_into() }
32 }
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.
39 #[inline]
40 pub fn degrade(self) -> Flex<'d, AnyPin> {
41 // Safety: We are about to drop the other copy of this pin, so
42 // this clone is safe.
43 let pin = unsafe { self.pin.clone_unchecked() };
44
45 // We don't want to run the destructor here, because that would
46 // deconfigure the pin.
47 core::mem::forget(self);
48
49 Flex {
50 pin: pin.map_into::<AnyPin>(),
51 }
52 } 33 }
53 34
54 /// Put the pin into input mode. 35 /// Put the pin into input mode.
@@ -218,7 +199,7 @@ impl<'d, T: Pin> Flex<'d, T> {
218 } 199 }
219} 200}
220 201
221impl<'d, T: Pin> Drop for Flex<'d, T> { 202impl<'d> Drop for Flex<'d> {
222 #[inline] 203 #[inline]
223 fn drop(&mut self) { 204 fn drop(&mut self) {
224 critical_section::with(|_| { 205 critical_section::with(|_| {
@@ -268,7 +249,7 @@ impl From<Pull> for vals::Pupdr {
268 249
269/// Speed settings 250/// Speed settings
270/// 251///
271/// These vary dpeending on the chip, ceck the reference manual or datasheet for details. 252/// These vary depending on the chip, check the reference manual or datasheet for details.
272#[allow(missing_docs)] 253#[allow(missing_docs)]
273#[derive(Debug, Copy, Clone)] 254#[derive(Debug, Copy, Clone)]
274#[cfg_attr(feature = "defmt", derive(defmt::Format))] 255#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -309,31 +290,19 @@ impl From<Speed> for vals::Ospeedr {
309} 290}
310 291
311/// GPIO input driver. 292/// GPIO input driver.
312pub struct Input<'d, T: Pin> { 293pub struct Input<'d> {
313 pub(crate) pin: Flex<'d, T>, 294 pub(crate) pin: Flex<'d>,
314} 295}
315 296
316impl<'d, T: Pin> Input<'d, T> { 297impl<'d> Input<'d> {
317 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. 298 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
318 #[inline] 299 #[inline]
319 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { 300 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self {
320 let mut pin = Flex::new(pin); 301 let mut pin = Flex::new(pin);
321 pin.set_as_input(pull); 302 pin.set_as_input(pull);
322 Self { pin } 303 Self { pin }
323 } 304 }
324 305
325 /// Type-erase (degrade) this pin into an `AnyPin`.
326 ///
327 /// This converts pin singletons (`PA5`, `PB6`, ...), which
328 /// are all different types, into the same type. It is useful for
329 /// creating arrays of pins, or avoiding generics.
330 #[inline]
331 pub fn degrade(self) -> Input<'d, AnyPin> {
332 Input {
333 pin: self.pin.degrade(),
334 }
335 }
336
337 /// Get whether the pin input level is high. 306 /// Get whether the pin input level is high.
338 #[inline] 307 #[inline]
339 pub fn is_high(&self) -> bool { 308 pub fn is_high(&self) -> bool {
@@ -386,14 +355,14 @@ impl From<Level> for bool {
386/// Note that pins will **return to their floating state** when `Output` is dropped. 355/// Note that pins will **return to their floating state** when `Output` is dropped.
387/// If pins should retain their state indefinitely, either keep ownership of the 356/// If pins should retain their state indefinitely, either keep ownership of the
388/// `Output`, or pass it to [`core::mem::forget`]. 357/// `Output`, or pass it to [`core::mem::forget`].
389pub struct Output<'d, T: Pin> { 358pub struct Output<'d> {
390 pub(crate) pin: Flex<'d, T>, 359 pub(crate) pin: Flex<'d>,
391} 360}
392 361
393impl<'d, T: Pin> Output<'d, T> { 362impl<'d> Output<'d> {
394 /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. 363 /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration.
395 #[inline] 364 #[inline]
396 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self { 365 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed) -> Self {
397 let mut pin = Flex::new(pin); 366 let mut pin = Flex::new(pin);
398 match initial_output { 367 match initial_output {
399 Level::High => pin.set_high(), 368 Level::High => pin.set_high(),
@@ -403,18 +372,6 @@ impl<'d, T: Pin> Output<'d, T> {
403 Self { pin } 372 Self { pin }
404 } 373 }
405 374
406 /// Type-erase (degrade) this pin into an `AnyPin`.
407 ///
408 /// This converts pin singletons (`PA5`, `PB6`, ...), which
409 /// are all different types, into the same type. It is useful for
410 /// creating arrays of pins, or avoiding generics.
411 #[inline]
412 pub fn degrade(self) -> Output<'d, AnyPin> {
413 Output {
414 pin: self.pin.degrade(),
415 }
416 }
417
418 /// Set the output as high. 375 /// Set the output as high.
419 #[inline] 376 #[inline]
420 pub fn set_high(&mut self) { 377 pub fn set_high(&mut self) {
@@ -463,14 +420,14 @@ impl<'d, T: Pin> Output<'d, T> {
463/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped. 420/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
464/// If pins should retain their state indefinitely, either keep ownership of the 421/// If pins should retain their state indefinitely, either keep ownership of the
465/// `OutputOpenDrain`, or pass it to [`core::mem::forget`]. 422/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
466pub struct OutputOpenDrain<'d, T: Pin> { 423pub struct OutputOpenDrain<'d> {
467 pub(crate) pin: Flex<'d, T>, 424 pub(crate) pin: Flex<'d>,
468} 425}
469 426
470impl<'d, T: Pin> OutputOpenDrain<'d, T> { 427impl<'d> OutputOpenDrain<'d> {
471 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration. 428 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration.
472 #[inline] 429 #[inline]
473 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { 430 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self {
474 let mut pin = Flex::new(pin); 431 let mut pin = Flex::new(pin);
475 432
476 match initial_output { 433 match initial_output {
@@ -482,18 +439,6 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
482 Self { pin } 439 Self { pin }
483 } 440 }
484 441
485 /// Type-erase (degrade) this pin into an `AnyPin`.
486 ///
487 /// This converts pin singletons (`PA5`, `PB6`, ...), which
488 /// are all different types, into the same type. It is useful for
489 /// creating arrays of pins, or avoiding generics.
490 #[inline]
491 pub fn degrade(self) -> Output<'d, AnyPin> {
492 Output {
493 pin: self.pin.degrade(),
494 }
495 }
496
497 /// Get whether the pin input level is high. 442 /// Get whether the pin input level is high.
498 #[inline] 443 #[inline]
499 pub fn is_high(&self) -> bool { 444 pub fn is_high(&self) -> bool {
@@ -836,7 +781,7 @@ pub(crate) unsafe fn init(_cs: CriticalSection) {
836 }); 781 });
837} 782}
838 783
839impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { 784impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> {
840 type Error = Infallible; 785 type Error = Infallible;
841 786
842 #[inline] 787 #[inline]
@@ -850,7 +795,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> {
850 } 795 }
851} 796}
852 797
853impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { 798impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> {
854 type Error = Infallible; 799 type Error = Infallible;
855 800
856 #[inline] 801 #[inline]
@@ -866,7 +811,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> {
866 } 811 }
867} 812}
868 813
869impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { 814impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> {
870 #[inline] 815 #[inline]
871 fn is_set_high(&self) -> Result<bool, Self::Error> { 816 fn is_set_high(&self) -> Result<bool, Self::Error> {
872 Ok(self.is_set_high()) 817 Ok(self.is_set_high())
@@ -879,7 +824,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d,
879 } 824 }
880} 825}
881 826
882impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> { 827impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> {
883 type Error = Infallible; 828 type Error = Infallible;
884 #[inline] 829 #[inline]
885 fn toggle(&mut self) -> Result<(), Self::Error> { 830 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -888,7 +833,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d
888 } 833 }
889} 834}
890 835
891impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, T> { 836impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> {
892 type Error = Infallible; 837 type Error = Infallible;
893 838
894 #[inline] 839 #[inline]
@@ -904,7 +849,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d,
904 } 849 }
905} 850}
906 851
907impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { 852impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d> {
908 #[inline] 853 #[inline]
909 fn is_set_high(&self) -> Result<bool, Self::Error> { 854 fn is_set_high(&self) -> Result<bool, Self::Error> {
910 Ok(self.is_set_high()) 855 Ok(self.is_set_high())
@@ -917,7 +862,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenD
917 } 862 }
918} 863}
919 864
920impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d, T> { 865impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d> {
921 type Error = Infallible; 866 type Error = Infallible;
922 #[inline] 867 #[inline]
923 fn toggle(&mut self) -> Result<(), Self::Error> { 868 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -926,7 +871,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpe
926 } 871 }
927} 872}
928 873
929impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { 874impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> {
930 type Error = Infallible; 875 type Error = Infallible;
931 876
932 #[inline] 877 #[inline]
@@ -940,7 +885,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> {
940 } 885 }
941} 886}
942 887
943impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { 888impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> {
944 type Error = Infallible; 889 type Error = Infallible;
945 890
946 #[inline] 891 #[inline]
@@ -956,7 +901,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> {
956 } 901 }
957} 902}
958 903
959impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { 904impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> {
960 #[inline] 905 #[inline]
961 fn is_set_high(&self) -> Result<bool, Self::Error> { 906 fn is_set_high(&self) -> Result<bool, Self::Error> {
962 Ok(self.is_set_high()) 907 Ok(self.is_set_high())
@@ -969,7 +914,7 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T>
969 } 914 }
970} 915}
971 916
972impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> { 917impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> {
973 type Error = Infallible; 918 type Error = Infallible;
974 #[inline] 919 #[inline]
975 fn toggle(&mut self) -> Result<(), Self::Error> { 920 fn toggle(&mut self) -> Result<(), Self::Error> {
@@ -978,11 +923,11 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d,
978 } 923 }
979} 924}
980 925
981impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { 926impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> {
982 type Error = Infallible; 927 type Error = Infallible;
983} 928}
984 929
985impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { 930impl<'d> embedded_hal_1::digital::InputPin for Input<'d> {
986 #[inline] 931 #[inline]
987 fn is_high(&mut self) -> Result<bool, Self::Error> { 932 fn is_high(&mut self) -> Result<bool, Self::Error> {
988 Ok((*self).is_high()) 933 Ok((*self).is_high())
@@ -994,11 +939,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
994 } 939 }
995} 940}
996 941
997impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> { 942impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
998 type Error = Infallible; 943 type Error = Infallible;
999} 944}
1000 945
1001impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { 946impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
1002 #[inline] 947 #[inline]
1003 fn set_high(&mut self) -> Result<(), Self::Error> { 948 fn set_high(&mut self) -> Result<(), Self::Error> {
1004 Ok(self.set_high()) 949 Ok(self.set_high())
@@ -1010,7 +955,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
1010 } 955 }
1011} 956}
1012 957
1013impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { 958impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> {
1014 #[inline] 959 #[inline]
1015 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 960 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1016 Ok((*self).is_set_high()) 961 Ok((*self).is_set_high())
@@ -1023,11 +968,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
1023 } 968 }
1024} 969}
1025 970
1026impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { 971impl<'d> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d> {
1027 type Error = Infallible; 972 type Error = Infallible;
1028} 973}
1029 974
1030impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { 975impl<'d> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d> {
1031 #[inline] 976 #[inline]
1032 fn is_high(&mut self) -> Result<bool, Self::Error> { 977 fn is_high(&mut self) -> Result<bool, Self::Error> {
1033 Ok((*self).is_high()) 978 Ok((*self).is_high())
@@ -1039,7 +984,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> {
1039 } 984 }
1040} 985}
1041 986
1042impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { 987impl<'d> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d> {
1043 #[inline] 988 #[inline]
1044 fn set_high(&mut self) -> Result<(), Self::Error> { 989 fn set_high(&mut self) -> Result<(), Self::Error> {
1045 Ok(self.set_high()) 990 Ok(self.set_high())
@@ -1051,7 +996,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> {
1051 } 996 }
1052} 997}
1053 998
1054impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { 999impl<'d> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d> {
1055 #[inline] 1000 #[inline]
1056 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 1001 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1057 Ok((*self).is_set_high()) 1002 Ok((*self).is_set_high())
@@ -1064,7 +1009,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<
1064 } 1009 }
1065} 1010}
1066 1011
1067impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { 1012impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
1068 #[inline] 1013 #[inline]
1069 fn is_high(&mut self) -> Result<bool, Self::Error> { 1014 fn is_high(&mut self) -> Result<bool, Self::Error> {
1070 Ok((*self).is_high()) 1015 Ok((*self).is_high())
@@ -1076,7 +1021,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
1076 } 1021 }
1077} 1022}
1078 1023
1079impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { 1024impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
1080 #[inline] 1025 #[inline]
1081 fn set_high(&mut self) -> Result<(), Self::Error> { 1026 fn set_high(&mut self) -> Result<(), Self::Error> {
1082 Ok(self.set_high()) 1027 Ok(self.set_high())
@@ -1088,11 +1033,11 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
1088 } 1033 }
1089} 1034}
1090 1035
1091impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { 1036impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> {
1092 type Error = Infallible; 1037 type Error = Infallible;
1093} 1038}
1094 1039
1095impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { 1040impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> {
1096 #[inline] 1041 #[inline]
1097 fn is_set_high(&mut self) -> Result<bool, Self::Error> { 1042 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1098 Ok((*self).is_set_high()) 1043 Ok((*self).is_set_high())
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
new file mode 100644
index 000000000..b47814f8b
--- /dev/null
+++ b/embassy-stm32/src/hash/mod.rs
@@ -0,0 +1,592 @@
1//! Hash generator (HASH)
2use core::cmp::min;
3#[cfg(hash_v2)]
4use core::future::poll_fn;
5use core::marker::PhantomData;
6#[cfg(hash_v2)]
7use core::ptr;
8#[cfg(hash_v2)]
9use core::task::Poll;
10
11use embassy_hal_internal::{into_ref, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker;
13use stm32_metapac::hash::regs::*;
14
15use crate::dma::NoDma;
16#[cfg(hash_v2)]
17use crate::dma::Transfer;
18use crate::interrupt::typelevel::Interrupt;
19use crate::peripherals::HASH;
20use crate::rcc::sealed::RccPeripheral;
21use crate::{interrupt, pac, peripherals, Peripheral};
22
23#[cfg(hash_v1)]
24const NUM_CONTEXT_REGS: usize = 51;
25#[cfg(hash_v3)]
26const NUM_CONTEXT_REGS: usize = 103;
27#[cfg(any(hash_v2, hash_v4))]
28const NUM_CONTEXT_REGS: usize = 54;
29
30const HASH_BUFFER_LEN: usize = 132;
31const DIGEST_BLOCK_SIZE: usize = 128;
32
33static HASH_WAKER: AtomicWaker = AtomicWaker::new();
34
35/// HASH interrupt handler.
36pub struct InterruptHandler<T: Instance> {
37 _phantom: PhantomData<T>,
38}
39
40impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
41 unsafe fn on_interrupt() {
42 let bits = T::regs().sr().read();
43 if bits.dinis() {
44 T::regs().imr().modify(|reg| reg.set_dinie(false));
45 HASH_WAKER.wake();
46 }
47 if bits.dcis() {
48 T::regs().imr().modify(|reg| reg.set_dcie(false));
49 HASH_WAKER.wake();
50 }
51 }
52}
53
54///Hash algorithm selection
55#[derive(Clone, Copy, PartialEq)]
56pub enum Algorithm {
57 /// SHA-1 Algorithm
58 SHA1 = 0,
59
60 #[cfg(any(hash_v1, hash_v2, hash_v4))]
61 /// MD5 Algorithm
62 MD5 = 1,
63
64 /// SHA-224 Algorithm
65 SHA224 = 2,
66
67 /// SHA-256 Algorithm
68 SHA256 = 3,
69
70 #[cfg(hash_v3)]
71 /// SHA-384 Algorithm
72 SHA384 = 12,
73
74 #[cfg(hash_v3)]
75 /// SHA-512/224 Algorithm
76 SHA512_224 = 13,
77
78 #[cfg(hash_v3)]
79 /// SHA-512/256 Algorithm
80 SHA512_256 = 14,
81
82 #[cfg(hash_v3)]
83 /// SHA-256 Algorithm
84 SHA512 = 15,
85}
86
87/// Input data width selection
88#[repr(u8)]
89#[derive(Clone, Copy)]
90pub enum DataType {
91 ///32-bit data, no data is swapped.
92 Width32 = 0,
93 ///16-bit data, each half-word is swapped.
94 Width16 = 1,
95 ///8-bit data, all bytes are swapped.
96 Width8 = 2,
97 ///1-bit data, all bits are swapped.
98 Width1 = 3,
99}
100
101/// Stores the state of the HASH peripheral for suspending/resuming
102/// digest calculation.
103pub struct Context<'c> {
104 first_word_sent: bool,
105 key_sent: bool,
106 buffer: [u8; HASH_BUFFER_LEN],
107 buflen: usize,
108 algo: Algorithm,
109 format: DataType,
110 imr: u32,
111 str: u32,
112 cr: u32,
113 csr: [u32; NUM_CONTEXT_REGS],
114 key: HmacKey<'c>,
115}
116
117type HmacKey<'k> = Option<&'k [u8]>;
118
119/// HASH driver.
120pub struct Hash<'d, T: Instance, D = NoDma> {
121 _peripheral: PeripheralRef<'d, T>,
122 #[allow(dead_code)]
123 dma: PeripheralRef<'d, D>,
124}
125
126impl<'d, T: Instance, D> Hash<'d, T, D> {
127 /// Instantiates, resets, and enables the HASH peripheral.
128 pub fn new(
129 peripheral: impl Peripheral<P = T> + 'd,
130 dma: impl Peripheral<P = D> + 'd,
131 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
132 ) -> Self {
133 HASH::enable_and_reset();
134 into_ref!(peripheral, dma);
135 let instance = Self {
136 _peripheral: peripheral,
137 dma: dma,
138 };
139
140 T::Interrupt::unpend();
141 unsafe { T::Interrupt::enable() };
142
143 instance
144 }
145
146 /// Starts computation of a new hash and returns the saved peripheral state.
147 pub fn start<'c>(&mut self, algorithm: Algorithm, format: DataType, key: HmacKey<'c>) -> Context<'c> {
148 // Define a context for this new computation.
149 let mut ctx = Context {
150 first_word_sent: false,
151 key_sent: false,
152 buffer: [0; HASH_BUFFER_LEN],
153 buflen: 0,
154 algo: algorithm,
155 format: format,
156 imr: 0,
157 str: 0,
158 cr: 0,
159 csr: [0; NUM_CONTEXT_REGS],
160 key,
161 };
162
163 // Set the data type in the peripheral.
164 T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8));
165
166 // Select the algorithm.
167 #[cfg(hash_v1)]
168 if ctx.algo == Algorithm::MD5 {
169 T::regs().cr().modify(|w| w.set_algo(true));
170 }
171
172 #[cfg(hash_v2)]
173 {
174 // Select the algorithm.
175 let mut algo0 = false;
176 let mut algo1 = false;
177 if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 {
178 algo0 = true;
179 }
180 if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 {
181 algo1 = true;
182 }
183 T::regs().cr().modify(|w| w.set_algo0(algo0));
184 T::regs().cr().modify(|w| w.set_algo1(algo1));
185 }
186
187 #[cfg(any(hash_v3, hash_v4))]
188 T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8));
189
190 // Configure HMAC mode if a key is provided.
191 if let Some(key) = ctx.key {
192 T::regs().cr().modify(|w| w.set_mode(true));
193 if key.len() > 64 {
194 T::regs().cr().modify(|w| w.set_lkey(true));
195 }
196 }
197
198 T::regs().cr().modify(|w| w.set_init(true));
199
200 // Store and return the state of the peripheral.
201 self.store_context(&mut ctx);
202 ctx
203 }
204
205 /// Restores the peripheral state using the given context,
206 /// then updates the state with the provided data.
207 /// Peripheral state is saved upon return.
208 pub fn update_blocking<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8]) {
209 // Restore the peripheral state.
210 self.load_context(&ctx);
211
212 // Load the HMAC key if provided.
213 if !ctx.key_sent {
214 if let Some(key) = ctx.key {
215 self.accumulate_blocking(key);
216 T::regs().str().write(|w| w.set_dcal(true));
217 // Block waiting for digest.
218 while !T::regs().sr().read().dinis() {}
219 }
220 ctx.key_sent = true;
221 }
222
223 let mut data_waiting = input.len() + ctx.buflen;
224 if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) {
225 // There isn't enough data to digest a block, so append it to the buffer.
226 ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input);
227 ctx.buflen += input.len();
228 self.store_context(ctx);
229 return;
230 }
231
232 let mut ilen_remaining = input.len();
233 let mut input_start = 0;
234
235 // Handle first block.
236 if !ctx.first_word_sent {
237 let empty_len = ctx.buffer.len() - ctx.buflen;
238 let copy_len = min(empty_len, ilen_remaining);
239 // Fill the buffer.
240 if copy_len > 0 {
241 ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[0..copy_len]);
242 ctx.buflen += copy_len;
243 ilen_remaining -= copy_len;
244 input_start += copy_len;
245 }
246 self.accumulate_blocking(ctx.buffer.as_slice());
247 data_waiting -= ctx.buflen;
248 ctx.buflen = 0;
249 ctx.first_word_sent = true;
250 }
251
252 if data_waiting < DIGEST_BLOCK_SIZE {
253 // There isn't enough data remaining to process another block, so store it.
254 ctx.buffer[0..ilen_remaining].copy_from_slice(&input[input_start..input_start + ilen_remaining]);
255 ctx.buflen += ilen_remaining;
256 } else {
257 // First ingest the data in the buffer.
258 let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen;
259 if empty_len > 0 {
260 let copy_len = min(empty_len, ilen_remaining);
261 ctx.buffer[ctx.buflen..ctx.buflen + copy_len]
262 .copy_from_slice(&input[input_start..input_start + copy_len]);
263 ctx.buflen += copy_len;
264 ilen_remaining -= copy_len;
265 input_start += copy_len;
266 }
267 self.accumulate_blocking(&ctx.buffer[0..DIGEST_BLOCK_SIZE]);
268 ctx.buflen = 0;
269
270 // Move any extra data to the now-empty buffer.
271 let leftovers = ilen_remaining % 64;
272 if leftovers > 0 {
273 ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]);
274 ctx.buflen += leftovers;
275 ilen_remaining -= leftovers;
276 }
277
278 // Hash the remaining data.
279 self.accumulate_blocking(&input[input_start..input_start + ilen_remaining]);
280 }
281
282 // Save the peripheral context.
283 self.store_context(ctx);
284 }
285
286 /// Restores the peripheral state using the given context,
287 /// then updates the state with the provided data.
288 /// Peripheral state is saved upon return.
289 #[cfg(hash_v2)]
290 pub async fn update<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8])
291 where
292 D: crate::hash::Dma<T>,
293 {
294 // Restore the peripheral state.
295 self.load_context(&ctx);
296
297 // Load the HMAC key if provided.
298 if !ctx.key_sent {
299 if let Some(key) = ctx.key {
300 self.accumulate(key).await;
301 }
302 ctx.key_sent = true;
303 }
304
305 let data_waiting = input.len() + ctx.buflen;
306 if data_waiting < DIGEST_BLOCK_SIZE {
307 // There isn't enough data to digest a block, so append it to the buffer.
308 ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input);
309 ctx.buflen += input.len();
310 self.store_context(ctx);
311 return;
312 }
313
314 // Enable multiple DMA transfers.
315 T::regs().cr().modify(|w| w.set_mdmat(true));
316
317 let mut ilen_remaining = input.len();
318 let mut input_start = 0;
319
320 // First ingest the data in the buffer.
321 let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen;
322 if empty_len > 0 {
323 let copy_len = min(empty_len, ilen_remaining);
324 ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[input_start..input_start + copy_len]);
325 ctx.buflen += copy_len;
326 ilen_remaining -= copy_len;
327 input_start += copy_len;
328 }
329 self.accumulate(&ctx.buffer[..DIGEST_BLOCK_SIZE]).await;
330 ctx.buflen = 0;
331
332 // Move any extra data to the now-empty buffer.
333 let leftovers = ilen_remaining % DIGEST_BLOCK_SIZE;
334 if leftovers > 0 {
335 assert!(ilen_remaining >= leftovers);
336 ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]);
337 ctx.buflen += leftovers;
338 ilen_remaining -= leftovers;
339 } else {
340 ctx.buffer
341 .copy_from_slice(&input[input.len() - DIGEST_BLOCK_SIZE..input.len()]);
342 ctx.buflen += DIGEST_BLOCK_SIZE;
343 ilen_remaining -= DIGEST_BLOCK_SIZE;
344 }
345
346 // Hash the remaining data.
347 self.accumulate(&input[input_start..input_start + ilen_remaining]).await;
348
349 // Save the peripheral context.
350 self.store_context(ctx);
351 }
352
353 /// Computes a digest for the given context.
354 /// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
355 /// The largest returned digest size is 128 bytes for SHA-512.
356 /// Panics if the supplied digest buffer is too short.
357 pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize {
358 // Restore the peripheral state.
359 self.load_context(&ctx);
360
361 // Hash the leftover bytes, if any.
362 self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]);
363 ctx.buflen = 0;
364
365 //Start the digest calculation.
366 T::regs().str().write(|w| w.set_dcal(true));
367
368 // Load the HMAC key if provided.
369 if let Some(key) = ctx.key {
370 while !T::regs().sr().read().dinis() {}
371 self.accumulate_blocking(key);
372 T::regs().str().write(|w| w.set_dcal(true));
373 }
374
375 // Block until digest computation is complete.
376 while !T::regs().sr().read().dcis() {}
377
378 // Return the digest.
379 let digest_words = match ctx.algo {
380 Algorithm::SHA1 => 5,
381 #[cfg(any(hash_v1, hash_v2, hash_v4))]
382 Algorithm::MD5 => 4,
383 Algorithm::SHA224 => 7,
384 Algorithm::SHA256 => 8,
385 #[cfg(hash_v3)]
386 Algorithm::SHA384 => 12,
387 #[cfg(hash_v3)]
388 Algorithm::SHA512_224 => 7,
389 #[cfg(hash_v3)]
390 Algorithm::SHA512_256 => 8,
391 #[cfg(hash_v3)]
392 Algorithm::SHA512 => 16,
393 };
394
395 let digest_len_bytes = digest_words * 4;
396 // Panics if the supplied digest buffer is too short.
397 if digest.len() < digest_len_bytes {
398 panic!("Digest buffer must be at least {} bytes long.", digest_words * 4);
399 }
400
401 let mut i = 0;
402 while i < digest_words {
403 let word = T::regs().hr(i).read();
404 digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice());
405 i += 1;
406 }
407 digest_len_bytes
408 }
409
410 /// Computes a digest for the given context.
411 /// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
412 /// The largest returned digest size is 128 bytes for SHA-512.
413 /// Panics if the supplied digest buffer is too short.
414 #[cfg(hash_v2)]
415 pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize
416 where
417 D: crate::hash::Dma<T>,
418 {
419 // Restore the peripheral state.
420 self.load_context(&ctx);
421
422 // Must be cleared prior to the last DMA transfer.
423 T::regs().cr().modify(|w| w.set_mdmat(false));
424
425 // Hash the leftover bytes, if any.
426 self.accumulate(&ctx.buffer[0..ctx.buflen]).await;
427 ctx.buflen = 0;
428
429 // Load the HMAC key if provided.
430 if let Some(key) = ctx.key {
431 self.accumulate(key).await;
432 }
433
434 // Wait for completion.
435 poll_fn(|cx| {
436 // Check if already done.
437 let bits = T::regs().sr().read();
438 if bits.dcis() {
439 return Poll::Ready(());
440 }
441 // Register waker, then enable interrupts.
442 HASH_WAKER.register(cx.waker());
443 T::regs().imr().modify(|reg| reg.set_dcie(true));
444 // Check for completion.
445 let bits = T::regs().sr().read();
446 if bits.dcis() {
447 Poll::Ready(())
448 } else {
449 Poll::Pending
450 }
451 })
452 .await;
453
454 // Return the digest.
455 let digest_words = match ctx.algo {
456 Algorithm::SHA1 => 5,
457 #[cfg(any(hash_v1, hash_v2, hash_v4))]
458 Algorithm::MD5 => 4,
459 Algorithm::SHA224 => 7,
460 Algorithm::SHA256 => 8,
461 #[cfg(hash_v3)]
462 Algorithm::SHA384 => 12,
463 #[cfg(hash_v3)]
464 Algorithm::SHA512_224 => 7,
465 #[cfg(hash_v3)]
466 Algorithm::SHA512_256 => 8,
467 #[cfg(hash_v3)]
468 Algorithm::SHA512 => 16,
469 };
470
471 let digest_len_bytes = digest_words * 4;
472 // Panics if the supplied digest buffer is too short.
473 if digest.len() < digest_len_bytes {
474 panic!("Digest buffer must be at least {} bytes long.", digest_words * 4);
475 }
476
477 let mut i = 0;
478 while i < digest_words {
479 let word = T::regs().hr(i).read();
480 digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice());
481 i += 1;
482 }
483 digest_len_bytes
484 }
485
486 /// Push data into the hash core.
487 fn accumulate_blocking(&mut self, input: &[u8]) {
488 // Set the number of valid bits.
489 let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8;
490 T::regs().str().modify(|w| w.set_nblw(num_valid_bits));
491
492 let mut i = 0;
493 while i < input.len() {
494 let mut word: [u8; 4] = [0; 4];
495 let copy_idx = min(i + 4, input.len());
496 word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]);
497 T::regs().din().write_value(u32::from_ne_bytes(word));
498 i += 4;
499 }
500 }
501
502 /// Push data into the hash core.
503 #[cfg(hash_v2)]
504 async fn accumulate(&mut self, input: &[u8])
505 where
506 D: crate::hash::Dma<T>,
507 {
508 // Ignore an input length of 0.
509 if input.len() == 0 {
510 return;
511 }
512
513 // Set the number of valid bits.
514 let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8;
515 T::regs().str().modify(|w| w.set_nblw(num_valid_bits));
516
517 // Configure DMA to transfer input to hash core.
518 let dma_request = self.dma.request();
519 let dst_ptr = T::regs().din().as_ptr();
520 let mut num_words = input.len() / 4;
521 if input.len() % 4 > 0 {
522 num_words += 1;
523 }
524 let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words);
525 let dma_transfer =
526 unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) };
527 T::regs().cr().modify(|w| w.set_dmae(true));
528
529 // Wait for the transfer to complete.
530 dma_transfer.await;
531 }
532
533 /// Save the peripheral state to a context.
534 fn store_context<'c>(&mut self, ctx: &mut Context<'c>) {
535 // Block waiting for data in ready.
536 while !T::regs().sr().read().dinis() {}
537
538 // Store peripheral context.
539 ctx.imr = T::regs().imr().read().0;
540 ctx.str = T::regs().str().read().0;
541 ctx.cr = T::regs().cr().read().0;
542 let mut i = 0;
543 while i < NUM_CONTEXT_REGS {
544 ctx.csr[i] = T::regs().csr(i).read();
545 i += 1;
546 }
547 }
548
549 /// Restore the peripheral state from a context.
550 fn load_context(&mut self, ctx: &Context) {
551 // Restore the peripheral state from the context.
552 T::regs().imr().write_value(Imr { 0: ctx.imr });
553 T::regs().str().write_value(Str { 0: ctx.str });
554 T::regs().cr().write_value(Cr { 0: ctx.cr });
555 T::regs().cr().modify(|w| w.set_init(true));
556 let mut i = 0;
557 while i < NUM_CONTEXT_REGS {
558 T::regs().csr(i).write_value(ctx.csr[i]);
559 i += 1;
560 }
561 }
562}
563
564pub(crate) mod sealed {
565 use super::*;
566
567 pub trait Instance {
568 fn regs() -> pac::hash::Hash;
569 }
570}
571
572/// HASH instance trait.
573pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send {
574 /// Interrupt for this HASH instance.
575 type Interrupt: interrupt::typelevel::Interrupt;
576}
577
578foreach_interrupt!(
579 ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => {
580 impl Instance for peripherals::$inst {
581 type Interrupt = crate::interrupt::typelevel::$irq;
582 }
583
584 impl sealed::Instance for peripherals::$inst {
585 fn regs() -> crate::pac::hash::Hash {
586 crate::pac::$inst
587 }
588 }
589 };
590);
591
592dma_trait!(Dma, Instance);
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index faefaabbc..3ec646fc3 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -10,8 +10,6 @@ pub use traits::Instance;
10#[allow(unused_imports)] 10#[allow(unused_imports)]
11use crate::gpio::sealed::{AFType, Pin}; 11use crate::gpio::sealed::{AFType, Pin};
12use crate::gpio::AnyPin; 12use crate::gpio::AnyPin;
13#[cfg(stm32f334)]
14use crate::rcc::get_freqs;
15use crate::time::Hertz; 13use crate::time::Hertz;
16use crate::Peripheral; 14use crate::Peripheral;
17 15
@@ -182,7 +180,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
182 T::enable_and_reset(); 180 T::enable_and_reset();
183 181
184 #[cfg(stm32f334)] 182 #[cfg(stm32f334)]
185 if unsafe { get_freqs() }.hrtim.is_some() { 183 if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P {
186 // Enable and and stabilize the DLL 184 // Enable and and stabilize the DLL
187 T::regs().dllcr().modify(|w| { 185 T::regs().dllcr().modify(|w| {
188 w.set_cal(true); 186 w.set_cal(true);
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs
index cfd31c47c..dcc2b9ef4 100644
--- a/embassy-stm32/src/hrtim/traits.rs
+++ b/embassy-stm32/src/hrtim/traits.rs
@@ -80,10 +80,12 @@ pub(crate) mod sealed {
80 80
81 fn set_master_frequency(frequency: Hertz) { 81 fn set_master_frequency(frequency: Hertz) {
82 let f = frequency.0; 82 let f = frequency.0;
83 #[cfg(not(stm32f334))] 83
84 // TODO: wire up HRTIM to the RCC mux infra.
85 //#[cfg(stm32f334)]
86 //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
87 //#[cfg(not(stm32f334))]
84 let timer_f = Self::frequency().0; 88 let timer_f = Self::frequency().0;
85 #[cfg(stm32f334)]
86 let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
87 89
88 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); 90 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
89 let psc = if Self::regs().isr().read().dllrdy() { 91 let psc = if Self::regs().isr().read().dllrdy() {
@@ -103,10 +105,12 @@ pub(crate) mod sealed {
103 105
104 fn set_channel_frequency(channel: usize, frequency: Hertz) { 106 fn set_channel_frequency(channel: usize, frequency: Hertz) {
105 let f = frequency.0; 107 let f = frequency.0;
106 #[cfg(not(stm32f334))] 108
109 // TODO: wire up HRTIM to the RCC mux infra.
110 //#[cfg(stm32f334)]
111 //let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
112 //#[cfg(not(stm32f334))]
107 let timer_f = Self::frequency().0; 113 let timer_f = Self::frequency().0;
108 #[cfg(stm32f334)]
109 let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
110 114
111 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); 115 let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
112 let psc = if Self::regs().isr().read().dllrdy() { 116 let psc = if Self::regs().isr().read().dllrdy() {
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 1f85c0bc5..fa9ec0532 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -4,7 +4,6 @@ use embassy_hal_internal::into_ref;
4use crate::gpio::sealed::{AFType, Pin as _}; 4use crate::gpio::sealed::{AFType, Pin as _};
5use crate::gpio::AnyPin; 5use crate::gpio::AnyPin;
6use crate::pac::spi::vals; 6use crate::pac::spi::vals;
7use crate::rcc::get_freqs;
8use crate::spi::{Config as SpiConfig, *}; 7use crate::spi::{Config as SpiConfig, *};
9use crate::time::Hertz; 8use crate::time::Hertz;
10use crate::{Peripheral, PeripheralRef}; 9use crate::{Peripheral, PeripheralRef};
@@ -80,20 +79,20 @@ impl Format {
80 #[cfg(any(spi_v1, spi_f1))] 79 #[cfg(any(spi_v1, spi_f1))]
81 const fn datlen(&self) -> vals::Datlen { 80 const fn datlen(&self) -> vals::Datlen {
82 match self { 81 match self {
83 Format::Data16Channel16 => vals::Datlen::SIXTEENBIT, 82 Format::Data16Channel16 => vals::Datlen::BITS16,
84 Format::Data16Channel32 => vals::Datlen::SIXTEENBIT, 83 Format::Data16Channel32 => vals::Datlen::BITS16,
85 Format::Data24Channel32 => vals::Datlen::TWENTYFOURBIT, 84 Format::Data24Channel32 => vals::Datlen::BITS24,
86 Format::Data32Channel32 => vals::Datlen::THIRTYTWOBIT, 85 Format::Data32Channel32 => vals::Datlen::BITS32,
87 } 86 }
88 } 87 }
89 88
90 #[cfg(any(spi_v1, spi_f1))] 89 #[cfg(any(spi_v1, spi_f1))]
91 const fn chlen(&self) -> vals::Chlen { 90 const fn chlen(&self) -> vals::Chlen {
92 match self { 91 match self {
93 Format::Data16Channel16 => vals::Chlen::SIXTEENBIT, 92 Format::Data16Channel16 => vals::Chlen::BITS16,
94 Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT, 93 Format::Data16Channel32 => vals::Chlen::BITS32,
95 Format::Data24Channel32 => vals::Chlen::THIRTYTWOBIT, 94 Format::Data24Channel32 => vals::Chlen::BITS32,
96 Format::Data32Channel32 => vals::Chlen::THIRTYTWOBIT, 95 Format::Data32Channel32 => vals::Chlen::BITS32,
97 } 96 }
98 } 97 }
99} 98}
@@ -193,10 +192,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
193 spi_cfg.frequency = freq; 192 spi_cfg.frequency = freq;
194 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg); 193 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
195 194
196 #[cfg(all(rcc_f4, not(stm32f410)))] 195 // TODO move i2s to the new mux infra.
197 let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap(); 196 //#[cfg(all(rcc_f4, not(stm32f410)))]
198 197 //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
199 #[cfg(stm32f410)] 198 //#[cfg(stm32f410)]
200 let pclk = T::frequency(); 199 let pclk = T::frequency();
201 200
202 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); 201 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 663a7f59d..523719bb9 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -7,7 +7,6 @@ use core::task::Poll;
7use self::sealed::Instance; 7use self::sealed::Instance;
8use crate::interrupt; 8use crate::interrupt;
9use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
10use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel};
11use crate::peripherals::IPCC; 10use crate::peripherals::IPCC;
12use crate::rcc::sealed::RccPeripheral; 11use crate::rcc::sealed::RccPeripheral;
13 12
@@ -105,7 +104,8 @@ impl Ipcc {
105 IPCC::enable_and_reset(); 104 IPCC::enable_and_reset();
106 IPCC::set_cpu2(true); 105 IPCC::set_cpu2(true);
107 106
108 _configure_pwr(); 107 // set RF wake-up clock = LSE
108 crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01));
109 109
110 let regs = IPCC::regs(); 110 let regs = IPCC::regs();
111 111
@@ -271,18 +271,3 @@ pub(crate) mod sealed {
271 fn state() -> &'static State; 271 fn state() -> &'static State;
272 } 272 }
273} 273}
274
275fn _configure_pwr() {
276 // TODO: move the rest of this to rcc
277 let rcc = crate::pac::RCC;
278
279 // TODO: required
280 // set RF wake-up clock = LSE
281 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
282
283 // set LPTIM1 & LPTIM2 clock source
284 rcc.ccipr().modify(|w| {
285 w.set_lptim1sel(Lptim1sel::PCLK1);
286 w.set_lptim2sel(Lptim2sel::PCLK1);
287 });
288}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index e18b16935..aba53ad80 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -34,6 +34,8 @@ pub mod adc;
34pub mod can; 34pub mod can;
35#[cfg(crc)] 35#[cfg(crc)]
36pub mod crc; 36pub mod crc;
37#[cfg(cryp)]
38pub mod cryp;
37#[cfg(dac)] 39#[cfg(dac)]
38pub mod dac; 40pub mod dac;
39#[cfg(dcmi)] 41#[cfg(dcmi)]
@@ -45,6 +47,8 @@ pub mod exti;
45pub mod flash; 47pub mod flash;
46#[cfg(fmc)] 48#[cfg(fmc)]
47pub mod fmc; 49pub mod fmc;
50#[cfg(hash)]
51pub mod hash;
48#[cfg(hrtim)] 52#[cfg(hrtim)]
49pub mod hrtim; 53pub mod hrtim;
50#[cfg(i2c)] 54#[cfg(i2c)]
@@ -216,6 +220,11 @@ pub fn init(config: Config) -> Peripherals {
216 220
217 #[cfg(dbgmcu)] 221 #[cfg(dbgmcu)]
218 crate::pac::DBGMCU.cr().modify(|cr| { 222 crate::pac::DBGMCU.cr().modify(|cr| {
223 #[cfg(any(dbgmcu_h5))]
224 {
225 cr.set_stop(config.enable_debug_during_sleep);
226 cr.set_standby(config.enable_debug_during_sleep);
227 }
219 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))] 228 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))]
220 { 229 {
221 cr.set_dbg_stop(config.enable_debug_during_sleep); 230 cr.set_dbg_stop(config.enable_debug_during_sleep);
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index ae8b3cacc..cf531e266 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -90,6 +90,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
90 in_pin.set_as_analog(); 90 in_pin.set_as_analog();
91 out_pin.set_as_analog(); 91 out_pin.set_as_analog();
92 92
93 // PGA_GAIN value may have different meaning in different MCU serials, use with caution.
93 let (vm_sel, pga_gain) = match gain { 94 let (vm_sel, pga_gain) = match gain {
94 OpAmpGain::Mul1 => (0b11, 0b00), 95 OpAmpGain::Mul1 => (0b11, 0b00),
95 OpAmpGain::Mul2 => (0b10, 0b00), 96 OpAmpGain::Mul2 => (0b10, 0b00),
@@ -127,6 +128,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
127 into_ref!(pin); 128 into_ref!(pin);
128 pin.set_as_analog(); 129 pin.set_as_analog();
129 130
131 // PGA_GAIN value may have different meaning in different MCU serials, use with caution.
130 let (vm_sel, pga_gain) = match gain { 132 let (vm_sel, pga_gain) = match gain {
131 OpAmpGain::Mul1 => (0b11, 0b00), 133 OpAmpGain::Mul1 => (0b11, 0b00),
132 OpAmpGain::Mul2 => (0b10, 0b00), 134 OpAmpGain::Mul2 => (0b10, 0b00),
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index d20f58185..39407b28c 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -201,12 +201,19 @@ impl LsConfig {
201 bdcr().modify(|w| w.set_bdrst(true)); 201 bdcr().modify(|w| w.set_bdrst(true));
202 bdcr().modify(|w| w.set_bdrst(false)); 202 bdcr().modify(|w| w.set_bdrst(false));
203 } 203 }
204 #[cfg(any(stm32h5))] 204 // H5 has a terrible, terrible errata: 'SRAM2 is erased when the backup domain is reset'
205 { 205 // pending a more sane sane way to handle this, just don't reset BD for now.
206 bdcr().modify(|w| w.set_vswrst(true)); 206 // This means the RTCSEL write below will have no effect, only if it has already been written
207 bdcr().modify(|w| w.set_vswrst(false)); 207 // after last power-on. Since it's uncommon to dynamically change RTCSEL, this is better than
208 } 208 // letting half our RAM go magically *poof*.
209 #[cfg(any(stm32c0))] 209 // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset
210 // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset
211 //#[cfg(any(stm32h5))]
212 //{
213 // bdcr().modify(|w| w.set_vswrst(true));
214 // bdcr().modify(|w| w.set_vswrst(false));
215 //}
216 #[cfg(any(stm32c0, stm32l0))]
210 { 217 {
211 bdcr().modify(|w| w.set_rtcrst(true)); 218 bdcr().modify(|w| w.set_rtcrst(true));
212 bdcr().modify(|w| w.set_rtcrst(false)); 219 bdcr().modify(|w| w.set_rtcrst(false));
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 68f029ca0..349f978c5 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -1,145 +1,184 @@
1use crate::pac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2use crate::pac::rcc::vals::Sw; 2pub use crate::pac::rcc::vals::{
3pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler}; 3 Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Hsikerdiv as HsiKerDiv, Ppre as APBPrescaler, Sw as Sysclk,
4};
4use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 6use crate::time::Hertz;
7 7
8/// HSI speed 8/// HSI speed
9pub const HSI_FREQ: Hertz = Hertz(48_000_000); 9pub const HSI_FREQ: Hertz = Hertz(48_000_000);
10 10
11/// System clock mux source 11/// HSE Mode
12#[derive(Clone, Copy)] 12#[derive(Clone, Copy, Eq, PartialEq)]
13pub enum ClockSrc { 13pub enum HseMode {
14 HSE(Hertz), 14 /// crystal/ceramic oscillator (HSEBYP=0)
15 HSI(HSIPrescaler), 15 Oscillator,
16 LSI, 16 /// external analog clock (low swing) (HSEBYP=1)
17 Bypass,
18}
19
20/// HSE Configuration
21#[derive(Clone, Copy, Eq, PartialEq)]
22pub struct Hse {
23 /// HSE frequency.
24 pub freq: Hertz,
25 /// HSE mode.
26 pub mode: HseMode,
27}
28
29/// HSI Configuration
30#[derive(Clone, Copy, Eq, PartialEq)]
31pub struct Hsi {
32 /// Division factor for HSISYS clock. Default is 4.
33 pub sys_div: HsiSysDiv,
34 /// Division factor for HSIKER clock. Default is 3.
35 pub ker_div: HsiKerDiv,
17} 36}
18 37
19/// Clocks configutation 38/// Clocks configutation
39#[non_exhaustive]
20pub struct Config { 40pub struct Config {
21 pub mux: ClockSrc, 41 /// HSI Configuration
42 pub hsi: Option<Hsi>,
43
44 /// HSE Configuration
45 pub hse: Option<Hse>,
46
47 /// System Clock Configuration
48 pub sys: Sysclk,
49
22 pub ahb_pre: AHBPrescaler, 50 pub ahb_pre: AHBPrescaler,
23 pub apb_pre: APBPrescaler, 51 pub apb1_pre: APBPrescaler,
52
53 /// Low-Speed Clock Configuration
24 pub ls: super::LsConfig, 54 pub ls: super::LsConfig,
55
56 /// Per-peripheral kernel clock selection muxes
57 pub mux: super::mux::ClockMux,
25} 58}
26 59
27impl Default for Config { 60impl Default for Config {
28 #[inline] 61 #[inline]
29 fn default() -> Config { 62 fn default() -> Config {
30 Config { 63 Config {
31 mux: ClockSrc::HSI(HSIPrescaler::DIV1), 64 hsi: Some(Hsi {
65 sys_div: HsiSysDiv::DIV4,
66 ker_div: HsiKerDiv::DIV3,
67 }),
68 hse: None,
69 sys: Sysclk::HSISYS,
32 ahb_pre: AHBPrescaler::DIV1, 70 ahb_pre: AHBPrescaler::DIV1,
33 apb_pre: APBPrescaler::DIV1, 71 apb1_pre: APBPrescaler::DIV1,
34 ls: Default::default(), 72 ls: Default::default(),
73 mux: Default::default(),
35 } 74 }
36 } 75 }
37} 76}
38 77
39pub(crate) unsafe fn init(config: Config) { 78pub(crate) unsafe fn init(config: Config) {
40 let (sys_clk, sw) = match config.mux { 79 // Configure HSI
41 ClockSrc::HSI(div) => { 80 let (hsi, hsisys, hsiker) = match config.hsi {
42 // Enable HSI 81 None => {
43 RCC.cr().write(|w| { 82 RCC.cr().modify(|w| w.set_hsion(false));
44 w.set_hsidiv(div); 83 (None, None, None)
45 w.set_hsion(true) 84 }
85 Some(hsi) => {
86 RCC.cr().modify(|w| {
87 w.set_hsidiv(hsi.sys_div);
88 w.set_hsikerdiv(hsi.ker_div);
89 w.set_hsion(true);
46 }); 90 });
47 while !RCC.cr().read().hsirdy() {} 91 while !RCC.cr().read().hsirdy() {}
48 92 (
49 (HSI_FREQ / div, Sw::HSI) 93 Some(HSI_FREQ),
94 Some(HSI_FREQ / hsi.sys_div),
95 Some(HSI_FREQ / hsi.ker_div),
96 )
50 } 97 }
51 ClockSrc::HSE(freq) => { 98 };
52 // Enable HSE
53 RCC.cr().write(|w| w.set_hseon(true));
54 while !RCC.cr().read().hserdy() {}
55 99
56 (freq, Sw::HSE) 100 // Configure HSE
101 let hse = match config.hse {
102 None => {
103 RCC.cr().modify(|w| w.set_hseon(false));
104 None
57 } 105 }
58 ClockSrc::LSI => { 106 Some(hse) => {
59 // Enable LSI 107 match hse.mode {
60 RCC.csr2().write(|w| w.set_lsion(true)); 108 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
61 while !RCC.csr2().read().lsirdy() {} 109 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
62 (super::LSI_FREQ, Sw::LSI) 110 }
111
112 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
113 RCC.cr().modify(|w| w.set_hseon(true));
114 while !RCC.cr().read().hserdy() {}
115 Some(hse.freq)
63 } 116 }
64 }; 117 };
65 118
66 let rtc = config.ls.init(); 119 let sys = match config.sys {
120 Sysclk::HSISYS => unwrap!(hsisys),
121 Sysclk::HSE => unwrap!(hse),
122 _ => unreachable!(),
123 };
67 124
68 // Determine the flash latency implied by the target clock speed 125 assert!(max::SYSCLK.contains(&sys));
69 // RM0454 § 3.3.4: 126
70 let target_flash_latency = if sys_clk <= Hertz(24_000_000) { 127 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
71 Latency::WS0 128 let hclk = sys / config.ahb_pre;
72 } else { 129 assert!(max::HCLK.contains(&hclk));
73 Latency::WS1 130
131 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
132 assert!(max::PCLK.contains(&pclk1));
133
134 let latency = match hclk.0 {
135 ..=24_000_000 => Latency::WS0,
136 _ => Latency::WS1,
74 }; 137 };
75 138
76 // Increase the number of cycles we wait for flash if the new value is higher 139 // Configure flash read access latency based on voltage scale and frequency
77 // There's no harm in waiting a little too much before the clock change, but we'll
78 // crash immediately if we don't wait enough after the clock change
79 let mut set_flash_latency_after = false;
80 FLASH.acr().modify(|w| { 140 FLASH.acr().modify(|w| {
81 // Is the current flash latency less than what we need at the new SYSCLK? 141 w.set_latency(latency);
82 if w.latency().to_bits() <= target_flash_latency.to_bits() {
83 // We must increase the number of wait states now
84 w.set_latency(target_flash_latency)
85 } else {
86 // We may decrease the number of wait states later
87 set_flash_latency_after = true;
88 }
89
90 // RM0490 § 3.3.4:
91 // > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register
92 // > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the
93 // > Flash memory.
94 //
95 // Enable flash prefetching if we have at least one wait state, and disable it otherwise.
96 w.set_prften(target_flash_latency.to_bits() > 0);
97 }); 142 });
98 143
99 if !set_flash_latency_after { 144 // Spin until the effective flash latency is set.
100 // Spin until the effective flash latency is compatible with the clock change 145 while FLASH.acr().read().latency() != latency {}
101 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
102 }
103 146
104 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 147 // Now that boost mode and flash read access latency are configured, set up SYSCLK
105 let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
106 RCC.cfgr().modify(|w| { 148 RCC.cfgr().modify(|w| {
107 w.set_sw(sw); 149 w.set_sw(config.sys);
108 w.set_hpre(hpre); 150 w.set_hpre(config.ahb_pre);
109 w.set_ppre(ppre); 151 w.set_ppre(config.apb1_pre);
110 }); 152 });
111 153
112 if set_flash_latency_after { 154 let rtc = config.ls.init();
113 // We can make the flash require fewer wait states
114 // Spin until the SYSCLK changes have taken effect
115 loop {
116 let cfgr = RCC.cfgr().read();
117 if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
118 break;
119 }
120 }
121
122 // Set the flash latency to require fewer wait states
123 FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
124 }
125 155
126 let ahb_freq = sys_clk / config.ahb_pre; 156 config.mux.init();
127 157
128 let (apb_freq, apb_tim_freq) = match config.apb_pre { 158 set_clocks!(
129 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 159 sys: Some(sys),
130 pre => { 160 hclk1: Some(hclk),
131 let freq = ahb_freq / pre; 161 pclk1: Some(pclk1),
132 (freq, freq * 2u32) 162 pclk1_tim: Some(pclk1_tim),
133 } 163 hsi: hsi,
134 }; 164 hsiker: hsiker,
165 hse: hse,
166 rtc: rtc,
135 167
136 set_freqs(Clocks { 168 // TODO
137 hsi: None, 169 lsi: None,
138 lse: None, 170 lse: None,
139 sys: sys_clk, 171 );
140 hclk1: ahb_freq, 172}
141 pclk1: apb_freq, 173
142 pclk1_tim: apb_tim_freq, 174mod max {
143 rtc, 175 use core::ops::RangeInclusive;
144 }); 176
177 use crate::time::Hertz;
178
179 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(48_000_000);
180 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
181 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
182 pub(crate) const PCLK: RangeInclusive<Hertz> = Hertz(8)..=Hertz(48_000_000);
183 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
145} 184}
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs
deleted file mode 100644
index feaa2f4c0..000000000
--- a/embassy-stm32/src/rcc/f0.rs
+++ /dev/null
@@ -1,172 +0,0 @@
1use stm32_metapac::flash::vals::Latency;
2
3use super::{set_freqs, Clocks};
4use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
5use crate::pac::{FLASH, RCC};
6use crate::time::Hertz;
7
8/// HSI speed
9pub const HSI_FREQ: Hertz = Hertz(8_000_000);
10
11/// Configuration of the clocks
12///
13/// hse takes precedence over hsi48 if both are enabled
14#[non_exhaustive]
15#[derive(Default)]
16pub struct Config {
17 pub hse: Option<Hertz>,
18 pub bypass_hse: bool,
19 pub usb_pll: bool,
20
21 #[cfg(not(stm32f0x0))]
22 pub hsi48: bool,
23
24 pub sys_ck: Option<Hertz>,
25 pub hclk: Option<Hertz>,
26 pub pclk: Option<Hertz>,
27
28 pub ls: super::LsConfig,
29}
30
31pub(crate) unsafe fn init(config: Config) {
32 let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI_FREQ.0);
33
34 let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
35 #[cfg(not(stm32f0x0))]
36 if config.hsi48 {
37 return (48_000_000, true);
38 }
39 (HSI_FREQ.0, false)
40 });
41
42 let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
43 (None, sysclk)
44 } else {
45 let prediv = if config.hse.is_some() { 1 } else { 2 };
46 let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
47 let pllmul = pllmul.max(2).min(16);
48
49 let pllmul_bits = pllmul as u8 - 2;
50 let real_sysclk = pllmul * src_clk / prediv;
51 (Some(pllmul_bits), real_sysclk)
52 };
53
54 let hpre_bits = config
55 .hclk
56 .map(|hclk| match real_sysclk / hclk.0 {
57 0 => unreachable!(),
58 1 => 0b0111,
59 2 => 0b1000,
60 3..=5 => 0b1001,
61 6..=11 => 0b1010,
62 12..=39 => 0b1011,
63 40..=95 => 0b1100,
64 96..=191 => 0b1101,
65 192..=383 => 0b1110,
66 _ => 0b1111,
67 })
68 .unwrap_or(0b0111);
69 let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
70
71 let ppre_bits = config
72 .pclk
73 .map(|pclk| match hclk / pclk.0 {
74 0 => unreachable!(),
75 1 => 0b011,
76 2 => 0b100,
77 3..=5 => 0b101,
78 6..=11 => 0b110,
79 _ => 0b111,
80 })
81 .unwrap_or(0b011);
82
83 let ppre: u8 = 1 << (ppre_bits - 0b011);
84 let pclk = hclk / u32::from(ppre);
85
86 let timer_mul = if ppre == 1 { 1 } else { 2 };
87
88 FLASH.acr().write(|w| {
89 w.set_latency(if real_sysclk <= 24_000_000 {
90 Latency::WS0
91 } else {
92 Latency::WS1
93 });
94 });
95
96 match (config.hse.is_some(), use_hsi48) {
97 (true, _) => {
98 RCC.cr().modify(|w| {
99 w.set_csson(true);
100 w.set_hseon(true);
101 w.set_hsebyp(config.bypass_hse);
102 });
103 while !RCC.cr().read().hserdy() {}
104
105 if pllmul_bits.is_some() {
106 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
107 }
108 }
109 // use_hsi48 will always be false for stm32f0x0
110 #[cfg(not(stm32f0x0))]
111 (false, true) => {
112 RCC.cr2().modify(|w| w.set_hsi48on(true));
113 while !RCC.cr2().read().hsi48rdy() {}
114
115 if pllmul_bits.is_some() {
116 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
117 }
118 }
119 _ => {
120 RCC.cr().modify(|w| w.set_hsion(true));
121 while !RCC.cr().read().hsirdy() {}
122
123 if pllmul_bits.is_some() {
124 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
125 }
126 }
127 }
128
129 if config.usb_pll {
130 RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLL1_P));
131 }
132 // TODO: Option to use CRS (Clock Recovery)
133
134 if let Some(pllmul_bits) = pllmul_bits {
135 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul::from_bits(pllmul_bits)));
136
137 RCC.cr().modify(|w| w.set_pllon(true));
138 while !RCC.cr().read().pllrdy() {}
139
140 RCC.cfgr().modify(|w| {
141 w.set_ppre(Ppre::from_bits(ppre_bits));
142 w.set_hpre(Hpre::from_bits(hpre_bits));
143 w.set_sw(Sw::PLL1_P)
144 });
145 } else {
146 RCC.cfgr().modify(|w| {
147 w.set_ppre(Ppre::from_bits(ppre_bits));
148 w.set_hpre(Hpre::from_bits(hpre_bits));
149
150 if config.hse.is_some() {
151 w.set_sw(Sw::HSE);
152 } else if use_hsi48 {
153 #[cfg(not(stm32f0x0))]
154 w.set_sw(Sw::HSI48);
155 } else {
156 w.set_sw(Sw::HSI)
157 }
158 })
159 }
160
161 let rtc = config.ls.init();
162
163 set_freqs(Clocks {
164 sys: Hertz(real_sysclk),
165 pclk1: Hertz(pclk),
166 pclk2: Hertz(pclk),
167 pclk1_tim: Hertz(pclk * timer_mul),
168 pclk2_tim: Hertz(pclk * timer_mul),
169 hclk1: Hertz(hclk),
170 rtc,
171 });
172}
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
new file mode 100644
index 000000000..215f8a3d2
--- /dev/null
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -0,0 +1,456 @@
1use crate::pac::flash::vals::Latency;
2#[cfg(stm32f1)]
3pub use crate::pac::rcc::vals::Adcpre as ADCPrescaler;
4#[cfg(stm32f3)]
5pub use crate::pac::rcc::vals::Adcpres as AdcPllPrescaler;
6use crate::pac::rcc::vals::Pllsrc;
7#[cfg(stm32f1)]
8pub use crate::pac::rcc::vals::Pllxtpre as PllPreDiv;
9#[cfg(any(stm32f0, stm32f3))]
10pub use crate::pac::rcc::vals::Prediv as PllPreDiv;
11pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Sw as Sysclk};
12use crate::pac::{FLASH, RCC};
13use crate::time::Hertz;
14
15/// HSI speed
16pub const HSI_FREQ: Hertz = Hertz(8_000_000);
17
18#[derive(Clone, Copy, Eq, PartialEq)]
19pub enum HseMode {
20 /// crystal/ceramic oscillator (HSEBYP=0)
21 Oscillator,
22 /// external analog clock (low swing) (HSEBYP=1)
23 Bypass,
24}
25
26#[derive(Clone, Copy, Eq, PartialEq)]
27pub struct Hse {
28 /// HSE frequency.
29 pub freq: Hertz,
30 /// HSE mode.
31 pub mode: HseMode,
32}
33
34#[derive(Clone, Copy, Eq, PartialEq)]
35pub enum PllSource {
36 HSE,
37 HSI,
38 #[cfg(rcc_f0v4)]
39 HSI48,
40}
41
42#[derive(Clone, Copy)]
43pub struct Pll {
44 pub src: PllSource,
45
46 /// PLL pre-divider.
47 ///
48 /// On some chips, this must be 2 if `src == HSI`. Init will panic if this is not the case.
49 pub prediv: PllPreDiv,
50
51 /// PLL multiplication factor.
52 pub mul: PllMul,
53}
54
55#[cfg(all(stm32f3, not(rcc_f37)))]
56#[derive(Clone, Copy)]
57pub enum AdcClockSource {
58 Pll(AdcPllPrescaler),
59 Hclk(AdcHclkPrescaler),
60}
61
62#[cfg(all(stm32f3, not(rcc_f37)))]
63#[derive(Clone, Copy, PartialEq, Eq)]
64pub enum AdcHclkPrescaler {
65 Div1,
66 Div2,
67 Div4,
68}
69
70#[cfg(stm32f334)]
71#[derive(Clone, Copy, PartialEq, Eq)]
72pub enum HrtimClockSource {
73 BusClk,
74 PllClk,
75}
76
77/// Clocks configutation
78#[non_exhaustive]
79pub struct Config {
80 pub hsi: bool,
81 pub hse: Option<Hse>,
82 #[cfg(crs)]
83 pub hsi48: Option<super::Hsi48Config>,
84 pub sys: Sysclk,
85
86 pub pll: Option<Pll>,
87
88 pub ahb_pre: AHBPrescaler,
89 pub apb1_pre: APBPrescaler,
90 #[cfg(not(stm32f0))]
91 pub apb2_pre: APBPrescaler,
92
93 #[cfg(stm32f1)]
94 pub adc_pre: ADCPrescaler,
95
96 #[cfg(all(stm32f3, not(rcc_f37)))]
97 pub adc: AdcClockSource,
98 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
99 pub adc34: AdcClockSource,
100
101 /// Per-peripheral kernel clock selection muxes
102 pub mux: super::mux::ClockMux,
103
104 pub ls: super::LsConfig,
105}
106
107impl Default for Config {
108 fn default() -> Self {
109 Self {
110 hsi: true,
111 hse: None,
112 #[cfg(crs)]
113 hsi48: Some(Default::default()),
114 sys: Sysclk::HSI,
115 pll: None,
116 ahb_pre: AHBPrescaler::DIV1,
117 apb1_pre: APBPrescaler::DIV1,
118 #[cfg(not(stm32f0))]
119 apb2_pre: APBPrescaler::DIV1,
120 ls: Default::default(),
121
122 #[cfg(stm32f1)]
123 // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz)
124 adc_pre: ADCPrescaler::DIV6,
125
126 #[cfg(all(stm32f3, not(rcc_f37)))]
127 adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
128 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
129 adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
130
131 mux: Default::default(),
132 }
133 }
134}
135
136/// Initialize and Set the clock frequencies
137pub(crate) unsafe fn init(config: Config) {
138 // Configure HSI
139 let hsi = match config.hsi {
140 false => {
141 RCC.cr().modify(|w| w.set_hsion(false));
142 None
143 }
144 true => {
145 RCC.cr().modify(|w| w.set_hsion(true));
146 while !RCC.cr().read().hsirdy() {}
147 Some(HSI_FREQ)
148 }
149 };
150
151 // Configure HSE
152 let hse = match config.hse {
153 None => {
154 RCC.cr().modify(|w| w.set_hseon(false));
155 None
156 }
157 Some(hse) => {
158 match hse.mode {
159 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
160 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
161 }
162
163 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
164 RCC.cr().modify(|w| w.set_hseon(true));
165 while !RCC.cr().read().hserdy() {}
166 Some(hse.freq)
167 }
168 };
169
170 // configure HSI48
171 #[cfg(crs)]
172 let hsi48 = config.hsi48.map(|config| super::init_hsi48(config));
173 #[cfg(not(crs))]
174 let hsi48: Option<Hertz> = None;
175
176 // Enable PLL
177 let pll = config.pll.map(|pll| {
178 let (src_val, src_freq) = match pll.src {
179 #[cfg(any(rcc_f0v3, rcc_f0v4, rcc_f3v3))]
180 PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)),
181 #[cfg(not(any(rcc_f0v3, rcc_f0v4, rcc_f3v3)))]
182 PllSource::HSI => {
183 if pll.prediv != PllPreDiv::DIV2 {
184 panic!("if PLL source is HSI, PLL prediv must be 2.");
185 }
186 (Pllsrc::HSI_DIV2, unwrap!(hsi))
187 }
188 PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)),
189 #[cfg(rcc_f0v4)]
190 PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)),
191 };
192 let in_freq = src_freq / pll.prediv;
193 assert!(max::PLL_IN.contains(&in_freq));
194 let out_freq = in_freq * pll.mul;
195 assert!(max::PLL_OUT.contains(&out_freq));
196
197 #[cfg(not(stm32f1))]
198 RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv));
199 RCC.cfgr().modify(|w| {
200 w.set_pllmul(pll.mul);
201 w.set_pllsrc(src_val);
202 #[cfg(stm32f1)]
203 w.set_pllxtpre(pll.prediv);
204 });
205 RCC.cr().modify(|w| w.set_pllon(true));
206 while !RCC.cr().read().pllrdy() {}
207
208 out_freq
209 });
210
211 #[cfg(stm32f3)]
212 let pll_mul_2 = pll.map(|pll| pll * 2u32);
213
214 #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))]
215 let usb = match pll {
216 Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5),
217 Some(Hertz(48_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1),
218 _ => None,
219 }
220 .map(|usbpre| {
221 RCC.cfgr().modify(|w| w.set_usbpre(usbpre));
222 Hertz(48_000_000)
223 });
224
225 // Configure sysclk
226 let sys = match config.sys {
227 Sysclk::HSI => unwrap!(hsi),
228 Sysclk::HSE => unwrap!(hse),
229 Sysclk::PLL1_P => unwrap!(pll),
230 _ => unreachable!(),
231 };
232
233 let hclk = sys / config.ahb_pre;
234 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
235 #[cfg(not(stm32f0))]
236 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
237 #[cfg(stm32f0)]
238 let (pclk2, pclk2_tim) = (pclk1, pclk1_tim);
239
240 assert!(max::HCLK.contains(&hclk));
241 assert!(max::PCLK1.contains(&pclk1));
242 #[cfg(not(stm32f0))]
243 assert!(max::PCLK2.contains(&pclk2));
244
245 #[cfg(stm32f1)]
246 let adc = pclk2 / config.adc_pre;
247 #[cfg(stm32f1)]
248 assert!(max::ADC.contains(&adc));
249
250 // Set latency based on HCLK frquency
251 #[cfg(stm32f0)]
252 let latency = match hclk.0 {
253 ..=24_000_000 => Latency::WS0,
254 _ => Latency::WS1,
255 };
256 #[cfg(any(stm32f1, stm32f3))]
257 let latency = match hclk.0 {
258 ..=24_000_000 => Latency::WS0,
259 ..=48_000_000 => Latency::WS1,
260 _ => Latency::WS2,
261 };
262 FLASH.acr().modify(|w| {
263 w.set_latency(latency);
264 // RM0316: "The prefetch buffer must be kept on when using a prescaler
265 // different from 1 on the AHB clock.", "Half-cycle access cannot be
266 // used when there is a prescaler different from 1 on the AHB clock"
267 #[cfg(stm32f3)]
268 if config.ahb_pre != AHBPrescaler::DIV1 {
269 w.set_hlfcya(false);
270 w.set_prftbe(true);
271 }
272 #[cfg(not(stm32f3))]
273 w.set_prftbe(true);
274 });
275
276 // Set prescalers
277 // CFGR has been written before (PLL, PLL48) don't overwrite these settings
278 RCC.cfgr().modify(|w: &mut stm32_metapac::rcc::regs::Cfgr| {
279 #[cfg(not(stm32f0))]
280 {
281 w.set_ppre1(config.apb1_pre);
282 w.set_ppre2(config.apb2_pre);
283 }
284 #[cfg(stm32f0)]
285 w.set_ppre(config.apb1_pre);
286 w.set_hpre(config.ahb_pre);
287 #[cfg(stm32f1)]
288 w.set_adcpre(config.adc_pre);
289 });
290
291 // Wait for the new prescalers to kick in
292 // "The clocks are divided with the new prescaler factor from
293 // 1 to 16 AHB cycles after write"
294 cortex_m::asm::delay(16);
295
296 // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings
297 RCC.cfgr().modify(|w| w.set_sw(config.sys));
298 while RCC.cfgr().read().sws() != config.sys {}
299
300 let rtc = config.ls.init();
301
302 #[cfg(all(stm32f3, not(rcc_f37)))]
303 use crate::pac::adccommon::vals::Ckmode;
304
305 #[cfg(all(stm32f3, not(rcc_f37)))]
306 let adc = match config.adc {
307 AdcClockSource::Pll(adcpres) => {
308 RCC.cfgr2().modify(|w| w.set_adc12pres(adcpres));
309 crate::pac::ADC_COMMON
310 .ccr()
311 .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS));
312
313 unwrap!(pll) / adcpres
314 }
315 AdcClockSource::Hclk(adcpres) => {
316 assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1));
317
318 let (div, ckmode) = match adcpres {
319 AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1),
320 AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2),
321 AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4),
322 };
323 crate::pac::ADC_COMMON.ccr().modify(|w| w.set_ckmode(ckmode));
324
325 hclk / div
326 }
327 };
328
329 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
330 let adc34 = match config.adc34 {
331 AdcClockSource::Pll(adcpres) => {
332 RCC.cfgr2().modify(|w| w.set_adc34pres(adcpres));
333 crate::pac::ADC3_COMMON
334 .ccr()
335 .modify(|w| w.set_ckmode(Ckmode::ASYNCHRONOUS));
336
337 unwrap!(pll) / adcpres
338 }
339 AdcClockSource::Hclk(adcpres) => {
340 assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1));
341
342 let (div, ckmode) = match adcpres {
343 AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1),
344 AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2),
345 AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4),
346 };
347 crate::pac::ADC3_COMMON.ccr().modify(|w| w.set_ckmode(ckmode));
348
349 hclk / div
350 }
351 };
352
353 /*
354 TODO: Maybe add something like this to clock_mux? How can we autogenerate the data for this?
355 let hrtim = match config.hrtim {
356 // Must be configured after the bus is ready, otherwise it won't work
357 HrtimClockSource::BusClk => None,
358 HrtimClockSource::PllClk => {
359 use crate::pac::rcc::vals::Timsw;
360
361 // Make sure that we're using the PLL
362 let pll = unwrap!(pll);
363 assert!((pclk2 == pll) || (pclk2 * 2u32 == pll));
364
365 RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P));
366
367 Some(pll * 2u32)
368 }
369 };
370 */
371
372 config.mux.init();
373
374 set_clocks!(
375 hsi: hsi,
376 hse: hse,
377 pll1_p: pll,
378 #[cfg(stm32f3)]
379 pll1_p_mul_2: pll_mul_2,
380 hsi_div_244: hsi.map(|h| h / 244u32),
381 sys: Some(sys),
382 pclk1: Some(pclk1),
383 pclk2: Some(pclk2),
384 pclk1_tim: Some(pclk1_tim),
385 pclk2_tim: Some(pclk2_tim),
386 hclk1: Some(hclk),
387 #[cfg(all(stm32f3, not(rcc_f37)))]
388 adc: Some(adc),
389 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
390 adc34: Some(adc34),
391 rtc: rtc,
392 hsi48: hsi48,
393 #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))]
394 usb: usb,
395 lse: None,
396 );
397}
398
399#[cfg(stm32f0)]
400mod max {
401 use core::ops::RangeInclusive;
402
403 use crate::time::Hertz;
404
405 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(32_000_000);
406 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(32_000_000);
407
408 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
409 pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
410
411 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(24_000_000);
412 pub(crate) const PLL_OUT: RangeInclusive<Hertz> = Hertz(16_000_000)..=Hertz(48_000_000);
413}
414
415#[cfg(stm32f1)]
416mod max {
417 use core::ops::RangeInclusive;
418
419 use crate::time::Hertz;
420
421 #[cfg(not(rcc_f1cl))]
422 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(16_000_000);
423 #[cfg(not(rcc_f1cl))]
424 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(25_000_000);
425
426 #[cfg(rcc_f1cl)]
427 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(3_000_000)..=Hertz(25_000_000);
428 #[cfg(rcc_f1cl)]
429 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000);
430
431 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000);
432 pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(36_000_000);
433 pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000);
434
435 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(25_000_000);
436 pub(crate) const PLL_OUT: RangeInclusive<Hertz> = Hertz(16_000_000)..=Hertz(72_000_000);
437
438 pub(crate) const ADC: RangeInclusive<Hertz> = Hertz(0)..=Hertz(14_000_000);
439}
440
441#[cfg(stm32f3)]
442mod max {
443 use core::ops::RangeInclusive;
444
445 use crate::time::Hertz;
446
447 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(32_000_000);
448 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(32_000_000);
449
450 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000);
451 pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(36_000_000);
452 pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000);
453
454 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(24_000_000);
455 pub(crate) const PLL_OUT: RangeInclusive<Hertz> = Hertz(16_000_000)..=Hertz(72_000_000);
456}
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
deleted file mode 100644
index 169551e45..000000000
--- a/embassy-stm32/src/rcc/f1.rs
+++ /dev/null
@@ -1,192 +0,0 @@
1use core::convert::TryFrom;
2
3use super::{set_freqs, Clocks};
4use crate::pac::flash::vals::Latency;
5use crate::pac::rcc::vals::*;
6use crate::pac::{FLASH, RCC};
7use crate::time::Hertz;
8
9/// HSI speed
10pub const HSI_FREQ: Hertz = Hertz(8_000_000);
11
12/// Configuration of the clocks
13///
14#[non_exhaustive]
15#[derive(Default)]
16pub struct Config {
17 pub hse: Option<Hertz>,
18
19 pub sys_ck: Option<Hertz>,
20 pub hclk: Option<Hertz>,
21 pub pclk1: Option<Hertz>,
22 pub pclk2: Option<Hertz>,
23 pub adcclk: Option<Hertz>,
24 pub pllxtpre: bool,
25
26 pub ls: super::LsConfig,
27}
28
29pub(crate) unsafe fn init(config: Config) {
30 let pllxtpre_div = if config.pllxtpre { 2 } else { 1 };
31 let pllsrcclk = config.hse.map(|hse| hse.0 / pllxtpre_div).unwrap_or(HSI_FREQ.0 / 2);
32
33 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
34 let pllmul = sysclk / pllsrcclk;
35
36 let (pllmul_bits, real_sysclk) = if pllmul == 1 {
37 (None, config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0))
38 } else {
39 let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
40 (Some(pllmul as u8 - 2), pllsrcclk * pllmul)
41 };
42
43 assert!(real_sysclk <= 72_000_000);
44
45 let hpre_bits = config
46 .hclk
47 .map(|hclk| match real_sysclk / hclk.0 {
48 0 => unreachable!(),
49 1 => 0b0111,
50 2 => 0b1000,
51 3..=5 => 0b1001,
52 6..=11 => 0b1010,
53 12..=39 => 0b1011,
54 40..=95 => 0b1100,
55 96..=191 => 0b1101,
56 192..=383 => 0b1110,
57 _ => 0b1111,
58 })
59 .unwrap_or(0b0111);
60
61 let hclk = if hpre_bits >= 0b1100 {
62 real_sysclk / (1 << (hpre_bits - 0b0110))
63 } else {
64 real_sysclk / (1 << (hpre_bits - 0b0111))
65 };
66
67 assert!(hclk <= 72_000_000);
68
69 let ppre1_bits = config
70 .pclk1
71 .map(|pclk1| match hclk / pclk1.0 {
72 0 => unreachable!(),
73 1 => 0b011,
74 2 => 0b100,
75 3..=5 => 0b101,
76 6..=11 => 0b110,
77 _ => 0b111,
78 })
79 .unwrap_or(0b011);
80
81 let ppre1 = 1 << (ppre1_bits - 0b011);
82 let pclk1 = hclk / u32::try_from(ppre1).unwrap();
83 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
84
85 assert!(pclk1 <= 36_000_000);
86
87 let ppre2_bits = config
88 .pclk2
89 .map(|pclk2| match hclk / pclk2.0 {
90 0 => unreachable!(),
91 1 => 0b011,
92 2 => 0b100,
93 3..=5 => 0b101,
94 6..=11 => 0b110,
95 _ => 0b111,
96 })
97 .unwrap_or(0b011);
98
99 let ppre2 = 1 << (ppre2_bits - 0b011);
100 let pclk2 = hclk / u32::try_from(ppre2).unwrap();
101 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
102
103 assert!(pclk2 <= 72_000_000);
104
105 FLASH.acr().write(|w| {
106 w.set_latency(if real_sysclk <= 24_000_000 {
107 Latency::WS0
108 } else if real_sysclk <= 48_000_000 {
109 Latency::WS1
110 } else {
111 Latency::WS2
112 });
113 // the prefetch buffer is enabled by default, let's keep it enabled
114 w.set_prftbe(true);
115 });
116
117 // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
118 // PLL output frequency is a supported one.
119 // usbpre == false: divide clock by 1.5, otherwise no division
120 #[cfg(not(rcc_f100))]
121 let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) {
122 (Some(_), Some(_), 72_000_000) => (false, true),
123 (Some(_), Some(_), 48_000_000) => (true, true),
124 _ => (true, false),
125 };
126
127 let apre_bits: u8 = config
128 .adcclk
129 .map(|adcclk| match pclk2 / adcclk.0 {
130 0..=2 => 0b00,
131 3..=4 => 0b01,
132 5..=7 => 0b10,
133 _ => 0b11,
134 })
135 .unwrap_or(0b11);
136
137 let apre = (apre_bits + 1) << 1;
138 let adcclk = pclk2 / unwrap!(u32::try_from(apre));
139
140 assert!(adcclk <= 14_000_000);
141
142 if config.hse.is_some() {
143 // enable HSE and wait for it to be ready
144 RCC.cr().modify(|w| w.set_hseon(true));
145 while !RCC.cr().read().hserdy() {}
146 }
147
148 if let Some(pllmul_bits) = pllmul_bits {
149 let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 };
150 RCC.cfgr()
151 .modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag)));
152
153 // enable PLL and wait for it to be ready
154 RCC.cfgr().modify(|w| {
155 w.set_pllmul(Pllmul::from_bits(pllmul_bits));
156 w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8));
157 });
158
159 RCC.cr().modify(|w| w.set_pllon(true));
160 while !RCC.cr().read().pllrdy() {}
161 }
162
163 // Only needed for stm32f103?
164 RCC.cfgr().modify(|w| {
165 w.set_adcpre(Adcpre::from_bits(apre_bits));
166 w.set_ppre2(Ppre::from_bits(ppre2_bits));
167 w.set_ppre1(Ppre::from_bits(ppre1_bits));
168 w.set_hpre(Hpre::from_bits(hpre_bits));
169 #[cfg(not(rcc_f100))]
170 w.set_usbpre(Usbpre::from_bits(usbpre as u8));
171 w.set_sw(if pllmul_bits.is_some() {
172 Sw::PLL1_P
173 } else if config.hse.is_some() {
174 Sw::HSE
175 } else {
176 Sw::HSI
177 });
178 });
179
180 let rtc = config.ls.init();
181
182 set_freqs(Clocks {
183 sys: Hertz(real_sysclk),
184 pclk1: Hertz(pclk1),
185 pclk2: Hertz(pclk2),
186 pclk1_tim: Hertz(pclk1 * timer_mul1),
187 pclk2_tim: Hertz(pclk2 * timer_mul2),
188 hclk1: Hertz(hclk),
189 adc: Some(Hertz(adcclk)),
190 rtc,
191 });
192}
diff --git a/embassy-stm32/src/rcc/f.rs b/embassy-stm32/src/rcc/f247.rs
index 36d9f178f..7b252870c 100644
--- a/embassy-stm32/src/rcc/f.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{
7#[cfg(any(stm32f4, stm32f7))] 7#[cfg(any(stm32f4, stm32f7))]
8use crate::pac::PWR; 8use crate::pac::PWR;
9use crate::pac::{FLASH, RCC}; 9use crate::pac::{FLASH, RCC};
10use crate::rcc::{set_freqs, Clocks};
11use crate::time::Hertz; 10use crate::time::Hertz;
12 11
13// TODO: on some F4s, PLLM is shared between all PLLs. Enforce that. 12// TODO: on some F4s, PLLM is shared between all PLLs. Enforce that.
@@ -96,6 +95,9 @@ pub struct Config {
96 95
97 pub ls: super::LsConfig, 96 pub ls: super::LsConfig,
98 97
98 /// Per-peripheral kernel clock selection muxes
99 pub mux: super::mux::ClockMux,
100
99 #[cfg(stm32f2)] 101 #[cfg(stm32f2)]
100 pub voltage: VoltageScale, 102 pub voltage: VoltageScale,
101} 103}
@@ -121,6 +123,7 @@ impl Default for Config {
121 123
122 #[cfg(stm32f2)] 124 #[cfg(stm32f2)]
123 voltage: VoltageScale::Range3, 125 voltage: VoltageScale::Range3,
126 mux: Default::default(),
124 } 127 }
125 } 128 }
126} 129}
@@ -183,9 +186,9 @@ pub(crate) unsafe fn init(config: Config) {
183 }; 186 };
184 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); 187 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
185 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] 188 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
186 let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); 189 let plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
187 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] 190 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
188 let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); 191 let pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
189 192
190 // Configure sysclk 193 // Configure sysclk
191 let sys = match config.sys { 194 let sys = match config.sys {
@@ -257,27 +260,46 @@ pub(crate) unsafe fn init(config: Config) {
257 }); 260 });
258 while RCC.cfgr().read().sws() != config.sys {} 261 while RCC.cfgr().read().sws() != config.sys {}
259 262
260 set_freqs(Clocks { 263 config.mux.init();
261 sys, 264
262 hclk1: hclk, 265 set_clocks!(
263 hclk2: hclk, 266 hsi: hsi,
264 hclk3: hclk, 267 hse: hse,
265 pclk1, 268 lse: None, // TODO
266 pclk2, 269 lsi: None, // TODO
267 pclk1_tim, 270 sys: Some(sys),
268 pclk2_tim, 271 hclk1: Some(hclk),
269 rtc, 272 hclk2: Some(hclk),
273 hclk3: Some(hclk),
274 pclk1: Some(pclk1),
275 pclk2: Some(pclk2),
276 pclk1_tim: Some(pclk1_tim),
277 pclk2_tim: Some(pclk2_tim),
278 rtc: rtc,
270 pll1_q: pll.q, 279 pll1_q: pll.q,
271 #[cfg(all(rcc_f4, not(stm32f410)))] 280
272 plli2s1_q: _plli2s.q, 281 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
273 #[cfg(all(rcc_f4, not(stm32f410)))] 282 plli2s1_p: plli2s.p,
274 plli2s1_r: _plli2s.r, 283 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
275 284 plli2s1_q: plli2s.q,
276 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] 285 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
277 pllsai1_q: _pllsai.q, 286 plli2s1_r: plli2s.r,
278 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] 287
279 pllsai1_r: _pllsai.r, 288 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
280 }); 289 pllsai1_p: pllsai.p,
290 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
291 pllsai1_q: pllsai.q,
292 #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
293 pllsai1_r: pllsai.r,
294
295 // TODO workaround until f4 rcc is fixed in stm32-data
296 #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))]
297 pllsai1_q: None,
298
299 hsi_div488: hsi.map(|hsi| hsi/488u32),
300 hsi_hse: None,
301 afif: None,
302 );
281} 303}
282 304
283struct PllInput { 305struct PllInput {
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs
deleted file mode 100644
index bf035fd25..000000000
--- a/embassy-stm32/src/rcc/f3.rs
+++ /dev/null
@@ -1,459 +0,0 @@
1#[cfg(rcc_f3)]
2use crate::pac::adccommon::vals::Ckmode;
3use crate::pac::flash::vals::Latency;
4pub use crate::pac::rcc::vals::Adcpres;
5use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
6use crate::pac::{FLASH, RCC};
7use crate::rcc::{set_freqs, Clocks};
8use crate::time::Hertz;
9
10/// HSI speed
11pub const HSI_FREQ: Hertz = Hertz(8_000_000);
12
13#[cfg(rcc_f3)]
14impl From<AdcClockSource> for Ckmode {
15 fn from(value: AdcClockSource) -> Self {
16 match value {
17 AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1,
18 AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2,
19 AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4,
20 _ => unreachable!(),
21 }
22 }
23}
24
25#[derive(Clone, Copy)]
26pub enum AdcClockSource {
27 Pll(Adcpres),
28 BusDiv1,
29 BusDiv2,
30 BusDiv4,
31}
32
33impl AdcClockSource {
34 pub fn bus_div(&self) -> u32 {
35 match self {
36 Self::BusDiv1 => 1,
37 Self::BusDiv2 => 2,
38 Self::BusDiv4 => 4,
39 _ => unreachable!(),
40 }
41 }
42}
43
44#[derive(Default)]
45pub enum HrtimClockSource {
46 #[default]
47 BusClk,
48 PllClk,
49}
50
51/// Clocks configutation
52#[non_exhaustive]
53#[derive(Default)]
54pub struct Config {
55 /// Frequency of HSE oscillator
56 /// 4MHz to 32MHz
57 pub hse: Option<Hertz>,
58 /// Bypass HSE for an external clock
59 pub bypass_hse: bool,
60 /// Frequency of the System Clock
61 pub sysclk: Option<Hertz>,
62 /// Frequency of AHB bus
63 pub hclk: Option<Hertz>,
64 /// Frequency of APB1 bus
65 /// - Max frequency 36MHz
66 pub pclk1: Option<Hertz>,
67 /// Frequency of APB2 bus
68 /// - Max frequency with HSE is 72MHz
69 /// - Max frequency without HSE is 64MHz
70 pub pclk2: Option<Hertz>,
71 /// USB clock setup
72 /// It is valid only when,
73 /// - HSE is enabled,
74 /// - The System clock frequency is either 48MHz or 72MHz
75 /// - APB1 clock has a minimum frequency of 10MHz
76 pub pll48: bool,
77 #[cfg(rcc_f3)]
78 /// ADC clock setup
79 /// - For AHB, a psc of 4 or less must be used
80 pub adc: Option<AdcClockSource>,
81 #[cfg(rcc_f3)]
82 /// ADC clock setup
83 /// - For AHB, a psc of 4 or less must be used
84 pub adc34: Option<AdcClockSource>,
85 #[cfg(stm32f334)]
86 pub hrtim: HrtimClockSource,
87 pub ls: super::LsConfig,
88}
89
90// Information required to setup the PLL clock
91#[derive(Clone, Copy)]
92struct PllConfig {
93 pll_src: Pllsrc,
94 pll_mul: Pllmul,
95 pll_div: Option<Prediv>,
96}
97
98/// Initialize and Set the clock frequencies
99pub(crate) unsafe fn init(config: Config) {
100 // Calculate the real System clock, and PLL configuration if applicable
101 let (sysclk, pll_config) = get_sysclk(&config);
102 assert!(sysclk.0 <= 72_000_000);
103
104 // Calculate real AHB clock
105 let hclk = config.hclk.map(|h| h).unwrap_or(sysclk);
106 let hpre = match sysclk.0 / hclk.0 {
107 0 => unreachable!(),
108 1 => Hpre::DIV1,
109 2 => Hpre::DIV2,
110 3..=5 => Hpre::DIV4,
111 6..=11 => Hpre::DIV8,
112 12..=39 => Hpre::DIV16,
113 40..=95 => Hpre::DIV64,
114 96..=191 => Hpre::DIV128,
115 192..=383 => Hpre::DIV256,
116 _ => Hpre::DIV512,
117 };
118 let hclk = sysclk / hpre;
119 assert!(hclk <= Hertz(72_000_000));
120
121 // Calculate real APB1 clock
122 let pclk1 = config.pclk1.unwrap_or(hclk);
123 let ppre1 = match hclk / pclk1 {
124 0 => unreachable!(),
125 1 => Ppre::DIV1,
126 2 => Ppre::DIV2,
127 3..=5 => Ppre::DIV4,
128 6..=11 => Ppre::DIV8,
129 _ => Ppre::DIV16,
130 };
131 let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 };
132 let pclk1 = hclk / ppre1;
133 assert!(pclk1 <= Hertz(36_000_000));
134
135 // Calculate real APB2 clock
136 let pclk2 = config.pclk2.unwrap_or(hclk);
137 let ppre2 = match hclk / pclk2 {
138 0 => unreachable!(),
139 1 => Ppre::DIV1,
140 2 => Ppre::DIV2,
141 3..=5 => Ppre::DIV4,
142 6..=11 => Ppre::DIV8,
143 _ => Ppre::DIV16,
144 };
145 let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 };
146 let pclk2 = hclk / ppre2;
147 assert!(pclk2 <= Hertz(72_000_000));
148
149 // Set latency based on HCLK frquency
150 // RM0316: "The prefetch buffer must be kept on when using a prescaler
151 // different from 1 on the AHB clock.", "Half-cycle access cannot be
152 // used when there is a prescaler different from 1 on the AHB clock"
153 FLASH.acr().modify(|w| {
154 w.set_latency(if hclk <= Hertz(24_000_000) {
155 Latency::WS0
156 } else if hclk <= Hertz(48_000_000) {
157 Latency::WS1
158 } else {
159 Latency::WS2
160 });
161 if hpre != Hpre::DIV1 {
162 w.set_hlfcya(false);
163 w.set_prftbe(true);
164 }
165 });
166
167 // Enable HSE
168 // RM0316: "Bits 31:26 Reserved, must be kept at reset value."
169 if config.hse.is_some() {
170 RCC.cr().modify(|w| {
171 w.set_hsebyp(config.bypass_hse);
172 // We turn on clock security to switch to HSI when HSE fails
173 w.set_csson(true);
174 w.set_hseon(true);
175 });
176 while !RCC.cr().read().hserdy() {}
177 }
178
179 // Enable PLL
180 // RM0316: "Reserved, must be kept at reset value."
181 if let Some(ref pll_config) = pll_config {
182 RCC.cfgr().modify(|w| {
183 w.set_pllmul(pll_config.pll_mul);
184 w.set_pllsrc(pll_config.pll_src);
185 });
186 if let Some(pll_div) = pll_config.pll_div {
187 RCC.cfgr2().modify(|w| w.set_prediv(pll_div));
188 }
189 RCC.cr().modify(|w| w.set_pllon(true));
190 while !RCC.cr().read().pllrdy() {}
191 }
192
193 // CFGR has been written before (PLL) don't overwrite these settings
194 if config.pll48 {
195 let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config);
196 RCC.cfgr().modify(|w| {
197 w.set_usbpre(usb_pre);
198 });
199 }
200
201 // Set prescalers
202 // CFGR has been written before (PLL, PLL48) don't overwrite these settings
203 RCC.cfgr().modify(|w| {
204 w.set_ppre2(ppre2);
205 w.set_ppre1(ppre1);
206 w.set_hpre(hpre);
207 });
208
209 // Wait for the new prescalers to kick in
210 // "The clocks are divided with the new prescaler factor from
211 // 1 to 16 AHB cycles after write"
212 cortex_m::asm::delay(16);
213
214 // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings
215 RCC.cfgr().modify(|w| {
216 w.set_sw(match (pll_config, config.hse) {
217 (Some(_), _) => Sw::PLL1_P,
218 (None, Some(_)) => Sw::HSE,
219 (None, None) => Sw::HSI,
220 })
221 });
222
223 #[cfg(rcc_f3)]
224 let adc = config.adc.map(|adc| match adc {
225 AdcClockSource::Pll(adcpres) => {
226 RCC.cfgr2().modify(|w| {
227 // Make sure that we're using the PLL
228 pll_config.unwrap();
229 w.set_adc12pres(adcpres);
230
231 sysclk / adcpres
232 })
233 }
234 _ => crate::pac::ADC_COMMON.ccr().modify(|w| {
235 assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
236
237 w.set_ckmode(adc.into());
238
239 sysclk / adc.bus_div()
240 }),
241 });
242
243 #[cfg(all(rcc_f3, adc3_common))]
244 let adc34 = config.adc34.map(|adc| match adc {
245 AdcClockSource::Pll(adcpres) => {
246 RCC.cfgr2().modify(|w| {
247 // Make sure that we're using the PLL
248 pll_config.unwrap();
249 w.set_adc34pres(adcpres);
250
251 sysclk / adcpres
252 })
253 }
254 _ => crate::pac::ADC_COMMON.ccr().modify(|w| {
255 assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
256
257 w.set_ckmode(adc.into());
258
259 sysclk / adc.bus_div()
260 }),
261 });
262
263 #[cfg(stm32f334)]
264 let hrtim = match config.hrtim {
265 // Must be configured after the bus is ready, otherwise it won't work
266 HrtimClockSource::BusClk => None,
267 HrtimClockSource::PllClk => {
268 use crate::pac::rcc::vals::Timsw;
269
270 // Make sure that we're using the PLL
271 pll_config.unwrap();
272 assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk));
273
274 RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P));
275
276 Some(sysclk * 2u32)
277 }
278 };
279
280 let rtc = config.ls.init();
281
282 set_freqs(Clocks {
283 sys: sysclk,
284 pclk1: pclk1,
285 pclk2: pclk2,
286 pclk1_tim: pclk1 * timer_mul1,
287 pclk2_tim: pclk2 * timer_mul2,
288 hclk1: hclk,
289 #[cfg(rcc_f3)]
290 adc: adc,
291 #[cfg(all(rcc_f3, adc3_common))]
292 adc34: adc34,
293 #[cfg(all(rcc_f3, not(adc3_common)))]
294 adc34: None,
295 #[cfg(stm32f334)]
296 hrtim: hrtim,
297 rtc,
298 });
299}
300
301#[inline]
302fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) {
303 match (config.sysclk, config.hse) {
304 (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None),
305 (Some(sysclk), None) if sysclk == HSI_FREQ => (HSI_FREQ, None),
306 // If the user selected System clock is different from HSI or HSE
307 // we will have to setup PLL clock source
308 (Some(sysclk), _) => {
309 let (sysclk, pll_config) = calc_pll(config, sysclk);
310 (sysclk, Some(pll_config))
311 }
312 (None, Some(hse)) => (hse, None),
313 (None, None) => (HSI_FREQ, None),
314 }
315}
316
317#[inline]
318fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
319 // Calculates the Multiplier and the Divisor to arrive at
320 // the required System clock from PLL source frequency
321 let get_mul_div = |sysclk, pllsrcclk| {
322 let bus_div = gcd(sysclk, pllsrcclk);
323 let mut multiplier = sysclk / bus_div;
324 let mut divisor = pllsrcclk / bus_div;
325 // Minimum PLL multiplier is two
326 if multiplier == 1 {
327 multiplier *= 2;
328 divisor *= 2;
329 }
330 assert!(multiplier <= 16);
331 assert!(divisor <= 16);
332 (multiplier, divisor)
333 };
334 // Based on the source of Pll, we calculate the actual system clock
335 // frequency, PLL's source identifier, multiplier and divisor
336 let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse {
337 Some(Hertz(hse)) => {
338 let (multiplier, divisor) = get_mul_div(sysclk, hse);
339 (
340 Hertz((hse / divisor) * multiplier),
341 Pllsrc::HSE_DIV_PREDIV,
342 into_pll_mul(multiplier),
343 Some(into_pre_div(divisor)),
344 )
345 }
346 None => {
347 cfg_if::cfg_if! {
348 // For some chips PREDIV is always two, and cannot be changed
349 if #[cfg(any(flashsize_d, flashsize_e))] {
350 let (multiplier, divisor) = get_mul_div(sysclk, HSI_FREQ.0);
351 (
352 Hertz((HSI_FREQ.0 / divisor) * multiplier),
353 Pllsrc::HSI_DIV_PREDIV,
354 into_pll_mul(multiplier),
355 Some(into_pre_div(divisor)),
356 )
357 } else {
358 let pllsrcclk = HSI_FREQ.0 / 2;
359 let multiplier = sysclk / pllsrcclk;
360 assert!(multiplier <= 16);
361 (
362 Hertz(pllsrcclk * multiplier),
363 Pllsrc::HSI_DIV2,
364 into_pll_mul(multiplier),
365 None,
366 )
367 }
368 }
369 }
370 };
371 (
372 act_sysclk,
373 PllConfig {
374 pll_src,
375 pll_mul,
376 pll_div,
377 },
378 )
379}
380
381#[inline]
382#[allow(unused_variables)]
383fn get_usb_pre(config: &Config, sysclk: Hertz, pclk1: Hertz, pll_config: &Option<PllConfig>) -> Usbpre {
384 cfg_if::cfg_if! {
385 // Some chips do not have USB
386 if #[cfg(any(stm32f301, stm32f318, stm32f334))] {
387 panic!("USB clock not supported by the chip");
388 } else {
389 let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= Hertz(10_000_000));
390 match (usb_ok, sysclk) {
391 (true, Hertz(72_000_000)) => Usbpre::DIV1_5,
392 (true, Hertz(48_000_000)) => Usbpre::DIV1,
393 _ => panic!(
394 "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
395 ),
396 }
397 }
398 }
399}
400
401// This function assumes cases when multiplier is one and it
402// being greater than 16 is made impossible
403#[inline]
404fn into_pll_mul(multiplier: u32) -> Pllmul {
405 match multiplier {
406 2 => Pllmul::MUL2,
407 3 => Pllmul::MUL3,
408 4 => Pllmul::MUL4,
409 5 => Pllmul::MUL5,
410 6 => Pllmul::MUL6,
411 7 => Pllmul::MUL7,
412 8 => Pllmul::MUL8,
413 9 => Pllmul::MUL9,
414 10 => Pllmul::MUL10,
415 11 => Pllmul::MUL11,
416 12 => Pllmul::MUL12,
417 13 => Pllmul::MUL13,
418 14 => Pllmul::MUL14,
419 15 => Pllmul::MUL15,
420 16 => Pllmul::MUL16,
421 _ => unreachable!(),
422 }
423}
424
425// This function assumes the incoming divisor cannot be greater
426// than 16
427#[inline]
428fn into_pre_div(divisor: u32) -> Prediv {
429 match divisor {
430 1 => Prediv::DIV1,
431 2 => Prediv::DIV2,
432 3 => Prediv::DIV3,
433 4 => Prediv::DIV4,
434 5 => Prediv::DIV5,
435 6 => Prediv::DIV6,
436 7 => Prediv::DIV7,
437 8 => Prediv::DIV8,
438 9 => Prediv::DIV9,
439 10 => Prediv::DIV10,
440 11 => Prediv::DIV11,
441 12 => Prediv::DIV12,
442 13 => Prediv::DIV13,
443 14 => Prediv::DIV14,
444 15 => Prediv::DIV15,
445 16 => Prediv::DIV16,
446 _ => unreachable!(),
447 }
448}
449
450// Determine GCD using Euclidean algorithm
451#[inline]
452fn gcd(mut a: u32, mut b: u32) -> u32 {
453 while b != 0 {
454 let r = a % b;
455 a = b;
456 b = r;
457 }
458 a
459}
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index b38fe1dcc..ea4422ccc 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -1,15 +1,16 @@
1use crate::pac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2use crate::pac::rcc::vals::{self, Sw}; 2pub use crate::pac::pwr::vals::Vos as VoltageRange;
3pub use crate::pac::rcc::vals::{ 3pub use crate::pac::rcc::vals::{
4 Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler, 4 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
5 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
5}; 6};
6use crate::pac::{FLASH, PWR, RCC}; 7use crate::pac::{FLASH, PWR, RCC};
7use crate::rcc::{set_freqs, Clocks};
8use crate::time::Hertz; 8use crate::time::Hertz;
9 9
10/// HSI speed 10/// HSI speed
11pub const HSI_FREQ: Hertz = Hertz(16_000_000); 11pub const HSI_FREQ: Hertz = Hertz(16_000_000);
12 12
13/// HSE Mode
13#[derive(Clone, Copy, Eq, PartialEq)] 14#[derive(Clone, Copy, Eq, PartialEq)]
14pub enum HseMode { 15pub enum HseMode {
15 /// crystal/ceramic oscillator (HSEBYP=0) 16 /// crystal/ceramic oscillator (HSEBYP=0)
@@ -18,353 +19,291 @@ pub enum HseMode {
18 Bypass, 19 Bypass,
19} 20}
20 21
21/// System clock mux source 22/// HSE Configuration
22#[derive(Clone, Copy)] 23#[derive(Clone, Copy, Eq, PartialEq)]
23pub enum ClockSrc { 24pub struct Hse {
24 HSE(Hertz, HseMode), 25 /// HSE frequency.
25 HSI(HSIPrescaler), 26 pub freq: Hertz,
26 PLL(PllConfig), 27 /// HSE mode.
27 LSI, 28 pub mode: HseMode,
28} 29}
29 30
30/// The PLL configuration. 31/// PLL Configuration
31/// 32///
32/// * `VCOCLK = source / m * n` 33/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
33/// * `PLLRCLK = VCOCLK / r` 34/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
34/// * `PLLQCLK = VCOCLK / q` 35/// frequency ranges for each of these settings.
35/// * `PLLPCLK = VCOCLK / p` 36pub struct Pll {
36#[derive(Clone, Copy)] 37 /// PLL Source clock selection.
37pub struct PllConfig {
38 /// The source from which the PLL receives a clock signal
39 pub source: PllSource, 38 pub source: PllSource,
40 /// The initial divisor of that clock signal
41 pub m: Pllm,
42 /// The PLL VCO multiplier, which must be in the range `8..=86`.
43 pub n: Plln,
44 /// The final divisor for `PLLRCLK` output which drives the system clock
45 pub r: Pllr,
46
47 /// The divisor for the `PLLQCLK` output, if desired
48 pub q: Option<Pllq>,
49
50 /// The divisor for the `PLLPCLK` output, if desired
51 pub p: Option<Pllp>,
52}
53 39
54impl Default for PllConfig { 40 /// PLL pre-divider
55 #[inline] 41 pub prediv: PllPreDiv,
56 fn default() -> PllConfig {
57 // HSI / 1 * 8 / 2 = 64 MHz
58 PllConfig {
59 source: PllSource::HSI,
60 m: Pllm::DIV1,
61 n: Plln::MUL8,
62 r: Pllr::DIV2,
63 q: None,
64 p: None,
65 }
66 }
67}
68 42
69#[derive(Clone, Copy, Eq, PartialEq)] 43 /// PLL multiplication factor for VCO
70pub enum PllSource { 44 pub mul: PllMul,
71 HSI, 45
72 HSE(Hertz, HseMode), 46 /// PLL division factor for P clock (ADC Clock)
73} 47 pub divp: Option<PllPDiv>,
74 48
75/// Sets the source for the 48MHz clock to the USB peripheral. 49 /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI)
76#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] 50 pub divq: Option<PllQDiv>,
77pub enum UsbSrc { 51
78 /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the 52 /// PLL division factor for R clock (SYSCLK)
79 /// oscillator to comply with the USB specification for oscillator tolerance. 53 pub divr: Option<PllRDiv>,
80 #[cfg(any(stm32g0b1, stm32g0c1))]
81 Hsi48(super::Hsi48Config),
82 /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The
83 /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
84 /// tolerance.
85 PllQ,
86 /// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply
87 /// with the USB specification for oscillator tolerance.
88 HSE,
89} 54}
90 55
91/// Clocks configutation 56/// Clocks configutation
57#[non_exhaustive]
92pub struct Config { 58pub struct Config {
93 pub mux: ClockSrc, 59 /// HSI Enable
60 pub hsi: bool,
61
62 /// HSE Configuration
63 pub hse: Option<Hse>,
64
65 /// System Clock Configuration
66 pub sys: Sysclk,
67
68 /// HSI48 Configuration
69 #[cfg(crs)]
70 pub hsi48: Option<super::Hsi48Config>,
71
72 /// PLL Configuration
73 pub pll: Option<Pll>,
74
75 /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration
76 /// MUST turn on the PLLR output.
94 pub ahb_pre: AHBPrescaler, 77 pub ahb_pre: AHBPrescaler,
95 pub apb_pre: APBPrescaler, 78 pub apb1_pre: APBPrescaler,
96 pub low_power_run: bool, 79
80 /// Low-Speed Clock Configuration
97 pub ls: super::LsConfig, 81 pub ls: super::LsConfig,
98 #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] 82
99 pub usb_src: Option<UsbSrc>, 83 pub low_power_run: bool,
84
85 pub voltage_range: VoltageRange,
86
87 /// Per-peripheral kernel clock selection muxes
88 pub mux: super::mux::ClockMux,
100} 89}
101 90
102impl Default for Config { 91impl Default for Config {
103 #[inline] 92 #[inline]
104 fn default() -> Config { 93 fn default() -> Config {
105 Config { 94 Config {
106 mux: ClockSrc::HSI(HSIPrescaler::DIV1), 95 hsi: true,
96 hse: None,
97 sys: Sysclk::HSI,
98 #[cfg(crs)]
99 hsi48: Some(Default::default()),
100 pll: None,
107 ahb_pre: AHBPrescaler::DIV1, 101 ahb_pre: AHBPrescaler::DIV1,
108 apb_pre: APBPrescaler::DIV1, 102 apb1_pre: APBPrescaler::DIV1,
109 low_power_run: false, 103 low_power_run: false,
110 ls: Default::default(), 104 ls: Default::default(),
111 #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] 105 voltage_range: VoltageRange::RANGE1,
112 usb_src: None, 106 mux: Default::default(),
113 } 107 }
114 } 108 }
115} 109}
116 110
117impl PllConfig { 111#[derive(Default)]
118 pub(crate) fn init(self) -> (Hertz, Option<Hertz>, Option<Hertz>) { 112pub struct PllFreq {
119 let (src, input_freq) = match self.source { 113 pub pll_p: Option<Hertz>,
120 PllSource::HSI => (vals::Pllsrc::HSI, HSI_FREQ), 114 pub pll_q: Option<Hertz>,
121 PllSource::HSE(freq, _) => (vals::Pllsrc::HSE, freq), 115 pub pll_r: Option<Hertz>,
122 };
123
124 let m_freq = input_freq / self.m;
125 // RM0454 § 5.4.4:
126 // > Caution: The software must set these bits so that the PLL input frequency after the
127 // > /M divider is between 2.66 and 16 MHz.
128 debug_assert!(m_freq.0 >= 2_660_000 && m_freq.0 <= 16_000_000);
129
130 let n_freq = m_freq * self.n as u32;
131 // RM0454 § 5.4.4:
132 // > Caution: The software must set these bits so that the VCO output frequency is between
133 // > 64 and 344 MHz.
134 debug_assert!(n_freq.0 >= 64_000_000 && n_freq.0 <= 344_000_000);
135
136 let r_freq = n_freq / self.r;
137 // RM0454 § 5.4.4:
138 // > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock.
139 debug_assert!(r_freq.0 <= 64_000_000);
140
141 let q_freq = self.q.map(|q| n_freq / q);
142 let p_freq = self.p.map(|p| n_freq / p);
143
144 // RM0454 § 5.2.3:
145 // > To modify the PLL configuration, proceed as follows:
146 // > 1. Disable the PLL by setting PLLON to 0 in Clock control register (RCC_CR).
147 RCC.cr().modify(|w| w.set_pllon(false));
148
149 // > 2. Wait until PLLRDY is cleared. The PLL is now fully stopped.
150 while RCC.cr().read().pllrdy() {}
151
152 // > 3. Change the desired parameter.
153 // Enable whichever clock source we're using, and wait for it to become ready
154 match self.source {
155 PllSource::HSI => {
156 RCC.cr().write(|w| w.set_hsion(true));
157 while !RCC.cr().read().hsirdy() {}
158 }
159 PllSource::HSE(_, mode) => {
160 RCC.cr().write(|w| {
161 w.set_hsebyp(mode != HseMode::Oscillator);
162 w.set_hseon(true);
163 });
164 while !RCC.cr().read().hserdy() {}
165 }
166 }
167
168 // Configure PLLCFGR
169 RCC.pllcfgr().modify(|w| {
170 w.set_pllr(self.r);
171 w.set_pllren(false);
172 w.set_pllq(self.q.unwrap_or(Pllq::DIV2));
173 w.set_pllqen(false);
174 w.set_pllp(self.p.unwrap_or(Pllp::DIV2));
175 w.set_pllpen(false);
176 w.set_plln(self.n);
177 w.set_pllm(self.m);
178 w.set_pllsrc(src)
179 });
180
181 // > 4. Enable the PLL again by setting PLLON to 1.
182 RCC.cr().modify(|w| w.set_pllon(true));
183
184 // Wait for the PLL to become ready
185 while !RCC.cr().read().pllrdy() {}
186
187 // > 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, and PLLREN in PLL
188 // > configuration register (RCC_PLLCFGR).
189 RCC.pllcfgr().modify(|w| {
190 // We'll use R for system clock, so enable that unconditionally
191 w.set_pllren(true);
192
193 // We may also use Q or P
194 w.set_pllqen(self.q.is_some());
195 w.set_pllpen(self.p.is_some());
196 });
197
198 (r_freq, q_freq, p_freq)
199 }
200} 116}
201 117
202pub(crate) unsafe fn init(config: Config) { 118pub(crate) unsafe fn init(config: Config) {
203 let mut pll1_q_freq = None; 119 // Configure HSI
204 let mut pll1_p_freq = None; 120 let hsi = match config.hsi {
205 121 false => {
206 let (sys_clk, sw) = match config.mux { 122 RCC.cr().modify(|w| w.set_hsion(false));
207 ClockSrc::HSI(div) => { 123 None
208 // Enable HSI 124 }
209 RCC.cr().write(|w| { 125 true => {
210 w.set_hsidiv(div); 126 RCC.cr().modify(|w| w.set_hsion(true));
211 w.set_hsion(true)
212 });
213 while !RCC.cr().read().hsirdy() {} 127 while !RCC.cr().read().hsirdy() {}
214 128 Some(HSI_FREQ)
215 (HSI_FREQ / div, Sw::HSI)
216 } 129 }
217 ClockSrc::HSE(freq, mode) => { 130 };
218 // Enable HSE
219 RCC.cr().write(|w| {
220 w.set_hseon(true);
221 w.set_hsebyp(mode != HseMode::Oscillator);
222 });
223 while !RCC.cr().read().hserdy() {}
224 131
225 (freq, Sw::HSE) 132 // Configure HSE
133 let hse = match config.hse {
134 None => {
135 RCC.cr().modify(|w| w.set_hseon(false));
136 None
226 } 137 }
227 ClockSrc::PLL(pll) => { 138 Some(hse) => {
228 let (r_freq, q_freq, p_freq) = pll.init(); 139 match hse.mode {
229 140 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
230 pll1_q_freq = q_freq; 141 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
231 pll1_p_freq = p_freq; 142 }
232 143
233 (r_freq, Sw::PLL1_R) 144 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
234 } 145 RCC.cr().modify(|w| w.set_hseon(true));
235 ClockSrc::LSI => { 146 while !RCC.cr().read().hserdy() {}
236 // Enable LSI 147 Some(hse.freq)
237 RCC.csr().write(|w| w.set_lsion(true));
238 while !RCC.csr().read().lsirdy() {}
239 (super::LSI_FREQ, Sw::LSI)
240 } 148 }
241 }; 149 };
242 150
243 // Determine the flash latency implied by the target clock speed 151 // Configure HSI48 if required
244 // RM0454 § 3.3.4: 152 #[cfg(crs)]
245 let target_flash_latency = if sys_clk.0 <= 24_000_000 { 153 let hsi48 = config.hsi48.map(super::init_hsi48);
246 Latency::WS0 154
247 } else if sys_clk.0 <= 48_000_000 { 155 let pll = config
248 Latency::WS1 156 .pll
249 } else { 157 .map(|pll_config| {
250 Latency::WS2 158 let src_freq = match pll_config.source {
251 }; 159 PllSource::HSI => unwrap!(hsi),
160 PllSource::HSE => unwrap!(hse),
161 _ => unreachable!(),
162 };
163
164 // Disable PLL before configuration
165 RCC.cr().modify(|w| w.set_pllon(false));
166 while RCC.cr().read().pllrdy() {}
167
168 let in_freq = src_freq / pll_config.prediv;
169 assert!(max::PLL_IN.contains(&in_freq));
170 let internal_freq = in_freq * pll_config.mul;
171
172 assert!(max::PLL_VCO.contains(&internal_freq));
173
174 RCC.pllcfgr().write(|w| {
175 w.set_plln(pll_config.mul);
176 w.set_pllm(pll_config.prediv);
177 w.set_pllsrc(pll_config.source.into());
178 });
252 179
253 // Increase the number of cycles we wait for flash if the new value is higher 180 let pll_p_freq = pll_config.divp.map(|div_p| {
254 // There's no harm in waiting a little too much before the clock change, but we'll 181 RCC.pllcfgr().modify(|w| {
255 // crash immediately if we don't wait enough after the clock change 182 w.set_pllp(div_p);
256 let mut set_flash_latency_after = false; 183 w.set_pllpen(true);
257 FLASH.acr().modify(|w| { 184 });
258 // Is the current flash latency less than what we need at the new SYSCLK? 185 let freq = internal_freq / div_p;
259 if w.latency().to_bits() <= target_flash_latency.to_bits() { 186 assert!(max::PLL_P.contains(&freq));
260 // We must increase the number of wait states now 187 freq
261 w.set_latency(target_flash_latency) 188 });
262 } else {
263 // We may decrease the number of wait states later
264 set_flash_latency_after = true;
265 }
266 189
267 // RM0454 § 3.3.5: 190 let pll_q_freq = pll_config.divq.map(|div_q| {
268 // > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register 191 RCC.pllcfgr().modify(|w| {
269 // > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the 192 w.set_pllq(div_q);
270 // > Flash memory. 193 w.set_pllqen(true);
271 // 194 });
272 // Enable flash prefetching if we have at least one wait state, and disable it otherwise. 195 let freq = internal_freq / div_q;
273 w.set_prften(target_flash_latency.to_bits() > 0); 196 assert!(max::PLL_Q.contains(&freq));
274 }); 197 freq
198 });
275 199
276 if !set_flash_latency_after { 200 let pll_r_freq = pll_config.divr.map(|div_r| {
277 // Spin until the effective flash latency is compatible with the clock change 201 RCC.pllcfgr().modify(|w| {
278 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} 202 w.set_pllr(div_r);
279 } 203 w.set_pllren(true);
204 });
205 let freq = internal_freq / div_r;
206 assert!(max::PLL_R.contains(&freq));
207 freq
208 });
280 209
281 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 210 // Enable the PLL
282 let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); 211 RCC.cr().modify(|w| w.set_pllon(true));
283 RCC.cfgr().modify(|w| { 212 while !RCC.cr().read().pllrdy() {}
284 w.set_sw(sw);
285 w.set_hpre(hpre);
286 w.set_ppre(ppre);
287 });
288 213
289 if set_flash_latency_after { 214 PllFreq {
290 // We can make the flash require fewer wait states 215 pll_p: pll_p_freq,
291 // Spin until the SYSCLK changes have taken effect 216 pll_q: pll_q_freq,
292 loop { 217 pll_r: pll_r_freq,
293 let cfgr = RCC.cfgr().read();
294 if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
295 break;
296 } 218 }
297 } 219 })
220 .unwrap_or_default();
221
222 let sys = match config.sys {
223 Sysclk::HSI => unwrap!(hsi),
224 Sysclk::HSE => unwrap!(hse),
225 Sysclk::PLL1_R => unwrap!(pll.pll_r),
226 _ => unreachable!(),
227 };
298 228
299 // Set the flash latency to require fewer wait states 229 assert!(max::SYSCLK.contains(&sys));
300 FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
301 }
302 230
303 let ahb_freq = sys_clk / config.ahb_pre; 231 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
232 let hclk = sys / config.ahb_pre;
233 assert!(max::HCLK.contains(&hclk));
304 234
305 let (apb_freq, apb_tim_freq) = match config.apb_pre { 235 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
306 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 236 assert!(max::PCLK.contains(&pclk1));
307 pre => { 237
308 let freq = ahb_freq / pre; 238 let latency = match (config.voltage_range, hclk.0) {
309 (freq, freq * 2u32) 239 (VoltageRange::RANGE1, ..=24_000_000) => Latency::WS0,
310 } 240 (VoltageRange::RANGE1, ..=48_000_000) => Latency::WS1,
241 (VoltageRange::RANGE1, _) => Latency::WS2,
242 (VoltageRange::RANGE2, ..=8_000_000) => Latency::WS0,
243 (VoltageRange::RANGE2, ..=16_000_000) => Latency::WS1,
244 (VoltageRange::RANGE2, _) => Latency::WS2,
245 _ => unreachable!(),
311 }; 246 };
312 247
248 // Configure flash read access latency based on voltage scale and frequency (RM0444 3.3.4)
249 FLASH.acr().modify(|w| {
250 w.set_latency(latency);
251 });
252
253 // Spin until the effective flash latency is set.
254 while FLASH.acr().read().latency() != latency {}
255
256 // Now that boost mode and flash read access latency are configured, set up SYSCLK
257 RCC.cfgr().modify(|w| {
258 w.set_sw(config.sys);
259 w.set_hpre(config.ahb_pre);
260 w.set_ppre(config.apb1_pre);
261 });
262
313 if config.low_power_run { 263 if config.low_power_run {
314 assert!(sys_clk.0 <= 2_000_000); 264 assert!(sys <= Hertz(2_000_000));
315 PWR.cr1().modify(|w| w.set_lpr(true)); 265 PWR.cr1().modify(|w| w.set_lpr(true));
316 } 266 }
317 267
318 let rtc = config.ls.init(); 268 let rtc = config.ls.init();
319 let lse_freq = config.ls.lse.map(|lse| lse.frequency); 269
320 270 config.mux.init();
321 let hsi_freq = (sw == Sw::HSI).then_some(HSI_FREQ); 271
322 let hsi_div_8_freq = hsi_freq.map(|f| f / 8u32); 272 set_clocks!(
323 let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ); 273 sys: Some(sys),
324 let hse_freq = (sw == Sw::HSE).then_some(sys_clk); 274 hclk1: Some(hclk),
325 275 pclk1: Some(pclk1),
326 #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))] 276 pclk1_tim: Some(pclk1_tim),
327 let hsi48_freq = config.usb_src.and_then(|config| { 277 pll1_p: pll.pll_p,
328 match config { 278 pll1_q: pll.pll_q,
329 UsbSrc::PllQ => { 279 pll1_r: pll.pll_r,
330 // Make sure the PLLQ is enabled and running at 48Mhz 280 hsi: hsi,
331 assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000); 281 hse: hse,
332 RCC.ccipr2() 282 #[cfg(crs)]
333 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q)); 283 hsi48: hsi48,
334 None 284 rtc: rtc,
335 } 285 hsi_div_8: hsi.map(|h| h / 8u32),
336 UsbSrc::HSE => { 286 hsi_div_488: hsi.map(|h| h / 488u32),
337 // Make sure the HSE is enabled and running at 48Mhz 287
338 assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000); 288 // TODO
339 RCC.ccipr2() 289 lsi: None,
340 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE)); 290 lse: None,
341 None 291 );
342 } 292}
343 #[cfg(any(stm32g0b1, stm32g0c1))] 293
344 UsbSrc::Hsi48(config) => { 294mod max {
345 let freq = super::init_hsi48(config); 295 use core::ops::RangeInclusive;
346 RCC.ccipr2() 296
347 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)); 297 use crate::time::Hertz;
348 Some(freq) 298
349 } 299 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(48_000_000);
350 } 300 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
351 }); 301 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(64_000_000);
352 #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))] 302 pub(crate) const PCLK: RangeInclusive<Hertz> = Hertz(8)..=Hertz(64_000_000);
353 let hsi48_freq: Option<Hertz> = None; 303 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(64_000_000);
354 304 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(2_660_000)..=Hertz(16_000_000);
355 set_freqs(Clocks { 305 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000);
356 sys: sys_clk, 306 pub(crate) const PLL_P: RangeInclusive<Hertz> = Hertz(3_090_000)..=Hertz(122_000_000);
357 hclk1: ahb_freq, 307 pub(crate) const PLL_Q: RangeInclusive<Hertz> = Hertz(12_000_000)..=Hertz(128_000_000);
358 pclk1: apb_freq, 308 pub(crate) const PLL_R: RangeInclusive<Hertz> = Hertz(12_000_000)..=Hertz(64_000_000);
359 pclk1_tim: apb_tim_freq,
360 hsi: hsi_freq,
361 hsi48: hsi48_freq,
362 hsi_div_8: hsi_div_8_freq,
363 hse: hse_freq,
364 lse: lse_freq,
365 lsi: lsi_freq,
366 pll1_q: pll1_q_freq,
367 pll1_p: pll1_p_freq,
368 rtc,
369 });
370} 309}
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index fca364c21..cd2d2a8a2 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,40 +1,30 @@
1use stm32_metapac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
3use stm32_metapac::FLASH;
4
5pub use crate::pac::rcc::vals::{ 2pub use crate::pac::rcc::vals::{
6 Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ, 3 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
7 Pllr as PllR, Ppre as APBPrescaler, 4 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
8}; 5};
9use crate::pac::{PWR, RCC}; 6use crate::pac::{FLASH, PWR, RCC};
10use crate::rcc::{set_freqs, Clocks};
11use crate::time::Hertz; 7use crate::time::Hertz;
12 8
13/// HSI speed 9/// HSI speed
14pub const HSI_FREQ: Hertz = Hertz(16_000_000); 10pub const HSI_FREQ: Hertz = Hertz(16_000_000);
15 11
16/// System clock mux source 12/// HSE Mode
17#[derive(Clone, Copy)] 13#[derive(Clone, Copy, Eq, PartialEq)]
18pub enum ClockSrc { 14pub enum HseMode {
19 HSE(Hertz), 15 /// crystal/ceramic oscillator (HSEBYP=0)
20 HSI, 16 Oscillator,
21 PLL, 17 /// external analog clock (low swing) (HSEBYP=1)
22} 18 Bypass,
23
24/// PLL clock input source
25#[derive(Clone, Copy, Debug)]
26pub enum PllSource {
27 HSI,
28 HSE(Hertz),
29} 19}
30 20
31impl Into<Pllsrc> for PllSource { 21/// HSE Configuration
32 fn into(self) -> Pllsrc { 22#[derive(Clone, Copy, Eq, PartialEq)]
33 match self { 23pub struct Hse {
34 PllSource::HSE(..) => Pllsrc::HSE, 24 /// HSE frequency.
35 PllSource::HSI => Pllsrc::HSI, 25 pub freq: Hertz,
36 } 26 /// HSE mode.
37 } 27 pub mode: HseMode,
38} 28}
39 29
40/// PLL Configuration 30/// PLL Configuration
@@ -47,68 +37,79 @@ pub struct Pll {
47 pub source: PllSource, 37 pub source: PllSource,
48 38
49 /// PLL pre-divider 39 /// PLL pre-divider
50 pub prediv_m: PllM, 40 pub prediv: PllPreDiv,
51 41
52 /// PLL multiplication factor for VCO 42 /// PLL multiplication factor for VCO
53 pub mul_n: PllN, 43 pub mul: PllMul,
54 44
55 /// PLL division factor for P clock (ADC Clock) 45 /// PLL division factor for P clock (ADC Clock)
56 pub div_p: Option<PllP>, 46 pub divp: Option<PllPDiv>,
57 47
58 /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI) 48 /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI)
59 pub div_q: Option<PllQ>, 49 pub divq: Option<PllQDiv>,
60 50
61 /// PLL division factor for R clock (SYSCLK) 51 /// PLL division factor for R clock (SYSCLK)
62 pub div_r: Option<PllR>, 52 pub divr: Option<PllRDiv>,
63}
64
65/// Sets the source for the 48MHz clock to the USB and RNG peripherals.
66pub enum Clock48MhzSrc {
67 /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
68 /// oscillator to comply with the USB specification for oscillator tolerance.
69 Hsi48(super::Hsi48Config),
70 /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
71 /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
72 /// tolerance.
73 PllQ,
74} 53}
75 54
76/// Clocks configutation 55/// Clocks configutation
56#[non_exhaustive]
77pub struct Config { 57pub struct Config {
78 pub mux: ClockSrc, 58 /// HSI Enable
59 pub hsi: bool,
60
61 /// HSE Configuration
62 pub hse: Option<Hse>,
63
64 /// System Clock Configuration
65 pub sys: Sysclk,
66
67 /// HSI48 Configuration
68 pub hsi48: Option<super::Hsi48Config>,
69
70 /// PLL Configuration
71 pub pll: Option<Pll>,
72
73 /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration
74 /// MUST turn on the PLLR output.
79 pub ahb_pre: AHBPrescaler, 75 pub ahb_pre: AHBPrescaler,
80 pub apb1_pre: APBPrescaler, 76 pub apb1_pre: APBPrescaler,
81 pub apb2_pre: APBPrescaler, 77 pub apb2_pre: APBPrescaler,
78
82 pub low_power_run: bool, 79 pub low_power_run: bool,
83 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
84 /// MUST turn on the PLLR output.
85 pub pll: Option<Pll>,
86 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
87 pub clock_48mhz_src: Option<Clock48MhzSrc>,
88 pub adc12_clock_source: AdcClockSource,
89 pub adc345_clock_source: AdcClockSource,
90 80
81 /// Low-Speed Clock Configuration
91 pub ls: super::LsConfig, 82 pub ls: super::LsConfig,
83
84 /// Enable range1 boost mode
85 /// Recommended when the SYSCLK frequency is greater than 150MHz.
86 pub boost: bool,
87
88 /// Per-peripheral kernel clock selection muxes
89 pub mux: super::mux::ClockMux,
92} 90}
93 91
94impl Default for Config { 92impl Default for Config {
95 #[inline] 93 #[inline]
96 fn default() -> Config { 94 fn default() -> Config {
97 Config { 95 Config {
98 mux: ClockSrc::HSI, 96 hsi: true,
97 hse: None,
98 sys: Sysclk::HSI,
99 hsi48: Some(Default::default()),
100 pll: None,
99 ahb_pre: AHBPrescaler::DIV1, 101 ahb_pre: AHBPrescaler::DIV1,
100 apb1_pre: APBPrescaler::DIV1, 102 apb1_pre: APBPrescaler::DIV1,
101 apb2_pre: APBPrescaler::DIV1, 103 apb2_pre: APBPrescaler::DIV1,
102 low_power_run: false, 104 low_power_run: false,
103 pll: None,
104 clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
105 adc12_clock_source: Adcsel::DISABLE,
106 adc345_clock_source: Adcsel::DISABLE,
107 ls: Default::default(), 105 ls: Default::default(),
106 boost: false,
107 mux: Default::default(),
108 } 108 }
109 } 109 }
110} 110}
111 111
112#[derive(Default)]
112pub struct PllFreq { 113pub struct PllFreq {
113 pub pll_p: Option<Hertz>, 114 pub pll_p: Option<Hertz>,
114 pub pll_q: Option<Hertz>, 115 pub pll_q: Option<Hertz>,
@@ -116,208 +117,233 @@ pub struct PllFreq {
116} 117}
117 118
118pub(crate) unsafe fn init(config: Config) { 119pub(crate) unsafe fn init(config: Config) {
119 let pll_freq = config.pll.map(|pll_config| { 120 // Configure HSI
120 let src_freq = match pll_config.source { 121 let hsi = match config.hsi {
121 PllSource::HSI => { 122 false => {
122 RCC.cr().write(|w| w.set_hsion(true)); 123 RCC.cr().modify(|w| w.set_hsion(false));
123 while !RCC.cr().read().hsirdy() {} 124 None
125 }
126 true => {
127 RCC.cr().modify(|w| w.set_hsion(true));
128 while !RCC.cr().read().hsirdy() {}
129 Some(HSI_FREQ)
130 }
131 };
124 132
125 HSI_FREQ 133 // Configure HSE
126 } 134 let hse = match config.hse {
127 PllSource::HSE(freq) => { 135 None => {
128 RCC.cr().write(|w| w.set_hseon(true)); 136 RCC.cr().modify(|w| w.set_hseon(false));
129 while !RCC.cr().read().hserdy() {} 137 None
130 freq 138 }
139 Some(hse) => {
140 match hse.mode {
141 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
142 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
131 } 143 }
132 };
133 144
134 // Disable PLL before configuration 145 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
135 RCC.cr().modify(|w| w.set_pllon(false)); 146 RCC.cr().modify(|w| w.set_hseon(true));
136 while RCC.cr().read().pllrdy() {} 147 while !RCC.cr().read().hserdy() {}
148 Some(hse.freq)
149 }
150 };
151
152 // Configure HSI48 if required
153 let hsi48 = config.hsi48.map(super::init_hsi48);
154
155 let pll = config
156 .pll
157 .map(|pll_config| {
158 let src_freq = match pll_config.source {
159 PllSource::HSI => unwrap!(hsi),
160 PllSource::HSE => unwrap!(hse),
161 _ => unreachable!(),
162 };
163
164 // Disable PLL before configuration
165 RCC.cr().modify(|w| w.set_pllon(false));
166 while RCC.cr().read().pllrdy() {}
137 167
138 let internal_freq = src_freq / pll_config.prediv_m * pll_config.mul_n; 168 let in_freq = src_freq / pll_config.prediv;
169 assert!(max::PLL_IN.contains(&in_freq));
170 let internal_freq = in_freq * pll_config.mul;
139 171
140 RCC.pllcfgr().write(|w| { 172 assert!(max::PLL_VCO.contains(&internal_freq));
141 w.set_plln(pll_config.mul_n);
142 w.set_pllm(pll_config.prediv_m);
143 w.set_pllsrc(pll_config.source.into());
144 });
145 173
146 let pll_p_freq = pll_config.div_p.map(|div_p| { 174 RCC.pllcfgr().write(|w| {
147 RCC.pllcfgr().modify(|w| { 175 w.set_plln(pll_config.mul);
148 w.set_pllp(div_p); 176 w.set_pllm(pll_config.prediv);
149 w.set_pllpen(true); 177 w.set_pllsrc(pll_config.source.into());
150 }); 178 });
151 internal_freq / div_p
152 });
153 179
154 let pll_q_freq = pll_config.div_q.map(|div_q| { 180 let pll_p_freq = pll_config.divp.map(|div_p| {
155 RCC.pllcfgr().modify(|w| { 181 RCC.pllcfgr().modify(|w| {
156 w.set_pllq(div_q); 182 w.set_pllp(div_p);
157 w.set_pllqen(true); 183 w.set_pllpen(true);
184 });
185 let freq = internal_freq / div_p;
186 assert!(max::PLL_P.contains(&freq));
187 freq
158 }); 188 });
159 internal_freq / div_q
160 });
161 189
162 let pll_r_freq = pll_config.div_r.map(|div_r| { 190 let pll_q_freq = pll_config.divq.map(|div_q| {
163 RCC.pllcfgr().modify(|w| { 191 RCC.pllcfgr().modify(|w| {
164 w.set_pllr(div_r); 192 w.set_pllq(div_q);
165 w.set_pllren(true); 193 w.set_pllqen(true);
194 });
195 let freq = internal_freq / div_q;
196 assert!(max::PLL_Q.contains(&freq));
197 freq
166 }); 198 });
167 internal_freq / div_r
168 });
169 199
170 // Enable the PLL 200 let pll_r_freq = pll_config.divr.map(|div_r| {
171 RCC.cr().modify(|w| w.set_pllon(true)); 201 RCC.pllcfgr().modify(|w| {
172 while !RCC.cr().read().pllrdy() {} 202 w.set_pllr(div_r);
203 w.set_pllren(true);
204 });
205 let freq = internal_freq / div_r;
206 assert!(max::PLL_R.contains(&freq));
207 freq
208 });
173 209
174 PllFreq { 210 // Enable the PLL
175 pll_p: pll_p_freq, 211 RCC.cr().modify(|w| w.set_pllon(true));
176 pll_q: pll_q_freq, 212 while !RCC.cr().read().pllrdy() {}
177 pll_r: pll_r_freq,
178 }
179 });
180 213
181 let (sys_clk, sw) = match config.mux { 214 PllFreq {
182 ClockSrc::HSI => { 215 pll_p: pll_p_freq,
183 // Enable HSI 216 pll_q: pll_q_freq,
184 RCC.cr().write(|w| w.set_hsion(true)); 217 pll_r: pll_r_freq,
185 while !RCC.cr().read().hsirdy() {} 218 }
219 })
220 .unwrap_or_default();
186 221
187 (HSI_FREQ, Sw::HSI) 222 let sys = match config.sys {
188 } 223 Sysclk::HSI => unwrap!(hsi),
189 ClockSrc::HSE(freq) => { 224 Sysclk::HSE => unwrap!(hse),
190 // Enable HSE 225 Sysclk::PLL1_R => unwrap!(pll.pll_r),
191 RCC.cr().write(|w| w.set_hseon(true)); 226 _ => unreachable!(),
192 while !RCC.cr().read().hserdy() {} 227 };
193 228
194 (freq, Sw::HSE) 229 assert!(max::SYSCLK.contains(&sys));
195 } 230
196 ClockSrc::PLL => { 231 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
197 assert!(pll_freq.is_some()); 232 let hclk = sys / config.ahb_pre;
198 assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); 233 assert!(max::HCLK.contains(&hclk));
199 234
200 let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; 235 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
201 236 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
202 assert!(freq <= 170_000_000); 237 assert!(max::PCLK.contains(&pclk2));
203 238 assert!(max::PCLK.contains(&pclk2));
204 if freq >= 150_000_000 { 239
205 // Enable Core Boost mode on freq >= 150Mhz ([RM0440] p234) 240 // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!)
206 PWR.cr5().modify(|w| w.set_r1mode(false)); 241 if config.boost {
207 // Set flash wait state in boost mode based on frequency ([RM0440] p191) 242 // RM0440 p235
208 if freq <= 36_000_000 { 243 // “The sequence to switch from Range1 normal mode to Range1 boost mode is:
209 FLASH.acr().modify(|w| w.set_latency(Latency::WS0)); 244 // 1. The system clock must be divided by 2 using the AHB prescaler before switching to a higher system frequency.
210 } else if freq <= 68_000_000 { 245 RCC.cfgr().modify(|w| w.set_hpre(AHBPrescaler::DIV2));
211 FLASH.acr().modify(|w| w.set_latency(Latency::WS1)); 246 // 2. Clear the R1MODE bit in the PWR_CR5 register. (enables boost mode)
212 } else if freq <= 102_000_000 { 247 PWR.cr5().modify(|w| w.set_r1mode(false));
213 FLASH.acr().modify(|w| w.set_latency(Latency::WS2)); 248
214 } else if freq <= 136_000_000 { 249 // Below:
215 FLASH.acr().modify(|w| w.set_latency(Latency::WS3)); 250 // 3. Adjust wait states according to new freq target
216 } else { 251 // 4. Configure and switch to new frequency
217 FLASH.acr().modify(|w| w.set_latency(Latency::WS4)); 252 }
218 }
219 } else {
220 PWR.cr5().modify(|w| w.set_r1mode(true));
221 // Set flash wait state in normal mode based on frequency ([RM0440] p191)
222 if freq <= 30_000_000 {
223 FLASH.acr().modify(|w| w.set_latency(Latency::WS0));
224 } else if freq <= 60_000_000 {
225 FLASH.acr().modify(|w| w.set_latency(Latency::WS1));
226 } else if freq <= 80_000_000 {
227 FLASH.acr().modify(|w| w.set_latency(Latency::WS2));
228 } else if freq <= 120_000_000 {
229 FLASH.acr().modify(|w| w.set_latency(Latency::WS3));
230 } else {
231 FLASH.acr().modify(|w| w.set_latency(Latency::WS4));
232 }
233 }
234 253
235 (Hertz(freq), Sw::PLL1_R) 254 let latency = match (config.boost, hclk.0) {
236 } 255 (true, ..=34_000_000) => Latency::WS0,
256 (true, ..=68_000_000) => Latency::WS1,
257 (true, ..=102_000_000) => Latency::WS2,
258 (true, ..=136_000_000) => Latency::WS3,
259 (true, _) => Latency::WS4,
260
261 (false, ..=36_000_000) => Latency::WS0,
262 (false, ..=60_000_000) => Latency::WS1,
263 (false, ..=90_000_000) => Latency::WS2,
264 (false, ..=120_000_000) => Latency::WS3,
265 (false, _) => Latency::WS4,
237 }; 266 };
238 267
268 // Configure flash read access latency based on boost mode and frequency (RM0440 p98)
269 FLASH.acr().modify(|w| {
270 w.set_latency(latency);
271 });
272
273 // Spin until the effective flash latency is set.
274 while FLASH.acr().read().latency() != latency {}
275
276 if config.boost {
277 // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency.
278 cortex_m::asm::delay(16);
279 }
280
281 // Now that boost mode and flash read access latency are configured, set up SYSCLK
239 RCC.cfgr().modify(|w| { 282 RCC.cfgr().modify(|w| {
240 w.set_sw(sw); 283 w.set_sw(config.sys);
241 w.set_hpre(config.ahb_pre); 284 w.set_hpre(config.ahb_pre);
242 w.set_ppre1(config.apb1_pre); 285 w.set_ppre1(config.apb1_pre);
243 w.set_ppre2(config.apb2_pre); 286 w.set_ppre2(config.apb2_pre);
244 }); 287 });
245 288
246 let ahb_freq = sys_clk / config.ahb_pre; 289 if config.low_power_run {
290 assert!(sys <= Hertz(2_000_000));
291 PWR.cr1().modify(|w| w.set_lpr(true));
292 }
247 293
248 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 294 let rtc = config.ls.init();
249 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
250 pre => {
251 let freq = ahb_freq / pre;
252 (freq, freq * 2u32)
253 }
254 };
255 295
256 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 296 config.mux.init();
257 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 297
258 pre => { 298 set_clocks!(
259 let freq = ahb_freq / pre; 299 sys: Some(sys),
260 (freq, freq * 2u32) 300 hclk1: Some(hclk),
261 } 301 hclk2: Some(hclk),
262 }; 302 hclk3: Some(hclk),
303 pclk1: Some(pclk1),
304 pclk1_tim: Some(pclk1_tim),
305 pclk2: Some(pclk2),
306 pclk2_tim: Some(pclk2_tim),
307 pll1_p: pll.pll_p,
308 pll1_q: pll.pll_q,
309 pll1_r: pll.pll_r,
310 hsi: hsi,
311 hse: hse,
312 hsi48: hsi48,
313 rtc: rtc,
314 );
315}
263 316
264 // Setup the 48 MHz clock if needed 317/// Acceptable Frequency Ranges
265 if let Some(clock_48mhz_src) = config.clock_48mhz_src { 318/// Currently assuming voltage scaling range 1 boost mode.
266 let source = match clock_48mhz_src { 319/// Where not specified in the generic G4 reference manual (RM0440), values taken from the STM32G474 datasheet.
267 Clock48MhzSrc::PllQ => { 320/// If acceptable ranges for other G4-family chips differ, make additional max modules gated behind cfg attrs.
268 // Make sure the PLLQ is enabled and running at 48Mhz 321mod max {
269 let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q); 322 use core::ops::RangeInclusive;
270 assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
271 323
272 crate::pac::rcc::vals::Clk48sel::PLL1_Q 324 use crate::time::Hertz;
273 }
274 Clock48MhzSrc::Hsi48(config) => {
275 super::init_hsi48(config);
276 crate::pac::rcc::vals::Clk48sel::HSI48
277 }
278 };
279 325
280 RCC.ccipr().modify(|w| w.set_clk48sel(source)); 326 /// HSE Frequency Range (RM0440 p280)
281 } 327 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(48_000_000);
282 328
283 RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); 329 /// External Clock Frequency Range (RM0440 p280)
284 RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); 330 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
285 331
286 let adc12_ck = match config.adc12_clock_source { 332 /// SYSCLK Frequency Range (RM0440 p282)
287 AdcClockSource::DISABLE => None, 333 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(170_000_000);
288 AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
289 AdcClockSource::SYS => Some(sys_clk),
290 _ => unreachable!(),
291 };
292 334
293 let adc345_ck = match config.adc345_clock_source { 335 /// PLL Output Frequency Range (RM0440 p281, STM32G474 Datasheet p123, Table 46)
294 AdcClockSource::DISABLE => None, 336 pub(crate) const PCLK: RangeInclusive<Hertz> = Hertz(8)..=Hertz(170_000_000);
295 AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
296 AdcClockSource::SYS => Some(sys_clk),
297 _ => unreachable!(),
298 };
299 337
300 if config.low_power_run { 338 /// HCLK (AHB) Clock Frequency Range (STM32G474 Datasheet)
301 assert!(sys_clk <= Hertz(2_000_000)); 339 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(170_000_000);
302 PWR.cr1().modify(|w| w.set_lpr(true));
303 }
304 340
305 let rtc = config.ls.init(); 341 /// PLL Source Frequency Range (STM32G474 Datasheet p123, Table 46)
342 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(2_660_000)..=Hertz(16_000_000);
306 343
307 set_freqs(Clocks { 344 /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46)
308 sys: sys_clk, 345 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000);
309 hclk1: ahb_freq, 346 pub(crate) const PLL_P: RangeInclusive<Hertz> = Hertz(2_064_500)..=Hertz(170_000_000);
310 hclk2: ahb_freq, 347 pub(crate) const PLL_Q: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
311 hclk3: ahb_freq, 348 pub(crate) const PLL_R: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
312 pclk1: apb1_freq,
313 pclk1_tim: apb1_tim_freq,
314 pclk2: apb2_freq,
315 pclk2_tim: apb2_tim_freq,
316 adc: adc12_ck,
317 adc34: adc345_ck,
318 pll1_p: None,
319 pll1_q: None, // TODO
320 hse: None, // TODO
321 rtc,
322 });
323} 349}
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 15b51a398..bab8bb19e 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -2,17 +2,11 @@ use core::ops::RangeInclusive;
2 2
3use crate::pac; 3use crate::pac;
4use crate::pac::pwr::vals::Vos; 4use crate::pac::pwr::vals::Vos;
5#[cfg(stm32h5)]
6pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
7#[cfg(stm32h7)]
8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
9pub use crate::pac::rcc::vals::{ 5pub use crate::pac::rcc::vals::{
10 Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, 6 Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
11 Pllsrc as PllSource, Sw as Sysclk,
12}; 7};
13use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; 8use crate::pac::rcc::vals::{Pllrge, Pllvcosel, Timpre};
14use crate::pac::{FLASH, PWR, RCC}; 9use crate::pac::{FLASH, PWR, RCC};
15use crate::rcc::{set_freqs, Clocks};
16use crate::time::Hertz; 10use crate::time::Hertz;
17 11
18/// HSI speed 12/// HSI speed
@@ -171,22 +165,7 @@ pub enum SupplyConfig {
171/// This is only used in certain power supply configurations: 165/// This is only used in certain power supply configurations:
172/// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass. 166/// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass.
173#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] 167#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
174#[derive(PartialEq)] 168pub use pac::pwr::vals::Sdlevel as SMPSSupplyVoltage;
175pub enum SMPSSupplyVoltage {
176 V1_8,
177 V2_5,
178}
179
180#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
181impl SMPSSupplyVoltage {
182 /// Convert SMPSSupplyVoltage to u8 representation.
183 fn to_u8(&self) -> u8 {
184 match self {
185 SMPSSupplyVoltage::V1_8 => 0b01,
186 SMPSSupplyVoltage::V2_5 => 0b10,
187 }
188 }
189}
190 169
191/// Configuration of the core clocks 170/// Configuration of the core clocks
192#[non_exhaustive] 171#[non_exhaustive]
@@ -210,14 +189,15 @@ pub struct Config {
210 #[cfg(stm32h7)] 189 #[cfg(stm32h7)]
211 pub apb4_pre: APBPrescaler, 190 pub apb4_pre: APBPrescaler,
212 191
213 pub per_clock_source: PerClockSource,
214 pub adc_clock_source: AdcClockSource,
215 pub timer_prescaler: TimerPrescaler, 192 pub timer_prescaler: TimerPrescaler,
216 pub voltage_scale: VoltageScale, 193 pub voltage_scale: VoltageScale,
217 pub ls: super::LsConfig, 194 pub ls: super::LsConfig,
218 195
219 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] 196 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
220 pub supply_config: SupplyConfig, 197 pub supply_config: SupplyConfig,
198
199 /// Per-peripheral kernel clock selection muxes
200 pub mux: super::mux::ClockMux,
221} 201}
222 202
223impl Default for Config { 203impl Default for Config {
@@ -241,19 +221,14 @@ impl Default for Config {
241 #[cfg(stm32h7)] 221 #[cfg(stm32h7)]
242 apb4_pre: APBPrescaler::DIV1, 222 apb4_pre: APBPrescaler::DIV1,
243 223
244 per_clock_source: PerClockSource::HSI,
245
246 #[cfg(stm32h5)]
247 adc_clock_source: AdcClockSource::HCLK1,
248 #[cfg(stm32h7)]
249 adc_clock_source: AdcClockSource::PER,
250
251 timer_prescaler: TimerPrescaler::DefaultX2, 224 timer_prescaler: TimerPrescaler::DefaultX2,
252 voltage_scale: VoltageScale::Scale0, 225 voltage_scale: VoltageScale::Scale0,
253 ls: Default::default(), 226 ls: Default::default(),
254 227
255 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] 228 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
256 supply_config: SupplyConfig::Default, 229 supply_config: SupplyConfig::Default,
230
231 mux: Default::default(),
257 } 232 }
258 } 233 }
259} 234}
@@ -276,7 +251,7 @@ pub(crate) unsafe fn init(config: Config) {
276 match config.supply_config { 251 match config.supply_config {
277 SupplyConfig::Default => { 252 SupplyConfig::Default => {
278 PWR.cr3().modify(|w| { 253 PWR.cr3().modify(|w| {
279 w.set_sdlevel(0b00); 254 w.set_sdlevel(SMPSSupplyVoltage::RESET);
280 w.set_sdexthp(false); 255 w.set_sdexthp(false);
281 w.set_sden(true); 256 w.set_sden(true);
282 w.set_ldoen(true); 257 w.set_ldoen(true);
@@ -298,11 +273,11 @@ pub(crate) unsafe fn init(config: Config) {
298 w.set_bypass(false); 273 w.set_bypass(false);
299 }); 274 });
300 } 275 }
301 SupplyConfig::SMPSLDO(ref smps_supply_voltage) 276 SupplyConfig::SMPSLDO(smps_supply_voltage)
302 | SupplyConfig::SMPSExternalLDO(ref smps_supply_voltage) 277 | SupplyConfig::SMPSExternalLDO(smps_supply_voltage)
303 | SupplyConfig::SMPSExternalLDOBypass(ref smps_supply_voltage) => { 278 | SupplyConfig::SMPSExternalLDOBypass(smps_supply_voltage) => {
304 PWR.cr3().modify(|w| { 279 PWR.cr3().modify(|w| {
305 w.set_sdlevel(smps_supply_voltage.to_u8()); 280 w.set_sdlevel(smps_supply_voltage);
306 w.set_sdexthp(matches!( 281 w.set_sdexthp(matches!(
307 config.supply_config, 282 config.supply_config,
308 SupplyConfig::SMPSExternalLDO(_) | SupplyConfig::SMPSExternalLDOBypass(_) 283 SupplyConfig::SMPSExternalLDO(_) | SupplyConfig::SMPSExternalLDOBypass(_)
@@ -426,7 +401,7 @@ pub(crate) unsafe fn init(config: Config) {
426 }; 401 };
427 402
428 // Configure HSI48. 403 // Configure HSI48.
429 let _hsi48 = config.hsi48.map(super::init_hsi48); 404 let hsi48 = config.hsi48.map(super::init_hsi48);
430 405
431 // Configure CSI. 406 // Configure CSI.
432 RCC.cr().modify(|w| w.set_csion(config.csi)); 407 RCC.cr().modify(|w| w.set_csion(config.csi));
@@ -516,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) {
516 #[cfg(stm32h7)] 491 #[cfg(stm32h7)]
517 assert!(apb4 <= pclk_max); 492 assert!(apb4 <= pclk_max);
518 493
519 let _per_ck = match config.per_clock_source {
520 Ckpersel::HSI => hsi,
521 Ckpersel::CSI => csi,
522 Ckpersel::HSE => hse,
523 _ => unreachable!(),
524 };
525
526 #[cfg(stm32h7)]
527 let adc = match config.adc_clock_source {
528 AdcClockSource::PLL2_P => pll2.p,
529 AdcClockSource::PLL3_R => pll3.r,
530 AdcClockSource::PER => _per_ck,
531 _ => unreachable!(),
532 };
533 #[cfg(stm32h5)]
534 let adc = match config.adc_clock_source {
535 AdcClockSource::HCLK1 => Some(hclk),
536 AdcClockSource::SYS => Some(sys),
537 AdcClockSource::PLL2_R => pll2.r,
538 AdcClockSource::HSE => hse,
539 AdcClockSource::HSI => hsi,
540 AdcClockSource::CSI => csi,
541 _ => unreachable!(),
542 };
543
544 flash_setup(hclk, config.voltage_scale); 494 flash_setup(hclk, config.voltage_scale);
545 495
546 let rtc = config.ls.init(); 496 let rtc = config.ls.init();
@@ -562,13 +512,6 @@ pub(crate) unsafe fn init(config: Config) {
562 RCC.d3cfgr().modify(|w| { 512 RCC.d3cfgr().modify(|w| {
563 w.set_d3ppre(config.apb4_pre); 513 w.set_d3ppre(config.apb4_pre);
564 }); 514 });
565
566 RCC.d1ccipr().modify(|w| {
567 w.set_ckpersel(config.per_clock_source);
568 });
569 RCC.d3ccipr().modify(|w| {
570 w.set_adcsel(config.adc_clock_source);
571 });
572 } 515 }
573 #[cfg(stm32h5)] 516 #[cfg(stm32h5)]
574 { 517 {
@@ -582,11 +525,6 @@ pub(crate) unsafe fn init(config: Config) {
582 w.set_ppre2(config.apb2_pre); 525 w.set_ppre2(config.apb2_pre);
583 w.set_ppre3(config.apb3_pre); 526 w.set_ppre3(config.apb3_pre);
584 }); 527 });
585
586 RCC.ccipr5().modify(|w| {
587 w.set_ckpersel(config.per_clock_source);
588 w.set_adcdacsel(config.adc_clock_source)
589 });
590 } 528 }
591 529
592 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); 530 RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
@@ -609,45 +547,35 @@ pub(crate) unsafe fn init(config: Config) {
609 while !pac::SYSCFG.cccsr().read().ready() {} 547 while !pac::SYSCFG.cccsr().read().ready() {}
610 } 548 }
611 549
612 set_freqs(Clocks { 550 config.mux.init();
613 sys, 551
614 hclk1: hclk, 552 set_clocks!(
615 hclk2: hclk, 553 sys: Some(sys),
616 hclk3: hclk, 554 hclk1: Some(hclk),
617 hclk4: hclk, 555 hclk2: Some(hclk),
618 pclk1: apb1, 556 hclk3: Some(hclk),
619 pclk2: apb2, 557 hclk4: Some(hclk),
620 pclk3: apb3, 558 pclk1: Some(apb1),
559 pclk2: Some(apb2),
560 pclk3: Some(apb3),
621 #[cfg(stm32h7)] 561 #[cfg(stm32h7)]
622 pclk4: apb4, 562 pclk4: Some(apb4),
623 #[cfg(stm32h5)] 563 pclk1_tim: Some(apb1_tim),
624 pclk4: Hertz(1), 564 pclk2_tim: Some(apb2_tim),
625 pclk1_tim: apb1_tim, 565 rtc: rtc,
626 pclk2_tim: apb2_tim, 566
627 adc, 567 hsi: hsi,
628 rtc, 568 hsi48: hsi48,
629 569 csi: csi,
630 #[cfg(any(stm32h5, stm32h7))] 570 csi_div_122: csi.map(|c| c / 122u32),
631 hsi: None, 571 hse: hse,
632 #[cfg(stm32h5)]
633 hsi48: None,
634 #[cfg(stm32h5)]
635 lsi: None,
636 #[cfg(any(stm32h5, stm32h7))]
637 csi: None,
638 572
639 #[cfg(any(stm32h5, stm32h7))]
640 lse: None, 573 lse: None,
641 #[cfg(any(stm32h5, stm32h7))] 574 lsi: None,
642 hse: None,
643 575
644 #[cfg(any(stm32h5, stm32h7))]
645 pll1_q: pll1.q, 576 pll1_q: pll1.q,
646 #[cfg(any(stm32h5, stm32h7))]
647 pll2_p: pll2.p, 577 pll2_p: pll2.p,
648 #[cfg(any(stm32h5, stm32h7))]
649 pll2_q: pll2.q, 578 pll2_q: pll2.q,
650 #[cfg(any(stm32h5, stm32h7))]
651 pll2_r: pll2.r, 579 pll2_r: pll2.r,
652 #[cfg(any(rcc_h5, stm32h7))] 580 #[cfg(any(rcc_h5, stm32h7))]
653 pll3_p: pll3.p, 581 pll3_p: pll3.p,
@@ -665,12 +593,8 @@ pub(crate) unsafe fn init(config: Config) {
665 593
666 #[cfg(stm32h5)] 594 #[cfg(stm32h5)]
667 audioclk: None, 595 audioclk: None,
668 #[cfg(any(stm32h5, stm32h7))] 596 i2s_ckin: None,
669 per: None, 597 );
670
671 #[cfg(stm32h7)]
672 rcc_pclk_d3: None,
673 });
674} 598}
675 599
676struct PllInput { 600struct PllInput {
@@ -733,7 +657,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
733 } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { 657 } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) {
734 Pllvcosel::WIDEVCO 658 Pllvcosel::WIDEVCO
735 } else { 659 } else {
736 panic!("pll vco_clk out of range: {} mhz", vco_clk.0) 660 panic!("pll vco_clk out of range: {} hz", vco_clk.0)
737 }; 661 };
738 662
739 let p = config.divp.map(|div| { 663 let p = config.divp.map(|div| {
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 257fd83fe..9079ddd41 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -1,15 +1,10 @@
1#[cfg(any(stm32l0, stm32l1))] 1#[cfg(any(stm32l0, stm32l1))]
2pub use crate::pac::pwr::vals::Vos as VoltageScale; 2pub use crate::pac::pwr::vals::Vos as VoltageScale;
3use crate::pac::rcc::regs::Cfgr; 3use crate::pac::rcc::regs::Cfgr;
4#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
5pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
6#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
7pub use crate::pac::rcc::vals::Clk48sel as Clk48Src;
8#[cfg(any(stm32wb, stm32wl))] 4#[cfg(any(stm32wb, stm32wl))]
9pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; 5pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
10pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as ClockSrc}; 6pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk};
11use crate::pac::{FLASH, RCC}; 7use crate::pac::{FLASH, RCC};
12use crate::rcc::{set_freqs, Clocks};
13use crate::time::Hertz; 8use crate::time::Hertz;
14 9
15/// HSI speed 10/// HSI speed
@@ -51,7 +46,7 @@ pub struct Config {
51 pub pllsai2: Option<Pll>, 46 pub pllsai2: Option<Pll>,
52 47
53 // sysclk, buses. 48 // sysclk, buses.
54 pub mux: ClockSrc, 49 pub sys: Sysclk,
55 pub ahb_pre: AHBPrescaler, 50 pub ahb_pre: AHBPrescaler,
56 pub apb1_pre: APBPrescaler, 51 pub apb1_pre: APBPrescaler,
57 pub apb2_pre: APBPrescaler, 52 pub apb2_pre: APBPrescaler,
@@ -60,18 +55,14 @@ pub struct Config {
60 #[cfg(any(stm32wl, stm32wb))] 55 #[cfg(any(stm32wl, stm32wb))]
61 pub shared_ahb_pre: AHBPrescaler, 56 pub shared_ahb_pre: AHBPrescaler,
62 57
63 // muxes
64 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
65 pub clk48_src: Clk48Src,
66
67 // low speed LSI/LSE/RTC 58 // low speed LSI/LSE/RTC
68 pub ls: super::LsConfig, 59 pub ls: super::LsConfig,
69 60
70 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
71 pub adc_clock_source: AdcClockSource,
72
73 #[cfg(any(stm32l0, stm32l1))] 61 #[cfg(any(stm32l0, stm32l1))]
74 pub voltage_scale: VoltageScale, 62 pub voltage_scale: VoltageScale,
63
64 /// Per-peripheral kernel clock selection muxes
65 pub mux: super::mux::ClockMux,
75} 66}
76 67
77impl Default for Config { 68impl Default for Config {
@@ -81,7 +72,7 @@ impl Default for Config {
81 hse: None, 72 hse: None,
82 hsi: false, 73 hsi: false,
83 msi: Some(MSIRange::RANGE4M), 74 msi: Some(MSIRange::RANGE4M),
84 mux: ClockSrc::MSI, 75 sys: Sysclk::MSI,
85 ahb_pre: AHBPrescaler::DIV1, 76 ahb_pre: AHBPrescaler::DIV1,
86 apb1_pre: APBPrescaler::DIV1, 77 apb1_pre: APBPrescaler::DIV1,
87 apb2_pre: APBPrescaler::DIV1, 78 apb2_pre: APBPrescaler::DIV1,
@@ -96,13 +87,10 @@ impl Default for Config {
96 pllsai2: None, 87 pllsai2: None,
97 #[cfg(crs)] 88 #[cfg(crs)]
98 hsi48: Some(Default::default()), 89 hsi48: Some(Default::default()),
99 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
100 clk48_src: Clk48Src::HSI48,
101 ls: Default::default(), 90 ls: Default::default(),
102 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
103 adc_clock_source: AdcClockSource::SYS,
104 #[cfg(any(stm32l0, stm32l1))] 91 #[cfg(any(stm32l0, stm32l1))]
105 voltage_scale: VoltageScale::RANGE1, 92 voltage_scale: VoltageScale::RANGE1,
93 mux: Default::default(),
106 } 94 }
107 } 95 }
108} 96}
@@ -114,12 +102,11 @@ pub const WPAN_DEFAULT: Config = Config {
114 mode: HseMode::Oscillator, 102 mode: HseMode::Oscillator,
115 prescaler: HsePrescaler::DIV1, 103 prescaler: HsePrescaler::DIV1,
116 }), 104 }),
117 mux: ClockSrc::PLL1_R, 105 sys: Sysclk::PLL1_R,
118 #[cfg(crs)] 106 #[cfg(crs)]
119 hsi48: Some(super::Hsi48Config { sync_from_usb: false }), 107 hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
120 msi: None, 108 msi: None,
121 hsi: false, 109 hsi: false,
122 clk48_src: Clk48Src::PLL1_Q,
123 110
124 ls: super::LsConfig::default_lse(), 111 ls: super::LsConfig::default_lse(),
125 112
@@ -138,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config {
138 shared_ahb_pre: AHBPrescaler::DIV1, 125 shared_ahb_pre: AHBPrescaler::DIV1,
139 apb1_pre: APBPrescaler::DIV1, 126 apb1_pre: APBPrescaler::DIV1,
140 apb2_pre: APBPrescaler::DIV1, 127 apb2_pre: APBPrescaler::DIV1,
141 adc_clock_source: AdcClockSource::SYS, 128
129 mux: super::mux::ClockMux::default(),
142}; 130};
143 131
144fn msi_enable(range: MSIRange) { 132fn msi_enable(range: MSIRange) {
@@ -162,11 +150,11 @@ pub(crate) unsafe fn init(config: Config) {
162 // Turn on MSI and configure it to 4MHz. 150 // Turn on MSI and configure it to 4MHz.
163 msi_enable(MSIRange::RANGE4M) 151 msi_enable(MSIRange::RANGE4M)
164 } 152 }
165 if RCC.cfgr().read().sws() != ClockSrc::MSI { 153 if RCC.cfgr().read().sws() != Sysclk::MSI {
166 // Set MSI as a clock source, reset prescalers. 154 // Set MSI as a clock source, reset prescalers.
167 RCC.cfgr().write_value(Cfgr::default()); 155 RCC.cfgr().write_value(Cfgr::default());
168 // Wait for clock switch status bits to change. 156 // Wait for clock switch status bits to change.
169 while RCC.cfgr().read().sws() != ClockSrc::MSI {} 157 while RCC.cfgr().read().sws() != Sysclk::MSI {}
170 } 158 }
171 159
172 // Set voltage scale 160 // Set voltage scale
@@ -216,12 +204,9 @@ pub(crate) unsafe fn init(config: Config) {
216 }); 204 });
217 205
218 #[cfg(crs)] 206 #[cfg(crs)]
219 let _hsi48 = config.hsi48.map(|config| { 207 let hsi48 = config.hsi48.map(|config| super::init_hsi48(config));
220 //
221 super::init_hsi48(config)
222 });
223 #[cfg(not(crs))] 208 #[cfg(not(crs))]
224 let _hsi48: Option<Hertz> = None; 209 let hsi48: Option<Hertz> = None;
225 210
226 let _plls = [ 211 let _plls = [
227 &config.pll, 212 &config.pll,
@@ -262,28 +247,13 @@ pub(crate) unsafe fn init(config: Config) {
262 #[cfg(any(stm32l4, stm32l5, stm32wb))] 247 #[cfg(any(stm32l4, stm32l5, stm32wb))]
263 let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input); 248 let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input);
264 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] 249 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
265 let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); 250 let pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input);
266
267 let sys_clk = match config.mux {
268 ClockSrc::HSE => hse.unwrap(),
269 ClockSrc::HSI => hsi.unwrap(),
270 ClockSrc::MSI => msi.unwrap(),
271 ClockSrc::PLL1_R => pll.r.unwrap(),
272 };
273 251
274 #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))] 252 let sys_clk = match config.sys {
275 RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src)); 253 Sysclk::HSE => hse.unwrap(),
276 #[cfg(any(rcc_l0_v2))] 254 Sysclk::HSI => hsi.unwrap(),
277 let _clk48 = match config.clk48_src { 255 Sysclk::MSI => msi.unwrap(),
278 Clk48Src::HSI48 => _hsi48, 256 Sysclk::PLL1_R => pll.r.unwrap(),
279 Clk48Src::PLL1_VCO_DIV_2 => pll.clk48,
280 };
281 #[cfg(any(stm32l4, stm32l5, stm32wb))]
282 let _clk48 = match config.clk48_src {
283 Clk48Src::HSI48 => _hsi48,
284 Clk48Src::MSI => msi,
285 Clk48Src::PLLSAI1_Q => pllsai1.q,
286 Clk48Src::PLL1_Q => pll.q,
287 }; 257 };
288 258
289 #[cfg(rcc_l4plus)] 259 #[cfg(rcc_l4plus)]
@@ -354,15 +324,12 @@ pub(crate) unsafe fn init(config: Config) {
354 while FLASH.acr().read().latency() != latency {} 324 while FLASH.acr().read().latency() != latency {}
355 325
356 RCC.cfgr().modify(|w| { 326 RCC.cfgr().modify(|w| {
357 w.set_sw(config.mux); 327 w.set_sw(config.sys);
358 w.set_hpre(config.ahb_pre); 328 w.set_hpre(config.ahb_pre);
359 w.set_ppre1(config.apb1_pre); 329 w.set_ppre1(config.apb1_pre);
360 w.set_ppre2(config.apb2_pre); 330 w.set_ppre2(config.apb2_pre);
361 }); 331 });
362 while RCC.cfgr().read().sws() != config.mux {} 332 while RCC.cfgr().read().sws() != config.sys {}
363
364 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
365 RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source));
366 333
367 #[cfg(any(stm32wl, stm32wb))] 334 #[cfg(any(stm32wl, stm32wb))]
368 { 335 {
@@ -376,37 +343,64 @@ pub(crate) unsafe fn init(config: Config) {
376 while !RCC.extcfgr().read().c2hpref() {} 343 while !RCC.extcfgr().read().c2hpref() {}
377 } 344 }
378 345
379 set_freqs(Clocks { 346 config.mux.init();
380 sys: sys_clk, 347
381 hclk1, 348 set_clocks!(
349 sys: Some(sys_clk),
350 hclk1: Some(hclk1),
382 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 351 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
383 hclk2, 352 hclk2: Some(hclk2),
384 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] 353 #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
385 hclk3, 354 hclk3: Some(hclk3),
386 pclk1, 355 pclk1: Some(pclk1),
387 pclk2, 356 pclk2: Some(pclk2),
388 pclk1_tim, 357 pclk1_tim: Some(pclk1_tim),
389 pclk2_tim, 358 pclk2_tim: Some(pclk2_tim),
390 #[cfg(stm32wl)] 359 #[cfg(stm32wl)]
391 pclk3: hclk3, 360 pclk3: Some(hclk3),
392 #[cfg(rcc_l4)] 361 hsi: hsi,
393 hsi: None, 362 hse: hse,
394 #[cfg(rcc_l4)] 363 msi: msi,
395 lse: None, 364 hsi48: hsi48,
396 #[cfg(rcc_l4)] 365
397 pllsai1_p: None, 366 #[cfg(any(stm32l0, stm32l1))]
398 #[cfg(rcc_l4)] 367 pll1_vco_div_2: pll.vco.map(|c| c/2u32),
368
369 #[cfg(not(any(stm32l0, stm32l1)))]
370 pll1_p: pll.p,
371 #[cfg(not(any(stm32l0, stm32l1)))]
372 pll1_q: pll.q,
373 pll1_r: pll.r,
374
375 #[cfg(any(stm32l4, stm32l5, stm32wb))]
376 pllsai1_p: pllsai1.p,
377 #[cfg(any(stm32l4, stm32l5, stm32wb))]
378 pllsai1_q: pllsai1.q,
379 #[cfg(any(stm32l4, stm32l5, stm32wb))]
380 pllsai1_r: pllsai1.r,
381
382 #[cfg(not(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5)))]
399 pllsai2_p: None, 383 pllsai2_p: None,
400 #[cfg(rcc_l4)] 384 #[cfg(not(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5)))]
401 pll1_p: None, 385 pllsai2_q: None,
402 #[cfg(rcc_l4)] 386 #[cfg(not(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5)))]
403 pll1_q: None, 387 pllsai2_r: None,
404 #[cfg(rcc_l4)] 388
389 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
390 pllsai2_p: pllsai2.p,
391 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
392 pllsai2_q: pllsai2.q,
393 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
394 pllsai2_r: pllsai2.r,
395
396 rtc: rtc,
397
398 // TODO
405 sai1_extclk: None, 399 sai1_extclk: None,
406 #[cfg(rcc_l4)]
407 sai2_extclk: None, 400 sai2_extclk: None,
408 rtc, 401 lsi: None,
409 }); 402 lse: None,
403 );
410} 404}
411 405
412#[cfg(any(stm32l0, stm32l1))] 406#[cfg(any(stm32l0, stm32l1))]
@@ -491,7 +485,7 @@ mod pll {
491 #[derive(Default)] 485 #[derive(Default)]
492 pub(super) struct PllOutput { 486 pub(super) struct PllOutput {
493 pub r: Option<Hertz>, 487 pub r: Option<Hertz>,
494 pub clk48: Option<Hertz>, 488 pub vco: Option<Hertz>,
495 } 489 }
496 490
497 pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput { 491 pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
@@ -508,7 +502,6 @@ mod pll {
508 let vco_freq = pll_src * pll.mul; 502 let vco_freq = pll_src * pll.mul;
509 503
510 let r = vco_freq / pll.div; 504 let r = vco_freq / pll.div;
511 let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000));
512 505
513 assert!(r <= Hertz(32_000_000)); 506 assert!(r <= Hertz(32_000_000));
514 507
@@ -521,7 +514,10 @@ mod pll {
521 // Enable PLL 514 // Enable PLL
522 pll_enable(instance, true); 515 pll_enable(instance, true);
523 516
524 PllOutput { r: Some(r), clk48 } 517 PllOutput {
518 r: Some(r),
519 vco: Some(vco_freq),
520 }
525 } 521 }
526} 522}
527 523
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index eaaf8071c..654943bc1 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -4,7 +4,7 @@ use embassy_hal_internal::into_ref;
4 4
5use crate::gpio::sealed::AFType; 5use crate::gpio::sealed::AFType;
6use crate::gpio::Speed; 6use crate::gpio::Speed;
7#[cfg(not(stm32f1))] 7#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
8pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; 8pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
9#[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))] 9#[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))]
10pub use crate::pac::rcc::vals::Mcosel as McoSource; 10pub use crate::pac::rcc::vals::Mcosel as McoSource;
@@ -13,10 +13,16 @@ pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
13use crate::pac::RCC; 13use crate::pac::RCC;
14use crate::{peripherals, Peripheral}; 14use crate::{peripherals, Peripheral};
15 15
16#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))]
17#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
18pub enum McoPrescaler {
19 DIV1,
20}
21
16pub(crate) mod sealed { 22pub(crate) mod sealed {
17 pub trait McoInstance { 23 pub trait McoInstance {
18 type Source; 24 type Source;
19 unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: super::McoPrescaler); 25 unsafe fn apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler);
20 } 26 }
21} 27}
22 28
@@ -29,7 +35,7 @@ macro_rules! impl_peri {
29 impl sealed::McoInstance for peripherals::$peri { 35 impl sealed::McoInstance for peripherals::$peri {
30 type Source = $source; 36 type Source = $source;
31 37
32 unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: McoPrescaler) { 38 unsafe fn apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) {
33 #[cfg(not(any(stm32u5, stm32wba)))] 39 #[cfg(not(any(stm32u5, stm32wba)))]
34 let r = RCC.cfgr(); 40 let r = RCC.cfgr();
35 #[cfg(any(stm32u5, stm32wba))] 41 #[cfg(any(stm32u5, stm32wba))]
@@ -37,8 +43,8 @@ macro_rules! impl_peri {
37 43
38 r.modify(|w| { 44 r.modify(|w| {
39 w.$set_source(source); 45 w.$set_source(source);
40 #[cfg(not(stm32f1))] 46 #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
41 w.$set_prescaler(prescaler); 47 w.$set_prescaler(_prescaler);
42 }); 48 });
43 } 49 }
44 } 50 }
@@ -68,16 +74,12 @@ impl<'d, T: McoInstance> Mco<'d, T> {
68 _peri: impl Peripheral<P = T> + 'd, 74 _peri: impl Peripheral<P = T> + 'd,
69 pin: impl Peripheral<P = impl McoPin<T>> + 'd, 75 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
70 source: T::Source, 76 source: T::Source,
71 #[cfg(not(stm32f1))] prescaler: McoPrescaler, 77 prescaler: McoPrescaler,
72 ) -> Self { 78 ) -> Self {
73 into_ref!(pin); 79 into_ref!(pin);
74 80
75 critical_section::with(|_| unsafe { 81 critical_section::with(|_| unsafe {
76 T::apply_clock_settings( 82 T::apply_clock_settings(source, prescaler);
77 source,
78 #[cfg(not(stm32f1))]
79 prescaler,
80 );
81 pin.set_as_af(pin.af_num(), AFType::OutputPushPull); 83 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
82 pin.set_speed(Speed::VeryHigh); 84 pin.set_speed(Speed::VeryHigh);
83 }); 85 });
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 240ffc6d2..910ebe205 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -5,11 +5,12 @@
5 5
6use core::mem::MaybeUninit; 6use core::mem::MaybeUninit;
7 7
8use crate::time::Hertz;
9
10mod bd; 8mod bd;
11mod mco;
12pub use bd::*; 9pub use bd::*;
10
11#[cfg(any(mco, mco1, mco2))]
12mod mco;
13#[cfg(any(mco, mco1, mco2))]
13pub use mco::*; 14pub use mco::*;
14 15
15#[cfg(crs)] 16#[cfg(crs)]
@@ -17,177 +18,20 @@ mod hsi48;
17#[cfg(crs)] 18#[cfg(crs)]
18pub use hsi48::*; 19pub use hsi48::*;
19 20
20#[cfg_attr(rcc_f0, path = "f0.rs")] 21#[cfg_attr(any(stm32f0, stm32f1, stm32f3), path = "f013.rs")]
21#[cfg_attr(any(stm32f1), path = "f1.rs")] 22#[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f247.rs")]
22#[cfg_attr(any(stm32f3), path = "f3.rs")] 23#[cfg_attr(stm32c0, path = "c0.rs")]
23#[cfg_attr(any(stm32f2, stm32f4, stm32f7), path = "f.rs")] 24#[cfg_attr(stm32g0, path = "g0.rs")]
24#[cfg_attr(rcc_c0, path = "c0.rs")] 25#[cfg_attr(stm32g4, path = "g4.rs")]
25#[cfg_attr(rcc_g0, path = "g0.rs")]
26#[cfg_attr(rcc_g4, path = "g4.rs")]
27#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")] 26#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")]
28#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")] 27#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")]
29#[cfg_attr(rcc_u5, path = "u5.rs")] 28#[cfg_attr(stm32u5, path = "u5.rs")]
30#[cfg_attr(rcc_wba, path = "wba.rs")] 29#[cfg_attr(stm32wba, path = "wba.rs")]
31mod _version; 30mod _version;
32 31
33pub use _version::*; 32pub use _version::*;
34 33
35// Model Clock Configuration 34pub use crate::_generated::{mux, Clocks};
36//
37// pub struct Clocks {
38// hse: Option<Hertz>,
39// hsi: bool,
40// lse: Option<Hertz>,
41// lsi: bool,
42// rtc: RtcSource,
43// }
44
45#[derive(Clone, Copy, Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct Clocks {
48 pub sys: Hertz,
49
50 // APB
51 pub pclk1: Hertz,
52 pub pclk1_tim: Hertz,
53 #[cfg(not(any(rcc_c0, rcc_g0)))]
54 pub pclk2: Hertz,
55 #[cfg(not(any(rcc_c0, rcc_g0)))]
56 pub pclk2_tim: Hertz,
57 #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))]
58 pub pclk3: Hertz,
59 #[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab, stm32h5))]
60 pub pclk4: Hertz,
61 #[cfg(any(rcc_wba))]
62 pub pclk7: Hertz,
63
64 // AHB
65 pub hclk1: Hertz,
66 #[cfg(any(
67 rcc_l4,
68 rcc_l4plus,
69 rcc_l5,
70 rcc_f2,
71 rcc_f4,
72 rcc_f410,
73 rcc_f7,
74 rcc_h5,
75 rcc_h50,
76 rcc_h7,
77 rcc_h7rm0433,
78 rcc_h7ab,
79 rcc_g4,
80 rcc_u5,
81 rcc_wb,
82 rcc_wba,
83 rcc_wl5,
84 rcc_wle
85 ))]
86 pub hclk2: Hertz,
87 #[cfg(any(
88 rcc_l4,
89 rcc_l4plus,
90 rcc_l5,
91 rcc_f2,
92 rcc_f4,
93 rcc_f410,
94 rcc_f7,
95 rcc_h5,
96 rcc_h50,
97 rcc_h7,
98 rcc_h7rm0433,
99 rcc_h7ab,
100 rcc_u5,
101 rcc_g4,
102 rcc_wb,
103 rcc_wl5,
104 rcc_wle
105 ))]
106 pub hclk3: Hertz,
107 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))]
108 pub hclk4: Hertz,
109
110 #[cfg(all(rcc_f4, not(stm32f410)))]
111 pub plli2s1_q: Option<Hertz>,
112 #[cfg(all(rcc_f4, not(stm32f410)))]
113 pub plli2s1_r: Option<Hertz>,
114
115 #[cfg(rcc_l4)]
116 pub pllsai1_p: Option<Hertz>,
117 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
118 pub pllsai1_q: Option<Hertz>,
119 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
120 pub pllsai1_r: Option<Hertz>,
121 #[cfg(rcc_l4)]
122 pub pllsai2_p: Option<Hertz>,
123
124 #[cfg(any(stm32g0, stm32g4, rcc_l4))]
125 pub pll1_p: Option<Hertz>,
126 #[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g0, stm32g4))]
127 pub pll1_q: Option<Hertz>,
128 #[cfg(any(stm32h5, stm32h7))]
129 pub pll2_p: Option<Hertz>,
130 #[cfg(any(stm32h5, stm32h7))]
131 pub pll2_q: Option<Hertz>,
132 #[cfg(any(stm32h5, stm32h7))]
133 pub pll2_r: Option<Hertz>,
134 #[cfg(any(stm32h5, stm32h7))]
135 pub pll3_p: Option<Hertz>,
136 #[cfg(any(stm32h5, stm32h7))]
137 pub pll3_q: Option<Hertz>,
138 #[cfg(any(stm32h5, stm32h7))]
139 pub pll3_r: Option<Hertz>,
140
141 #[cfg(any(
142 rcc_f1,
143 rcc_f100,
144 rcc_f1cl,
145 rcc_h5,
146 rcc_h50,
147 rcc_h7,
148 rcc_h7rm0433,
149 rcc_h7ab,
150 rcc_f3,
151 rcc_g4
152 ))]
153 pub adc: Option<Hertz>,
154
155 #[cfg(any(rcc_f3, rcc_g4))]
156 pub adc34: Option<Hertz>,
157
158 #[cfg(stm32f334)]
159 pub hrtim: Option<Hertz>,
160
161 pub rtc: Option<Hertz>,
162
163 #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))]
164 pub hsi: Option<Hertz>,
165 #[cfg(any(stm32h5, stm32g0))]
166 pub hsi48: Option<Hertz>,
167 #[cfg(stm32g0)]
168 pub hsi_div_8: Option<Hertz>,
169 #[cfg(any(stm32g0, stm32h5))]
170 pub lsi: Option<Hertz>,
171 #[cfg(any(stm32h5, stm32h7))]
172 pub csi: Option<Hertz>,
173
174 #[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))]
175 pub lse: Option<Hertz>,
176 #[cfg(any(stm32h5, stm32h7, stm32g0, stm32g4))]
177 pub hse: Option<Hertz>,
178
179 #[cfg(stm32h5)]
180 pub audioclk: Option<Hertz>,
181 #[cfg(any(stm32h5, stm32h7))]
182 pub per: Option<Hertz>,
183
184 #[cfg(stm32h7)]
185 pub rcc_pclk_d3: Option<Hertz>,
186 #[cfg(rcc_l4)]
187 pub sai1_extclk: Option<Hertz>,
188 #[cfg(rcc_l4)]
189 pub sai2_extclk: Option<Hertz>,
190}
191 35
192#[cfg(feature = "low-power")] 36#[cfg(feature = "low-power")]
193/// Must be written within a critical section 37/// Must be written within a critical section
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index dff08dc9b..9533e16c4 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,135 +1,83 @@
1pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; 1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; 2pub use crate::pac::rcc::vals::{
3 Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
4 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
5};
6use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge};
3use crate::pac::{FLASH, PWR, RCC}; 7use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 8use crate::time::Hertz;
6 9
7/// HSI speed 10/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(16_000_000); 11pub const HSI_FREQ: Hertz = Hertz(16_000_000);
9 12
10pub use crate::pac::pwr::vals::Vos as VoltageScale; 13#[derive(Clone, Copy, Eq, PartialEq)]
11 14pub enum HseMode {
12#[derive(Copy, Clone)] 15 /// crystal/ceramic oscillator (HSEBYP=0)
13#[allow(non_camel_case_types)] 16 Oscillator,
14pub enum ClockSrc { 17 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
15 /// Use an internal medium speed oscillator (MSIS) as the system clock. 18 Bypass,
16 MSI(Msirange), 19 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
17 /// Use the external high speed clock as the system clock. 20 BypassDigital,
18 ///
19 /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
20 /// never exceed 50 MHz.
21 HSE(Hertz),
22 /// Use the 16 MHz internal high speed oscillator as the system clock.
23 HSI,
24 /// Use PLL1 as the system clock.
25 PLL1_R(PllConfig),
26} 21}
27 22
28impl Default for ClockSrc { 23#[derive(Clone, Copy, Eq, PartialEq)]
29 fn default() -> Self { 24pub struct Hse {
30 // The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9 25 /// HSE frequency.
31 ClockSrc::MSI(Msirange::RANGE_4MHZ) 26 pub freq: Hertz,
32 } 27 /// HSE mode.
28 pub mode: HseMode,
33} 29}
34 30
35#[derive(Clone, Copy)] 31#[derive(Clone, Copy)]
36pub struct PllConfig { 32pub struct Pll {
37 /// The clock source for the PLL. 33 /// The clock source for the PLL.
38 pub source: PllSource, 34 pub source: PllSource,
39 /// The PLL prescaler. 35 /// The PLL pre-divider.
40 /// 36 ///
41 /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. 37 /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz.
42 pub m: Pllm, 38 pub prediv: PllPreDiv,
43 /// The PLL multiplier. 39 /// The PLL multiplier.
44 /// 40 ///
45 /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 41 /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544
46 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. 42 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`.
47 pub n: Plln, 43 pub mul: PllMul,
48 /// The divider for the P output. 44 /// The divider for the P output.
49 /// 45 ///
50 /// The P output is one of several options 46 /// The P output is one of several options
51 /// that can be used to feed the SAI/MDF/ADF Clock mux's. 47 /// that can be used to feed the SAI/MDF/ADF Clock mux's.
52 pub p: Plldiv, 48 pub divp: Option<PllDiv>,
53 /// The divider for the Q output. 49 /// The divider for the Q output.
54 /// 50 ///
55 /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks 51 /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks
56 /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. 52 /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's.
57 pub q: Plldiv, 53 pub divq: Option<PllDiv>,
58 /// The divider for the R output. 54 /// The divider for the R output.
59 /// 55 ///
60 /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` 56 /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r`
61 /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default 57 /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default
62 /// `Config { voltage_range }`. 58 /// `Config { voltage_range }`.
63 pub r: Plldiv, 59 pub divr: Option<PllDiv>,
64}
65
66impl PllConfig {
67 /// A configuration for HSI / 1 * 10 / 1 = 160 MHz
68 pub const fn hsi_160mhz() -> Self {
69 PllConfig {
70 source: PllSource::HSI,
71 m: Pllm::DIV1,
72 n: Plln::MUL10,
73 p: Plldiv::DIV3,
74 q: Plldiv::DIV2,
75 r: Plldiv::DIV1,
76 }
77 }
78
79 /// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz
80 pub const fn msis_160mhz() -> Self {
81 PllConfig {
82 source: PllSource::MSIS(Msirange::RANGE_48MHZ),
83 m: Pllm::DIV3,
84 n: Plln::MUL10,
85 p: Plldiv::DIV3,
86 q: Plldiv::DIV2,
87 r: Plldiv::DIV1,
88 }
89 }
90}
91
92#[derive(Clone, Copy)]
93pub enum PllSource {
94 /// Use an internal medium speed oscillator as the PLL source.
95 MSIS(Msirange),
96 /// Use the external high speed clock as the system PLL source.
97 ///
98 /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
99 /// never exceed 50 MHz.
100 HSE(Hertz),
101 /// Use the 16 MHz internal high speed oscillator as the PLL source.
102 HSI,
103} 60}
104 61
105impl Into<Pllsrc> for PllSource { 62pub struct Config {
106 fn into(self) -> Pllsrc { 63 // base clock sources
107 match self { 64 pub msi: Option<MSIRange>,
108 PllSource::MSIS(..) => Pllsrc::MSIS, 65 pub hsi: bool,
109 PllSource::HSE(..) => Pllsrc::HSE, 66 pub hse: Option<Hse>,
110 PllSource::HSI => Pllsrc::HSI, 67 pub hsi48: Option<super::Hsi48Config>,
111 }
112 }
113}
114 68
115impl Into<Sw> for ClockSrc { 69 // pll
116 fn into(self) -> Sw { 70 pub pll1: Option<Pll>,
117 match self { 71 pub pll2: Option<Pll>,
118 ClockSrc::MSI(..) => Sw::MSIS, 72 pub pll3: Option<Pll>,
119 ClockSrc::HSE(..) => Sw::HSE,
120 ClockSrc::HSI => Sw::HSI,
121 ClockSrc::PLL1_R(..) => Sw::PLL1_R,
122 }
123 }
124}
125 73
126pub struct Config { 74 // sysclk, buses.
127 pub mux: ClockSrc, 75 pub sys: Sysclk,
128 pub ahb_pre: AHBPrescaler, 76 pub ahb_pre: AHBPrescaler,
129 pub apb1_pre: APBPrescaler, 77 pub apb1_pre: APBPrescaler,
130 pub apb2_pre: APBPrescaler, 78 pub apb2_pre: APBPrescaler,
131 pub apb3_pre: APBPrescaler, 79 pub apb3_pre: APBPrescaler,
132 pub hsi48: Option<super::Hsi48Config>, 80
133 /// The voltage range influences the maximum clock frequencies for different parts of the 81 /// The voltage range influences the maximum clock frequencies for different parts of the
134 /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks 82 /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
135 /// exceeding 55 MHz require at least `RANGE2`. 83 /// exceeding 55 MHz require at least `RANGE2`.
@@ -137,37 +85,41 @@ pub struct Config {
137 /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits. 85 /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
138 pub voltage_range: VoltageScale, 86 pub voltage_range: VoltageScale,
139 pub ls: super::LsConfig, 87 pub ls: super::LsConfig,
140}
141 88
142impl Config { 89 /// Per-peripheral kernel clock selection muxes
143 unsafe fn init_hsi(&self) -> Hertz { 90 pub mux: super::mux::ClockMux,
144 RCC.cr().write(|w| w.set_hsion(true)); 91}
145 while !RCC.cr().read().hsirdy() {}
146
147 HSI_FREQ
148 }
149 92
150 unsafe fn init_hse(&self, frequency: Hertz) -> Hertz { 93impl Default for Config {
151 // Check frequency limits per RM456 § 11.4.10 94 fn default() -> Self {
152 match self.voltage_range { 95 Self {
153 VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { 96 msi: Some(Msirange::RANGE_4MHZ),
154 assert!(frequency.0 <= 50_000_000); 97 hse: None,
155 } 98 hsi: false,
156 VoltageScale::RANGE4 => { 99 hsi48: Some(Default::default()),
157 assert!(frequency.0 <= 25_000_000); 100 pll1: None,
158 } 101 pll2: None,
102 pll3: None,
103 sys: Sysclk::MSIS,
104 ahb_pre: AHBPrescaler::DIV1,
105 apb1_pre: APBPrescaler::DIV1,
106 apb2_pre: APBPrescaler::DIV1,
107 apb3_pre: APBPrescaler::DIV1,
108 voltage_range: VoltageScale::RANGE1,
109 ls: Default::default(),
110 mux: Default::default(),
159 } 111 }
160
161 // Enable HSE, and wait for it to stabilize
162 RCC.cr().write(|w| w.set_hseon(true));
163 while !RCC.cr().read().hserdy() {}
164
165 frequency
166 } 112 }
113}
114
115pub(crate) unsafe fn init(config: Config) {
116 // Set the requested power mode
117 PWR.vosr().modify(|w| w.set_vos(config.voltage_range));
118 while !PWR.vosr().read().vosrdy() {}
167 119
168 unsafe fn init_msis(&self, range: Msirange) -> Hertz { 120 let msi = config.msi.map(|range| {
169 // Check MSI output per RM0456 § 11.4.10 121 // Check MSI output per RM0456 § 11.4.10
170 match self.voltage_range { 122 match config.voltage_range {
171 VoltageScale::RANGE4 => { 123 VoltageScale::RANGE4 => {
172 assert!(msirange_to_hertz(range).0 <= 24_000_000); 124 assert!(msirange_to_hertz(range).0 <= 24_000_000);
173 } 125 }
@@ -192,223 +144,98 @@ impl Config {
192 }); 144 });
193 while !RCC.cr().read().msisrdy() {} 145 while !RCC.cr().read().msisrdy() {}
194 msirange_to_hertz(range) 146 msirange_to_hertz(range)
195 }
196}
197
198impl Default for Config {
199 fn default() -> Self {
200 Self {
201 mux: ClockSrc::default(),
202 ahb_pre: AHBPrescaler::DIV1,
203 apb1_pre: APBPrescaler::DIV1,
204 apb2_pre: APBPrescaler::DIV1,
205 apb3_pre: APBPrescaler::DIV1,
206 hsi48: Some(Default::default()),
207 voltage_range: VoltageScale::RANGE3,
208 ls: Default::default(),
209 }
210 }
211}
212
213pub(crate) unsafe fn init(config: Config) {
214 // Ensure PWR peripheral clock is enabled
215 RCC.ahb3enr().modify(|w| {
216 w.set_pwren(true);
217 }); 147 });
218 RCC.ahb3enr().read(); // synchronize
219 148
220 // Set the requested power mode 149 let hsi = config.hsi.then(|| {
221 PWR.vosr().modify(|w| { 150 RCC.cr().write(|w| w.set_hsion(true));
222 w.set_vos(config.voltage_range); 151 while !RCC.cr().read().hsirdy() {}
152
153 HSI_FREQ
223 }); 154 });
224 while !PWR.vosr().read().vosrdy() {}
225 155
226 let sys_clk = match config.mux { 156 let hse = config.hse.map(|hse| {
227 ClockSrc::MSI(range) => config.init_msis(range), 157 // Check frequency limits per RM456 § 11.4.10
228 ClockSrc::HSE(freq) => config.init_hse(freq), 158 match config.voltage_range {
229 ClockSrc::HSI => config.init_hsi(), 159 VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => {
230 ClockSrc::PLL1_R(pll) => { 160 assert!(hse.freq.0 <= 50_000_000);
231 // Configure the PLL source
232 let source_clk = match pll.source {
233 PllSource::MSIS(range) => config.init_msis(range),
234 PllSource::HSE(hertz) => config.init_hse(hertz),
235 PllSource::HSI => config.init_hsi(),
236 };
237
238 // Calculate the reference clock, which is the source divided by m
239 let reference_clk = source_clk / pll.m;
240
241 // Check limits per RM0456 § 11.4.6
242 assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16));
243
244 // Calculate the PLL1 VCO clock and PLL1 R output clock
245 let pll1_clk = reference_clk * pll.n;
246 let pll1r_clk = pll1_clk / pll.r;
247
248 // Check system clock per RM0456 § 11.4.9
249 assert!(pll1r_clk <= Hertz::mhz(160));
250
251 // Check PLL clocks per RM0456 § 11.4.10
252 match config.voltage_range {
253 VoltageScale::RANGE1 => {
254 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
255 assert!(pll1r_clk <= Hertz::mhz(208));
256 }
257 VoltageScale::RANGE2 => {
258 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
259 assert!(pll1r_clk <= Hertz::mhz(110));
260 }
261 VoltageScale::RANGE3 => {
262 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330));
263 assert!(pll1r_clk <= Hertz::mhz(55));
264 }
265 VoltageScale::RANGE4 => {
266 panic!("PLL is unavailable in voltage range 4");
267 }
268 } 161 }
162 VoltageScale::RANGE4 => {
163 assert!(hse.freq.0 <= 25_000_000);
164 }
165 }
269 166
270 // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler 167 // Enable HSE, and wait for it to stabilize
271 // value that results in an output between 4 and 16 MHz for the PWR EPOD boost 168 RCC.cr().write(|w| {
272 let mboost = if pll1r_clk >= Hertz::mhz(55) { 169 w.set_hseon(true);
273 // source_clk can be up to 50 MHz, so there's just a few cases: 170 w.set_hsebyp(hse.mode != HseMode::Oscillator);
274 if source_clk > Hertz::mhz(32) { 171 w.set_hseext(match hse.mode {
275 // Divide by 4, giving EPOD 8-12.5 MHz 172 HseMode::Oscillator | HseMode::Bypass => Hseext::ANALOG,
276 Pllmboost::DIV4 173 HseMode::BypassDigital => Hseext::DIGITAL,
277 } else if source_clk > Hertz::mhz(16) {
278 // Divide by 2, giving EPOD 8-16 MHz
279 Pllmboost::DIV2
280 } else {
281 // Bypass, giving EPOD 4-16 MHz
282 Pllmboost::DIV1
283 }
284 } else {
285 // Nothing to do
286 Pllmboost::DIV1
287 };
288
289 // Disable the PLL, and wait for it to disable
290 RCC.cr().modify(|w| w.set_pllon(0, false));
291 while RCC.cr().read().pllrdy(0) {}
292
293 // Configure the PLL
294 RCC.pll1cfgr().write(|w| {
295 // Configure PLL1 source and prescaler
296 w.set_pllsrc(pll.source.into());
297 w.set_pllm(pll.m);
298
299 // Configure PLL1 input frequncy range
300 let input_range = if reference_clk <= Hertz::mhz(8) {
301 Pllrge::FREQ_4TO8MHZ
302 } else {
303 Pllrge::FREQ_8TO16MHZ
304 };
305 w.set_pllrge(input_range);
306
307 // Set the prescaler for PWR EPOD
308 w.set_pllmboost(mboost);
309
310 // Enable PLL1_R output
311 w.set_pllren(true);
312 }); 174 });
175 });
176 while !RCC.cr().read().hserdy() {}
313 177
314 // Configure the PLL divisors 178 hse.freq
315 RCC.pll1divr().modify(|w| { 179 });
316 // Set the VCO multiplier
317 w.set_plln(pll.n);
318 w.set_pllp(pll.p);
319 w.set_pllq(pll.q);
320 // Set the R output divisor
321 w.set_pllr(pll.r);
322 });
323 180
324 // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? 181 let hsi48 = config.hsi48.map(super::init_hsi48);
325 if pll1r_clk >= Hertz::mhz(55) {
326 // Enable the booster
327 PWR.vosr().modify(|w| {
328 w.set_boosten(true);
329 });
330 while !PWR.vosr().read().boostrdy() {}
331 }
332 182
333 // Enable the PLL 183 let pll_input = PllInput { hse, hsi, msi };
334 RCC.cr().modify(|w| w.set_pllon(0, true)); 184 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
335 while !RCC.cr().read().pllrdy(0) {} 185 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range);
186 let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range);
336 187
337 pll1r_clk 188 let sys_clk = match config.sys {
338 } 189 Sysclk::HSE => hse.unwrap(),
190 Sysclk::HSI => hsi.unwrap(),
191 Sysclk::MSIS => msi.unwrap(),
192 Sysclk::PLL1_R => pll1.r.unwrap(),
339 }; 193 };
340 194
341 let _hsi48 = config.hsi48.map(super::init_hsi48); 195 // Do we need the EPOD booster to reach the target clock speed per § 10.5.4?
196 if sys_clk >= Hertz::mhz(55) {
197 // Enable the booster
198 PWR.vosr().modify(|w| w.set_boosten(true));
199 while !PWR.vosr().read().boostrdy() {}
200 }
342 201
343 // The clock source is ready 202 // The clock source is ready
344 // Calculate and set the flash wait states 203 // Calculate and set the flash wait states
345 let wait_states = match config.voltage_range { 204 let wait_states = match config.voltage_range {
346 // VOS 1 range VCORE 1.26V - 1.40V 205 // VOS 1 range VCORE 1.26V - 1.40V
347 VoltageScale::RANGE1 => { 206 VoltageScale::RANGE1 => match sys_clk.0 {
348 if sys_clk.0 < 32_000_000 { 207 ..=32_000_000 => 0,
349 0 208 ..=64_000_000 => 1,
350 } else if sys_clk.0 < 64_000_000 { 209 ..=96_000_000 => 2,
351 1 210 ..=128_000_000 => 3,
352 } else if sys_clk.0 < 96_000_000 { 211 _ => 4,
353 2 212 },
354 } else if sys_clk.0 < 128_000_000 {
355 3
356 } else {
357 4
358 }
359 }
360 // VOS 2 range VCORE 1.15V - 1.26V 213 // VOS 2 range VCORE 1.15V - 1.26V
361 VoltageScale::RANGE2 => { 214 VoltageScale::RANGE2 => match sys_clk.0 {
362 if sys_clk.0 < 30_000_000 { 215 ..=30_000_000 => 0,
363 0 216 ..=60_000_000 => 1,
364 } else if sys_clk.0 < 60_000_000 { 217 ..=90_000_000 => 2,
365 1 218 _ => 3,
366 } else if sys_clk.0 < 90_000_000 { 219 },
367 2
368 } else {
369 3
370 }
371 }
372 // VOS 3 range VCORE 1.05V - 1.15V 220 // VOS 3 range VCORE 1.05V - 1.15V
373 VoltageScale::RANGE3 => { 221 VoltageScale::RANGE3 => match sys_clk.0 {
374 if sys_clk.0 < 24_000_000 { 222 ..=24_000_000 => 0,
375 0 223 ..=48_000_000 => 1,
376 } else if sys_clk.0 < 48_000_000 { 224 _ => 2,
377 1 225 },
378 } else {
379 2
380 }
381 }
382 // VOS 4 range VCORE 0.95V - 1.05V 226 // VOS 4 range VCORE 0.95V - 1.05V
383 VoltageScale::RANGE4 => { 227 VoltageScale::RANGE4 => match sys_clk.0 {
384 if sys_clk.0 < 12_000_000 { 228 ..=12_000_000 => 0,
385 0 229 _ => 1,
386 } else { 230 },
387 1
388 }
389 }
390 }; 231 };
391 FLASH.acr().modify(|w| { 232 FLASH.acr().modify(|w| {
392 w.set_latency(wait_states); 233 w.set_latency(wait_states);
393 }); 234 });
394 235
395 // Switch the system clock source 236 // Switch the system clock source
396 RCC.cfgr1().modify(|w| { 237 RCC.cfgr1().modify(|w| w.set_sw(config.sys));
397 w.set_sw(config.mux.into()); 238 while RCC.cfgr1().read().sws() != config.sys {}
398 });
399
400 // RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus
401 // frequency for each voltage range exactly matches the maximum permitted PLL output frequency.
402 // Given that:
403 //
404 // 1. Any bus frequency can never exceed the system clock frequency;
405 // 2. We checked the PLL output frequency if we're using it as a system clock;
406 // 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and
407 // we checked the HSE frequency if configured as a system clock; and
408 // 4. The maximum frequencies from the other clock sources are lower than the lowest bus
409 // frequency limit
410 //
411 // ...then we do not need to perform additional bus-related frequency checks.
412 239
413 // Configure the bus prescalers 240 // Configure the bus prescalers
414 RCC.cfgr2().modify(|w| { 241 RCC.cfgr2().modify(|w| {
@@ -420,46 +247,57 @@ pub(crate) unsafe fn init(config: Config) {
420 w.set_ppre3(config.apb3_pre); 247 w.set_ppre3(config.apb3_pre);
421 }); 248 });
422 249
423 let ahb_freq = sys_clk / config.ahb_pre; 250 let hclk = sys_clk / config.ahb_pre;
424 251
425 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 252 let hclk_max = match config.voltage_range {
426 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 253 VoltageScale::RANGE1 => Hertz::mhz(160),
427 pre => { 254 VoltageScale::RANGE2 => Hertz::mhz(110),
428 let freq = ahb_freq / pre; 255 VoltageScale::RANGE3 => Hertz::mhz(55),
429 (freq, freq * 2u32) 256 VoltageScale::RANGE4 => Hertz::mhz(25),
430 }
431 }; 257 };
258 assert!(hclk <= hclk_max);
432 259
433 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 260 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
434 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 261 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
435 pre => { 262 let (pclk3, _) = super::util::calc_pclk(hclk, config.apb3_pre);
436 let freq = ahb_freq / pre;
437 (freq, freq * 2u32)
438 }
439 };
440
441 let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
442 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
443 pre => {
444 let freq = ahb_freq / pre;
445 (freq, freq * 2u32)
446 }
447 };
448 263
449 let rtc = config.ls.init(); 264 let rtc = config.ls.init();
450 265
451 set_freqs(Clocks { 266 config.mux.init();
452 sys: sys_clk, 267
453 hclk1: ahb_freq, 268 set_clocks!(
454 hclk2: ahb_freq, 269 sys: Some(sys_clk),
455 hclk3: ahb_freq, 270 hclk1: Some(hclk),
456 pclk1: apb1_freq, 271 hclk2: Some(hclk),
457 pclk2: apb2_freq, 272 hclk3: Some(hclk),
458 pclk3: apb3_freq, 273 pclk1: Some(pclk1),
459 pclk1_tim: apb1_tim_freq, 274 pclk2: Some(pclk2),
460 pclk2_tim: apb2_tim_freq, 275 pclk3: Some(pclk3),
461 rtc, 276 pclk1_tim: Some(pclk1_tim),
462 }); 277 pclk2_tim: Some(pclk2_tim),
278 hsi48: hsi48,
279 rtc: rtc,
280 hse: hse,
281 hsi: hsi,
282 pll1_p: pll1.p,
283 pll1_q: pll1.q,
284 pll1_r: pll1.r,
285 pll2_p: pll2.p,
286 pll2_q: pll2.q,
287 pll2_r: pll2.r,
288 pll3_p: pll3.p,
289 pll3_q: pll3.q,
290 pll3_r: pll3.r,
291
292 // TODO
293 audioclk: None,
294 hsi48_div_2: None,
295 lse: None,
296 lsi: None,
297 msik: None,
298 shsi: None,
299 shsi_div_2: None,
300 );
463} 301}
464 302
465fn msirange_to_hertz(range: Msirange) -> Hertz { 303fn msirange_to_hertz(range: Msirange) -> Hertz {
@@ -482,3 +320,126 @@ fn msirange_to_hertz(range: Msirange) -> Hertz {
482 Msirange::RANGE_100KHZ => Hertz(100_000), 320 Msirange::RANGE_100KHZ => Hertz(100_000),
483 } 321 }
484} 322}
323
324pub(super) struct PllInput {
325 pub hsi: Option<Hertz>,
326 pub hse: Option<Hertz>,
327 pub msi: Option<Hertz>,
328}
329
330#[allow(unused)]
331#[derive(Default)]
332pub(super) struct PllOutput {
333 pub p: Option<Hertz>,
334 pub q: Option<Hertz>,
335 pub r: Option<Hertz>,
336}
337
338#[derive(PartialEq, Eq, Clone, Copy)]
339enum PllInstance {
340 Pll1 = 0,
341 Pll2 = 1,
342 Pll3 = 2,
343}
344
345fn pll_enable(instance: PllInstance, enabled: bool) {
346 RCC.cr().modify(|w| w.set_pllon(instance as _, enabled));
347 while RCC.cr().read().pllrdy(instance as _) != enabled {}
348}
349
350fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) -> PllOutput {
351 // Disable PLL
352 pll_enable(instance, false);
353
354 let Some(pll) = config else { return PllOutput::default() };
355
356 let src_freq = match pll.source {
357 PllSource::DISABLE => panic!("must not select PLL source as DISABLE"),
358 PllSource::HSE => unwrap!(input.hse),
359 PllSource::HSI => unwrap!(input.hsi),
360 PllSource::MSIS => unwrap!(input.msi),
361 };
362
363 // Calculate the reference clock, which is the source divided by m
364 let ref_freq = src_freq / pll.prediv;
365 // Check limits per RM0456 § 11.4.6
366 assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16));
367
368 // Check PLL clocks per RM0456 § 11.4.10
369 let (vco_min, vco_max, out_max) = match voltage_range {
370 VoltageScale::RANGE1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(208)),
371 VoltageScale::RANGE2 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(110)),
372 VoltageScale::RANGE3 => (Hertz::mhz(128), Hertz::mhz(330), Hertz::mhz(55)),
373 VoltageScale::RANGE4 => panic!("PLL is unavailable in voltage range 4"),
374 };
375
376 // Calculate the PLL VCO clock
377 let vco_freq = ref_freq * pll.mul;
378 assert!(vco_freq >= vco_min && vco_freq <= vco_max);
379
380 // Calculate output clocks.
381 let p = pll.divp.map(|div| vco_freq / div);
382 let q = pll.divq.map(|div| vco_freq / div);
383 let r = pll.divr.map(|div| vco_freq / div);
384 for freq in [p, q, r] {
385 if let Some(freq) = freq {
386 assert!(freq <= out_max);
387 }
388 }
389
390 let divr = match instance {
391 PllInstance::Pll1 => RCC.pll1divr(),
392 PllInstance::Pll2 => RCC.pll2divr(),
393 PllInstance::Pll3 => RCC.pll3divr(),
394 };
395 divr.write(|w| {
396 w.set_plln(pll.mul);
397 w.set_pllp(pll.divp.unwrap_or(PllDiv::DIV1));
398 w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1));
399 w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1));
400 });
401
402 let input_range = match ref_freq.0 {
403 ..=8_000_000 => Pllrge::FREQ_4TO8MHZ,
404 _ => Pllrge::FREQ_8TO16MHZ,
405 };
406
407 macro_rules! write_fields {
408 ($w:ident) => {
409 $w.set_pllpen(pll.divp.is_some());
410 $w.set_pllqen(pll.divq.is_some());
411 $w.set_pllren(pll.divr.is_some());
412 $w.set_pllm(pll.prediv);
413 $w.set_pllsrc(pll.source);
414 $w.set_pllrge(input_range);
415 };
416 }
417
418 match instance {
419 PllInstance::Pll1 => RCC.pll1cfgr().write(|w| {
420 // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler
421 // value that results in an output between 4 and 16 MHz for the PWR EPOD boost
422 if r.unwrap() >= Hertz::mhz(55) {
423 // source_clk can be up to 50 MHz, so there's just a few cases:
424 let mboost = match src_freq.0 {
425 ..=16_000_000 => Pllmboost::DIV1, // Bypass, giving EPOD 4-16 MHz
426 ..=32_000_000 => Pllmboost::DIV2, // Divide by 2, giving EPOD 8-16 MHz
427 _ => Pllmboost::DIV4, // Divide by 4, giving EPOD 8-12.5 MHz
428 };
429 w.set_pllmboost(mboost);
430 }
431 write_fields!(w);
432 }),
433 PllInstance::Pll2 => RCC.pll2cfgr().write(|w| {
434 write_fields!(w);
435 }),
436 PllInstance::Pll3 => RCC.pll3cfgr().write(|w| {
437 write_fields!(w);
438 }),
439 }
440
441 // Enable PLL
442 pll_enable(instance, true);
443
444 PllOutput { p, q, r }
445}
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index c0cd91507..8e1779d7c 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -1,88 +1,117 @@
1use stm32_metapac::rcc::vals::{Pllsrc, Sw}; 1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2 2use crate::pac::rcc::regs::Cfgr1;
3pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk};
3use crate::pac::{FLASH, RCC}; 4use crate::pac::{FLASH, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 5use crate::time::Hertz;
6 6
7/// HSI speed 7/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(16_000_000); 8pub const HSI_FREQ: Hertz = Hertz(16_000_000);
9// HSE speed
10pub const HSE_FREQ: Hertz = Hertz(32_000_000);
9 11
10pub use crate::pac::pwr::vals::Vos as VoltageScale; 12#[derive(Clone, Copy, Eq, PartialEq)]
11pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; 13pub struct Hse {
12 14 pub prescaler: HsePrescaler,
13#[derive(Copy, Clone)]
14pub enum ClockSrc {
15 HSE(Hertz),
16 HSI,
17}
18
19#[derive(Clone, Copy, Debug)]
20pub enum PllSource {
21 HSE(Hertz),
22 HSI,
23}
24
25impl Into<Pllsrc> for PllSource {
26 fn into(self) -> Pllsrc {
27 match self {
28 PllSource::HSE(..) => Pllsrc::HSE,
29 PllSource::HSI => Pllsrc::HSI,
30 }
31 }
32}
33
34impl Into<Sw> for ClockSrc {
35 fn into(self) -> Sw {
36 match self {
37 ClockSrc::HSE(..) => Sw::HSE,
38 ClockSrc::HSI => Sw::HSI,
39 }
40 }
41} 15}
42 16
17/// Clocks configuration
43pub struct Config { 18pub struct Config {
44 pub mux: ClockSrc, 19 // base clock sources
20 pub hsi: bool,
21 pub hse: Option<Hse>,
22
23 // sysclk, buses.
24 pub sys: Sysclk,
45 pub ahb_pre: AHBPrescaler, 25 pub ahb_pre: AHBPrescaler,
46 pub apb1_pre: APBPrescaler, 26 pub apb1_pre: APBPrescaler,
47 pub apb2_pre: APBPrescaler, 27 pub apb2_pre: APBPrescaler,
48 pub apb7_pre: APBPrescaler, 28 pub apb7_pre: APBPrescaler,
29
30 // low speed LSI/LSE/RTC
49 pub ls: super::LsConfig, 31 pub ls: super::LsConfig,
32
33 pub voltage_scale: VoltageScale,
34
35 /// Per-peripheral kernel clock selection muxes
36 pub mux: super::mux::ClockMux,
50} 37}
51 38
52impl Default for Config { 39impl Default for Config {
53 fn default() -> Self { 40 #[inline]
54 Self { 41 fn default() -> Config {
55 mux: ClockSrc::HSI, 42 Config {
43 hse: None,
44 hsi: true,
45 sys: Sysclk::HSI,
56 ahb_pre: AHBPrescaler::DIV1, 46 ahb_pre: AHBPrescaler::DIV1,
57 apb1_pre: APBPrescaler::DIV1, 47 apb1_pre: APBPrescaler::DIV1,
58 apb2_pre: APBPrescaler::DIV1, 48 apb2_pre: APBPrescaler::DIV1,
59 apb7_pre: APBPrescaler::DIV1, 49 apb7_pre: APBPrescaler::DIV1,
60 ls: Default::default(), 50 ls: Default::default(),
51 voltage_scale: VoltageScale::RANGE2,
52 mux: Default::default(),
61 } 53 }
62 } 54 }
63} 55}
64 56
57fn hsi_enable() {
58 RCC.cr().modify(|w| w.set_hsion(true));
59 while !RCC.cr().read().hsirdy() {}
60}
61
65pub(crate) unsafe fn init(config: Config) { 62pub(crate) unsafe fn init(config: Config) {
66 let sys_clk = match config.mux { 63 // Switch to HSI to prevent problems with PLL configuration.
67 ClockSrc::HSE(freq) => { 64 if !RCC.cr().read().hsion() {
68 RCC.cr().write(|w| w.set_hseon(true)); 65 hsi_enable()
69 while !RCC.cr().read().hserdy() {} 66 }
67 if RCC.cfgr1().read().sws() != Sysclk::HSI {
68 // Set HSI as a clock source, reset prescalers.
69 RCC.cfgr1().write_value(Cfgr1::default());
70 // Wait for clock switch status bits to change.
71 while RCC.cfgr1().read().sws() != Sysclk::HSI {}
72 }
70 73
71 freq 74 // Set voltage scale
72 } 75 crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale));
73 ClockSrc::HSI => { 76 while !crate::pac::PWR.vosr().read().vosrdy() {}
74 RCC.cr().write(|w| w.set_hsion(true));
75 while !RCC.cr().read().hsirdy() {}
76 77
77 HSI_FREQ 78 let rtc = config.ls.init();
78 } 79
80 let hsi = config.hsi.then(|| {
81 hsi_enable();
82
83 HSI_FREQ
84 });
85
86 let hse = config.hse.map(|hse| {
87 RCC.cr().write(|w| {
88 w.set_hseon(true);
89 w.set_hsepre(hse.prescaler);
90 });
91 while !RCC.cr().read().hserdy() {}
92
93 HSE_FREQ
94 });
95
96 let sys_clk = match config.sys {
97 Sysclk::HSE => hse.unwrap(),
98 Sysclk::HSI => hsi.unwrap(),
99 Sysclk::_RESERVED_1 => unreachable!(),
100 Sysclk::PLL1_R => todo!(),
79 }; 101 };
80 102
81 // TODO make configurable 103 assert!(sys_clk.0 <= 100_000_000);
82 let power_vos = VoltageScale::RANGE1; 104
105 let hclk1 = sys_clk / config.ahb_pre;
106 let hclk2 = hclk1;
107 let hclk4 = hclk1;
108 // TODO: hclk5
109 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
110 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
111 let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre);
83 112
84 // states and programming delay 113 // Set flash wait states
85 let wait_states = match power_vos { 114 let flash_latency = match config.voltage_scale {
86 VoltageScale::RANGE1 => match sys_clk.0 { 115 VoltageScale::RANGE1 => match sys_clk.0 {
87 ..=32_000_000 => 0, 116 ..=32_000_000 => 0,
88 ..=64_000_000 => 1, 117 ..=64_000_000 => 1,
@@ -97,13 +126,24 @@ pub(crate) unsafe fn init(config: Config) {
97 }, 126 },
98 }; 127 };
99 128
100 FLASH.acr().modify(|w| { 129 FLASH.acr().modify(|w| w.set_latency(flash_latency));
101 w.set_latency(wait_states); 130 while FLASH.acr().read().latency() != flash_latency {}
102 }); 131
132 // Set sram wait states
133 let _sram_latency = match config.voltage_scale {
134 VoltageScale::RANGE1 => 0,
135 VoltageScale::RANGE2 => match sys_clk.0 {
136 ..=12_000_000 => 0,
137 ..=16_000_000 => 1,
138 _ => 2,
139 },
140 };
141 // TODO: Set the SRAM wait states
103 142
104 RCC.cfgr1().modify(|w| { 143 RCC.cfgr1().modify(|w| {
105 w.set_sw(config.mux.into()); 144 w.set_sw(config.sys);
106 }); 145 });
146 while RCC.cfgr1().read().sws() != config.sys {}
107 147
108 RCC.cfgr2().modify(|w| { 148 RCC.cfgr2().modify(|w| {
109 w.set_hpre(config.ahb_pre); 149 w.set_hpre(config.ahb_pre);
@@ -111,45 +151,25 @@ pub(crate) unsafe fn init(config: Config) {
111 w.set_ppre2(config.apb2_pre); 151 w.set_ppre2(config.apb2_pre);
112 }); 152 });
113 153
114 RCC.cfgr3().modify(|w| { 154 config.mux.init();
115 w.set_ppre7(config.apb7_pre); 155
116 }); 156 set_clocks!(
117 157 sys: Some(sys_clk),
118 let ahb_freq = sys_clk / config.ahb_pre; 158 hclk1: Some(hclk1),
119 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 159 hclk2: Some(hclk2),
120 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 160 hclk4: Some(hclk4),
121 pre => { 161 pclk1: Some(pclk1),
122 let freq = ahb_freq / pre; 162 pclk2: Some(pclk2),
123 (freq, freq * 2u32) 163 pclk7: Some(pclk7),
124 } 164 pclk1_tim: Some(pclk1_tim),
125 }; 165 pclk2_tim: Some(pclk2_tim),
126 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 166 rtc: rtc,
127 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 167 hse: hse,
128 pre => { 168 hsi: hsi,
129 let freq = ahb_freq / pre; 169
130 (freq, freq * 2u32) 170 // TODO
131 } 171 lse: None,
132 }; 172 lsi: None,
133 let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre { 173 pll1_q: None,
134 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 174 );
135 pre => {
136 let freq = ahb_freq / pre;
137 (freq, freq * 2u32)
138 }
139 };
140
141 let rtc = config.ls.init();
142
143 set_freqs(Clocks {
144 sys: sys_clk,
145 hclk1: ahb_freq,
146 hclk2: ahb_freq,
147 hclk4: ahb_freq,
148 pclk1: apb1_freq,
149 pclk2: apb2_freq,
150 pclk7: apb7_freq,
151 pclk1_tim: apb1_tim_freq,
152 pclk2_tim: apb2_tim_freq,
153 rtc,
154 });
155} 175}
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index 5e647612c..02f96f8a9 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -1,5 +1,6 @@
1//! Serial Audio Interface (SAI) 1//! Serial Audio Interface (SAI)
2#![macro_use] 2#![macro_use]
3#![cfg_attr(gpdma, allow(unused))]
3 4
4use core::marker::PhantomData; 5use core::marker::PhantomData;
5 6
@@ -7,6 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
7 8
8use self::sealed::WhichSubBlock; 9use self::sealed::WhichSubBlock;
9pub use crate::dma::word; 10pub use crate::dma::word;
11#[cfg(not(gpdma))]
10use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 12use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
11use crate::gpio::sealed::{AFType, Pin as _}; 13use crate::gpio::sealed::{AFType, Pin as _};
12use crate::gpio::AnyPin; 14use crate::gpio::AnyPin;
@@ -26,6 +28,7 @@ pub enum Error {
26 Overrun, 28 Overrun,
27} 29}
28 30
31#[cfg(not(gpdma))]
29impl From<ringbuffer::OverrunError> for Error { 32impl From<ringbuffer::OverrunError> for Error {
30 fn from(_: ringbuffer::OverrunError) -> Self { 33 fn from(_: ringbuffer::OverrunError) -> Self {
31 Self::Overrun 34 Self::Overrun
@@ -41,7 +44,7 @@ pub enum Mode {
41} 44}
42 45
43impl Mode { 46impl Mode {
44 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 47 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
45 const fn mode(&self, tx_rx: TxRx) -> vals::Mode { 48 const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
46 match tx_rx { 49 match tx_rx {
47 TxRx::Transmitter => match self { 50 TxRx::Transmitter => match self {
@@ -76,7 +79,7 @@ pub enum SlotSize {
76} 79}
77 80
78impl SlotSize { 81impl SlotSize {
79 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 82 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
80 const fn slotsz(&self) -> vals::Slotsz { 83 const fn slotsz(&self) -> vals::Slotsz {
81 match self { 84 match self {
82 SlotSize::DataSize => vals::Slotsz::DATASIZE, 85 SlotSize::DataSize => vals::Slotsz::DATASIZE,
@@ -99,7 +102,7 @@ pub enum DataSize {
99} 102}
100 103
101impl DataSize { 104impl DataSize {
102 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 105 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
103 const fn ds(&self) -> vals::Ds { 106 const fn ds(&self) -> vals::Ds {
104 match self { 107 match self {
105 DataSize::Data8 => vals::Ds::BIT8, 108 DataSize::Data8 => vals::Ds::BIT8,
@@ -124,7 +127,7 @@ pub enum FifoThreshold {
124} 127}
125 128
126impl FifoThreshold { 129impl FifoThreshold {
127 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 130 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
128 const fn fth(&self) -> vals::Fth { 131 const fn fth(&self) -> vals::Fth {
129 match self { 132 match self {
130 FifoThreshold::Empty => vals::Fth::EMPTY, 133 FifoThreshold::Empty => vals::Fth::EMPTY,
@@ -145,7 +148,7 @@ pub enum MuteValue {
145} 148}
146 149
147impl MuteValue { 150impl MuteValue {
148 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 151 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
149 const fn muteval(&self) -> vals::Muteval { 152 const fn muteval(&self) -> vals::Muteval {
150 match self { 153 match self {
151 MuteValue::Zero => vals::Muteval::SENDZERO, 154 MuteValue::Zero => vals::Muteval::SENDZERO,
@@ -164,7 +167,7 @@ pub enum Protocol {
164} 167}
165 168
166impl Protocol { 169impl Protocol {
167 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 170 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
168 const fn prtcfg(&self) -> vals::Prtcfg { 171 const fn prtcfg(&self) -> vals::Prtcfg {
169 match self { 172 match self {
170 Protocol::Free => vals::Prtcfg::FREE, 173 Protocol::Free => vals::Prtcfg::FREE,
@@ -183,7 +186,7 @@ pub enum SyncInput {
183 /// Syncs with the other A/B sub-block within the SAI unit 186 /// Syncs with the other A/B sub-block within the SAI unit
184 Internal, 187 Internal,
185 /// Syncs with a sub-block in the other SAI unit 188 /// Syncs with a sub-block in the other SAI unit
186 #[cfg(sai_v4)] 189 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
187 External(SyncInputInstance), 190 External(SyncInputInstance),
188} 191}
189 192
@@ -192,14 +195,14 @@ impl SyncInput {
192 match self { 195 match self {
193 SyncInput::None => vals::Syncen::ASYNCHRONOUS, 196 SyncInput::None => vals::Syncen::ASYNCHRONOUS,
194 SyncInput::Internal => vals::Syncen::INTERNAL, 197 SyncInput::Internal => vals::Syncen::INTERNAL,
195 #[cfg(any(sai_v4))] 198 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
196 SyncInput::External(_) => vals::Syncen::EXTERNAL, 199 SyncInput::External(_) => vals::Syncen::EXTERNAL,
197 } 200 }
198 } 201 }
199} 202}
200 203
201/// SAI instance to sync from. 204/// SAI instance to sync from.
202#[cfg(sai_v4)] 205#[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
203#[derive(Copy, Clone, PartialEq)] 206#[derive(Copy, Clone, PartialEq)]
204#[allow(missing_docs)] 207#[allow(missing_docs)]
205pub enum SyncInputInstance { 208pub enum SyncInputInstance {
@@ -222,7 +225,7 @@ pub enum StereoMono {
222} 225}
223 226
224impl StereoMono { 227impl StereoMono {
225 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 228 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
226 const fn mono(&self) -> vals::Mono { 229 const fn mono(&self) -> vals::Mono {
227 match self { 230 match self {
228 StereoMono::Stereo => vals::Mono::STEREO, 231 StereoMono::Stereo => vals::Mono::STEREO,
@@ -241,7 +244,7 @@ pub enum BitOrder {
241} 244}
242 245
243impl BitOrder { 246impl BitOrder {
244 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 247 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
245 const fn lsbfirst(&self) -> vals::Lsbfirst { 248 const fn lsbfirst(&self) -> vals::Lsbfirst {
246 match self { 249 match self {
247 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, 250 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST,
@@ -260,7 +263,7 @@ pub enum FrameSyncOffset {
260} 263}
261 264
262impl FrameSyncOffset { 265impl FrameSyncOffset {
263 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 266 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
264 const fn fsoff(&self) -> vals::Fsoff { 267 const fn fsoff(&self) -> vals::Fsoff {
265 match self { 268 match self {
266 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, 269 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST,
@@ -279,7 +282,7 @@ pub enum FrameSyncPolarity {
279} 282}
280 283
281impl FrameSyncPolarity { 284impl FrameSyncPolarity {
282 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 285 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
283 const fn fspol(&self) -> vals::Fspol { 286 const fn fspol(&self) -> vals::Fspol {
284 match self { 287 match self {
285 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, 288 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE,
@@ -297,7 +300,7 @@ pub enum FrameSyncDefinition {
297} 300}
298 301
299impl FrameSyncDefinition { 302impl FrameSyncDefinition {
300 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 303 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
301 const fn fsdef(&self) -> bool { 304 const fn fsdef(&self) -> bool {
302 match self { 305 match self {
303 FrameSyncDefinition::StartOfFrame => false, 306 FrameSyncDefinition::StartOfFrame => false,
@@ -315,7 +318,7 @@ pub enum ClockStrobe {
315} 318}
316 319
317impl ClockStrobe { 320impl ClockStrobe {
318 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 321 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
319 const fn ckstr(&self) -> vals::Ckstr { 322 const fn ckstr(&self) -> vals::Ckstr {
320 match self { 323 match self {
321 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, 324 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE,
@@ -333,7 +336,7 @@ pub enum ComplementFormat {
333} 336}
334 337
335impl ComplementFormat { 338impl ComplementFormat {
336 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 339 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
337 const fn cpl(&self) -> vals::Cpl { 340 const fn cpl(&self) -> vals::Cpl {
338 match self { 341 match self {
339 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, 342 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT,
@@ -352,7 +355,7 @@ pub enum Companding {
352} 355}
353 356
354impl Companding { 357impl Companding {
355 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 358 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
356 const fn comp(&self) -> vals::Comp { 359 const fn comp(&self) -> vals::Comp {
357 match self { 360 match self {
358 Companding::None => vals::Comp::NOCOMPANDING, 361 Companding::None => vals::Comp::NOCOMPANDING,
@@ -371,7 +374,7 @@ pub enum OutputDrive {
371} 374}
372 375
373impl OutputDrive { 376impl OutputDrive {
374 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 377 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
375 const fn outdriv(&self) -> vals::Outdriv { 378 const fn outdriv(&self) -> vals::Outdriv {
376 match self { 379 match self {
377 OutputDrive::OnStart => vals::Outdriv::ONSTART, 380 OutputDrive::OnStart => vals::Outdriv::ONSTART,
@@ -404,7 +407,7 @@ pub enum MasterClockDivider {
404} 407}
405 408
406impl MasterClockDivider { 409impl MasterClockDivider {
407 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 410 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
408 const fn mckdiv(&self) -> u8 { 411 const fn mckdiv(&self) -> u8 {
409 match self { 412 match self {
410 MasterClockDivider::MasterClockDisabled => 0, 413 MasterClockDivider::MasterClockDisabled => 0,
@@ -501,12 +504,12 @@ impl Config {
501 } 504 }
502} 505}
503 506
504enum RingBuffer<'d, C: Channel, W: word::Word> { 507#[cfg(not(gpdma))]
505 Writable(WritableRingBuffer<'d, C, W>), 508enum RingBuffer<'d, W: word::Word> {
506 Readable(ReadableRingBuffer<'d, C, W>), 509 Writable(WritableRingBuffer<'d, W>),
510 Readable(ReadableRingBuffer<'d, W>),
507} 511}
508 512
509#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
510fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W { 513fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W {
511 let ch = w.ch(sub_block as usize); 514 let ch = w.ch(sub_block as usize);
512 ch.dr().as_ptr() as _ 515 ch.dr().as_ptr() as _
@@ -528,13 +531,14 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) {
528 ) 531 )
529} 532}
530 533
531fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( 534#[cfg(not(gpdma))]
532 dma: impl Peripheral<P = C> + 'd, 535fn get_ring_buffer<'d, T: Instance, W: word::Word>(
536 dma: impl Peripheral<P = impl Channel> + 'd,
533 dma_buf: &'d mut [W], 537 dma_buf: &'d mut [W],
534 request: Request, 538 request: Request,
535 sub_block: WhichSubBlock, 539 sub_block: WhichSubBlock,
536 tx_rx: TxRx, 540 tx_rx: TxRx,
537) -> RingBuffer<'d, C, W> { 541) -> RingBuffer<'d, W> {
538 let opts = TransferOptions { 542 let opts = TransferOptions {
539 half_transfer_ir: true, 543 half_transfer_ir: true,
540 //the new_write() and new_read() always use circular mode 544 //the new_write() and new_read() always use circular mode
@@ -554,12 +558,12 @@ fn update_synchronous_config(config: &mut Config) {
554 config.mode = Mode::Slave; 558 config.mode = Mode::Slave;
555 config.sync_output = false; 559 config.sync_output = false;
556 560
557 #[cfg(any(sai_v1, sai_v2, sai_v3))] 561 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm))]
558 { 562 {
559 config.sync_input = SyncInput::Internal; 563 config.sync_input = SyncInput::Internal;
560 } 564 }
561 565
562 #[cfg(any(sai_v4))] 566 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
563 { 567 {
564 //this must either be Internal or External 568 //this must either be Internal or External
565 //The asynchronous sub-block on the same SAI needs to enable sync_output 569 //The asynchronous sub-block on the same SAI needs to enable sync_output
@@ -593,17 +597,21 @@ pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (S
593} 597}
594 598
595/// SAI sub-block driver. 599/// SAI sub-block driver.
596pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { 600pub struct Sai<'d, T: Instance, W: word::Word> {
597 _peri: PeripheralRef<'d, T>, 601 _peri: PeripheralRef<'d, T>,
598 sd: Option<PeripheralRef<'d, AnyPin>>, 602 sd: Option<PeripheralRef<'d, AnyPin>>,
599 fs: Option<PeripheralRef<'d, AnyPin>>, 603 fs: Option<PeripheralRef<'d, AnyPin>>,
600 sck: Option<PeripheralRef<'d, AnyPin>>, 604 sck: Option<PeripheralRef<'d, AnyPin>>,
601 mclk: Option<PeripheralRef<'d, AnyPin>>, 605 mclk: Option<PeripheralRef<'d, AnyPin>>,
602 ring_buffer: RingBuffer<'d, C, W>, 606 #[cfg(gpdma)]
607 ring_buffer: PhantomData<W>,
608 #[cfg(not(gpdma))]
609 ring_buffer: RingBuffer<'d, W>,
603 sub_block: WhichSubBlock, 610 sub_block: WhichSubBlock,
604} 611}
605 612
606impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { 613#[cfg(not(gpdma))]
614impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
607 /// Create a new SAI driver in asynchronous mode with MCLK. 615 /// Create a new SAI driver in asynchronous mode with MCLK.
608 /// 616 ///
609 /// You can obtain the [`SubBlock`] with [`split_subblocks`]. 617 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
@@ -613,13 +621,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
613 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, 621 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
614 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, 622 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
615 mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd, 623 mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd,
616 dma: impl Peripheral<P = C> + 'd, 624 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd,
617 dma_buf: &'d mut [W], 625 dma_buf: &'d mut [W],
618 mut config: Config, 626 mut config: Config,
619 ) -> Self 627 ) -> Self {
620 where
621 C: Channel + Dma<T, S>,
622 {
623 into_ref!(mclk); 628 into_ref!(mclk);
624 629
625 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); 630 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
@@ -642,13 +647,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
642 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd, 647 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd,
643 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, 648 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
644 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, 649 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
645 dma: impl Peripheral<P = C> + 'd, 650 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd,
646 dma_buf: &'d mut [W], 651 dma_buf: &'d mut [W],
647 config: Config, 652 config: Config,
648 ) -> Self 653 ) -> Self {
649 where
650 C: Channel + Dma<T, S>,
651 {
652 let peri = peri.peri; 654 let peri = peri.peri;
653 into_ref!(peri, dma, sck, sd, fs); 655 into_ref!(peri, dma, sck, sd, fs);
654 656
@@ -671,7 +673,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
671 None, 673 None,
672 Some(sd.map_into()), 674 Some(sd.map_into()),
673 Some(fs.map_into()), 675 Some(fs.map_into()),
674 get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), 676 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
675 config, 677 config,
676 ) 678 )
677 } 679 }
@@ -682,13 +684,10 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
682 pub fn new_synchronous<S: SubBlockInstance>( 684 pub fn new_synchronous<S: SubBlockInstance>(
683 peri: SubBlock<'d, T, S>, 685 peri: SubBlock<'d, T, S>,
684 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, 686 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
685 dma: impl Peripheral<P = C> + 'd, 687 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd,
686 dma_buf: &'d mut [W], 688 dma_buf: &'d mut [W],
687 mut config: Config, 689 mut config: Config,
688 ) -> Self 690 ) -> Self {
689 where
690 C: Channel + Dma<T, S>,
691 {
692 update_synchronous_config(&mut config); 691 update_synchronous_config(&mut config);
693 692
694 let peri = peri.peri; 693 let peri = peri.peri;
@@ -709,7 +708,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
709 None, 708 None,
710 Some(sd.map_into()), 709 Some(sd.map_into()),
711 None, 710 None,
712 get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), 711 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
713 config, 712 config,
714 ) 713 )
715 } 714 }
@@ -721,16 +720,16 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
721 mclk: Option<PeripheralRef<'d, AnyPin>>, 720 mclk: Option<PeripheralRef<'d, AnyPin>>,
722 sd: Option<PeripheralRef<'d, AnyPin>>, 721 sd: Option<PeripheralRef<'d, AnyPin>>,
723 fs: Option<PeripheralRef<'d, AnyPin>>, 722 fs: Option<PeripheralRef<'d, AnyPin>>,
724 ring_buffer: RingBuffer<'d, C, W>, 723 ring_buffer: RingBuffer<'d, W>,
725 config: Config, 724 config: Config,
726 ) -> Self { 725 ) -> Self {
727 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 726 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
728 { 727 {
729 let ch = T::REGS.ch(sub_block as usize); 728 let ch = T::REGS.ch(sub_block as usize);
730 ch.cr1().modify(|w| w.set_saien(false)); 729 ch.cr1().modify(|w| w.set_saien(false));
731 } 730 }
732 731
733 #[cfg(any(sai_v4))] 732 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))]
734 { 733 {
735 if let SyncInput::External(i) = config.sync_input { 734 if let SyncInput::External(i) = config.sync_input {
736 T::REGS.gcr().modify(|w| { 735 T::REGS.gcr().modify(|w| {
@@ -749,7 +748,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
749 } 748 }
750 } 749 }
751 750
752 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 751 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
753 { 752 {
754 let ch = T::REGS.ch(sub_block as usize); 753 let ch = T::REGS.ch(sub_block as usize);
755 ch.cr1().modify(|w| { 754 ch.cr1().modify(|w| {
@@ -830,7 +829,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
830 } 829 }
831 } 830 }
832 831
833 fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool { 832 fn is_transmitter(ring_buffer: &RingBuffer<W>) -> bool {
834 match ring_buffer { 833 match ring_buffer {
835 RingBuffer::Writable(_) => true, 834 RingBuffer::Writable(_) => true,
836 _ => false, 835 _ => false,
@@ -889,7 +888,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
889 } 888 }
890} 889}
891 890
892impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { 891impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> {
893 fn drop(&mut self) { 892 fn drop(&mut self) {
894 let ch = T::REGS.ch(self.sub_block as usize); 893 let ch = T::REGS.ch(self.sub_block as usize);
895 ch.cr1().modify(|w| w.set_saien(false)); 894 ch.cr1().modify(|w| w.set_saien(false));
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index debe26c88..bf1d2ca9b 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -228,10 +228,10 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> {
228} 228}
229 229
230#[cfg(sdmmc_v1)] 230#[cfg(sdmmc_v1)]
231type Transfer<'a, C> = crate::dma::Transfer<'a, C>; 231type Transfer<'a> = crate::dma::Transfer<'a>;
232#[cfg(sdmmc_v2)] 232#[cfg(sdmmc_v2)]
233struct Transfer<'a, C> { 233struct Transfer<'a> {
234 _dummy: core::marker::PhantomData<&'a mut C>, 234 _dummy: PhantomData<&'a ()>,
235} 235}
236 236
237#[cfg(all(sdmmc_v1, dma))] 237#[cfg(all(sdmmc_v1, dma))]
@@ -548,7 +548,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
548 buffer: &'a mut [u32], 548 buffer: &'a mut [u32],
549 length_bytes: u32, 549 length_bytes: u32,
550 block_size: u8, 550 block_size: u8,
551 ) -> Transfer<'a, Dma> { 551 ) -> Transfer<'a> {
552 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 552 assert!(block_size <= 14, "Block size up to 2^14 bytes");
553 let regs = T::regs(); 553 let regs = T::regs();
554 554
@@ -596,12 +596,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
596 /// # Safety 596 /// # Safety
597 /// 597 ///
598 /// `buffer` must be valid for the whole transfer and word aligned 598 /// `buffer` must be valid for the whole transfer and word aligned
599 fn prepare_datapath_write<'a>( 599 fn prepare_datapath_write<'a>(&'a mut self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> {
600 &'a mut self,
601 buffer: &'a [u32],
602 length_bytes: u32,
603 block_size: u8,
604 ) -> Transfer<'a, Dma> {
605 assert!(block_size <= 14, "Block size up to 2^14 bytes"); 600 assert!(block_size <= 14, "Block size up to 2^14 bytes");
606 let regs = T::regs(); 601 let regs = T::regs();
607 602
@@ -670,7 +665,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
670 _ => panic!("Invalid Bus Width"), 665 _ => panic!("Invalid Bus Width"),
671 }; 666 };
672 667
673 let ker_ck = T::kernel_clk(); 668 let ker_ck = T::frequency();
674 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; 669 let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?;
675 670
676 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 671 // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
@@ -1023,7 +1018,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1023 /// specified frequency. 1018 /// specified frequency.
1024 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { 1019 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
1025 let regs = T::regs(); 1020 let regs = T::regs();
1026 let ker_ck = T::kernel_clk(); 1021 let ker_ck = T::frequency();
1027 1022
1028 let bus_width = match self.d3.is_some() { 1023 let bus_width = match self.d3.is_some() {
1029 true => BusWidth::Four, 1024 true => BusWidth::Four,
@@ -1429,7 +1424,6 @@ pub(crate) mod sealed {
1429 1424
1430 fn regs() -> RegBlock; 1425 fn regs() -> RegBlock;
1431 fn state() -> &'static AtomicWaker; 1426 fn state() -> &'static AtomicWaker;
1432 fn kernel_clk() -> Hertz;
1433 } 1427 }
1434 1428
1435 pub trait Pins<T: Instance> {} 1429 pub trait Pins<T: Instance> {}
@@ -1461,61 +1455,6 @@ pub trait SdmmcDma<T: Instance> {}
1461#[cfg(sdmmc_v2)] 1455#[cfg(sdmmc_v2)]
1462impl<T: Instance> SdmmcDma<T> for NoDma {} 1456impl<T: Instance> SdmmcDma<T> for NoDma {}
1463 1457
1464cfg_if::cfg_if! {
1465 // TODO, these could not be implemented, because required clocks are not exposed in RCC:
1466 // - H7 uses pll1_q_ck or pll2_r_ck depending on SDMMCSEL
1467 // - L1 uses pll48
1468 // - L4 uses clk48(pll48)
1469 // - L4+, L5, U5 uses clk48(pll48) or PLLSAI3CLK(PLLP) depending on SDMMCSEL
1470 if #[cfg(stm32f1)] {
1471 // F1 uses AHB1(HCLK), which is correct in PAC
1472 macro_rules! kernel_clk {
1473 ($inst:ident) => {
1474 <peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
1475 }
1476 }
1477 } else if #[cfg(any(stm32f2, stm32f4))] {
1478 // F2, F4 always use pll48
1479 macro_rules! kernel_clk {
1480 ($inst:ident) => {
1481 critical_section::with(|_| unsafe {
1482 unwrap!(crate::rcc::get_freqs().pll1_q)
1483 })
1484 }
1485 }
1486 } else if #[cfg(stm32f7)] {
1487 macro_rules! kernel_clk {
1488 (SDMMC1) => {
1489 critical_section::with(|_| unsafe {
1490 let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc1sel();
1491 if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS {
1492 crate::rcc::get_freqs().sys
1493 } else {
1494 unwrap!(crate::rcc::get_freqs().pll1_q)
1495 }
1496 })
1497 };
1498 (SDMMC2) => {
1499 critical_section::with(|_| unsafe {
1500 let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc2sel();
1501 if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS {
1502 crate::rcc::get_freqs().sys
1503 } else {
1504 unwrap!(crate::rcc::get_freqs().pll1_q)
1505 }
1506 })
1507 };
1508 }
1509 } else {
1510 // Use default peripheral clock and hope it works
1511 macro_rules! kernel_clk {
1512 ($inst:ident) => {
1513 <peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
1514 }
1515 }
1516 }
1517}
1518
1519foreach_peripheral!( 1458foreach_peripheral!(
1520 (sdmmc, $inst:ident) => { 1459 (sdmmc, $inst:ident) => {
1521 impl sealed::Instance for peripherals::$inst { 1460 impl sealed::Instance for peripherals::$inst {
@@ -1529,10 +1468,6 @@ foreach_peripheral!(
1529 static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); 1468 static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new();
1530 &WAKER 1469 &WAKER
1531 } 1470 }
1532
1533 fn kernel_clk() -> Hertz {
1534 kernel_clk!($inst)
1535 }
1536 } 1471 }
1537 1472
1538 impl Instance for peripherals::$inst {} 1473 impl Instance for peripherals::$inst {}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 23f027e70..172bc8112 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1005,8 +1005,8 @@ mod word_impl {
1005 1005
1006 pub type Config = vals::Dff; 1006 pub type Config = vals::Dff;
1007 1007
1008 impl_word!(u8, vals::Dff::EIGHTBIT); 1008 impl_word!(u8, vals::Dff::BITS8);
1009 impl_word!(u16, vals::Dff::SIXTEENBIT); 1009 impl_word!(u16, vals::Dff::BITS16);
1010} 1010}
1011 1011
1012#[cfg(spi_v2)] 1012#[cfg(spi_v2)]
@@ -1015,19 +1015,19 @@ mod word_impl {
1015 1015
1016 pub type Config = (vals::Ds, vals::Frxth); 1016 pub type Config = (vals::Ds, vals::Frxth);
1017 1017
1018 impl_word!(word::U4, (vals::Ds::FOURBIT, vals::Frxth::QUARTER)); 1018 impl_word!(word::U4, (vals::Ds::BITS4, vals::Frxth::QUARTER));
1019 impl_word!(word::U5, (vals::Ds::FIVEBIT, vals::Frxth::QUARTER)); 1019 impl_word!(word::U5, (vals::Ds::BITS5, vals::Frxth::QUARTER));
1020 impl_word!(word::U6, (vals::Ds::SIXBIT, vals::Frxth::QUARTER)); 1020 impl_word!(word::U6, (vals::Ds::BITS6, vals::Frxth::QUARTER));
1021 impl_word!(word::U7, (vals::Ds::SEVENBIT, vals::Frxth::QUARTER)); 1021 impl_word!(word::U7, (vals::Ds::BITS7, vals::Frxth::QUARTER));
1022 impl_word!(u8, (vals::Ds::EIGHTBIT, vals::Frxth::QUARTER)); 1022 impl_word!(u8, (vals::Ds::BITS8, vals::Frxth::QUARTER));
1023 impl_word!(word::U9, (vals::Ds::NINEBIT, vals::Frxth::HALF)); 1023 impl_word!(word::U9, (vals::Ds::BITS9, vals::Frxth::HALF));
1024 impl_word!(word::U10, (vals::Ds::TENBIT, vals::Frxth::HALF)); 1024 impl_word!(word::U10, (vals::Ds::BITS10, vals::Frxth::HALF));
1025 impl_word!(word::U11, (vals::Ds::ELEVENBIT, vals::Frxth::HALF)); 1025 impl_word!(word::U11, (vals::Ds::BITS11, vals::Frxth::HALF));
1026 impl_word!(word::U12, (vals::Ds::TWELVEBIT, vals::Frxth::HALF)); 1026 impl_word!(word::U12, (vals::Ds::BITS12, vals::Frxth::HALF));
1027 impl_word!(word::U13, (vals::Ds::THIRTEENBIT, vals::Frxth::HALF)); 1027 impl_word!(word::U13, (vals::Ds::BITS13, vals::Frxth::HALF));
1028 impl_word!(word::U14, (vals::Ds::FOURTEENBIT, vals::Frxth::HALF)); 1028 impl_word!(word::U14, (vals::Ds::BITS14, vals::Frxth::HALF));
1029 impl_word!(word::U15, (vals::Ds::FIFTEENBIT, vals::Frxth::HALF)); 1029 impl_word!(word::U15, (vals::Ds::BITS15, vals::Frxth::HALF));
1030 impl_word!(u16, (vals::Ds::SIXTEENBIT, vals::Frxth::HALF)); 1030 impl_word!(u16, (vals::Ds::BITS16, vals::Frxth::HALF));
1031} 1031}
1032 1032
1033#[cfg(any(spi_v3, spi_v4, spi_v5))] 1033#[cfg(any(spi_v3, spi_v4, spi_v5))]
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 320b29ddb..37b2e7526 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -1,3 +1,5 @@
1#![allow(non_snake_case)]
2
1use core::cell::Cell; 3use core::cell::Cell;
2use core::convert::TryInto; 4use core::convert::TryInto;
3use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; 5use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
@@ -14,7 +16,9 @@ use crate::pac::timer::vals;
14use crate::rcc::sealed::RccPeripheral; 16use crate::rcc::sealed::RccPeripheral;
15#[cfg(feature = "low-power")] 17#[cfg(feature = "low-power")]
16use crate::rtc::Rtc; 18use crate::rtc::Rtc;
17use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; 19#[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))]
20use crate::timer::sealed::AdvancedControlInstance;
21use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance};
18use crate::{interrupt, peripherals}; 22use crate::{interrupt, peripherals};
19 23
20// NOTE regarding ALARM_COUNT: 24// NOTE regarding ALARM_COUNT:
@@ -22,18 +26,22 @@ use crate::{interrupt, peripherals};
22// As of 2023-12-04, this driver is implemented using CC1 as the halfway rollover interrupt, and any 26// As of 2023-12-04, this driver is implemented using CC1 as the halfway rollover interrupt, and any
23// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST 27// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST
24// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not 28// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not
25// candidates for use as an embassy-time driver provider. 29// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.)
26// 30//
27// The values of ALARM_COUNT below are not the TOTAL CC registers available, but rather the number 31// The values of ALARM_COUNT below are not the TOTAL CC registers available, but rather the number
28// available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers: 32// available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers:
29// CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3. 33// CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3.
30 34
31#[cfg(not(any(time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22)))] 35cfg_if::cfg_if! {
32const ALARM_COUNT: usize = 3; 36 if #[cfg(any(time_driver_tim9, time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] {
33 37 const ALARM_COUNT: usize = 1;
34#[cfg(any(time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] 38 } else {
35const ALARM_COUNT: usize = 1; 39 const ALARM_COUNT: usize = 3;
40 }
41}
36 42
43#[cfg(time_driver_tim1)]
44type T = peripherals::TIM1;
37#[cfg(time_driver_tim2)] 45#[cfg(time_driver_tim2)]
38type T = peripherals::TIM2; 46type T = peripherals::TIM2;
39#[cfg(time_driver_tim3)] 47#[cfg(time_driver_tim3)]
@@ -42,20 +50,42 @@ type T = peripherals::TIM3;
42type T = peripherals::TIM4; 50type T = peripherals::TIM4;
43#[cfg(time_driver_tim5)] 51#[cfg(time_driver_tim5)]
44type T = peripherals::TIM5; 52type T = peripherals::TIM5;
53#[cfg(time_driver_tim8)]
54type T = peripherals::TIM8;
45#[cfg(time_driver_tim9)] 55#[cfg(time_driver_tim9)]
46type T = peripherals::TIM9; 56type T = peripherals::TIM9;
47#[cfg(time_driver_tim11)]
48type T = peripherals::TIM11;
49#[cfg(time_driver_tim12)] 57#[cfg(time_driver_tim12)]
50type T = peripherals::TIM12; 58type T = peripherals::TIM12;
51#[cfg(time_driver_tim15)] 59#[cfg(time_driver_tim15)]
52type T = peripherals::TIM15; 60type T = peripherals::TIM15;
61#[cfg(time_driver_tim20)]
62type T = peripherals::TIM20;
53#[cfg(time_driver_tim21)] 63#[cfg(time_driver_tim21)]
54type T = peripherals::TIM21; 64type T = peripherals::TIM21;
55#[cfg(time_driver_tim22)] 65#[cfg(time_driver_tim22)]
56type T = peripherals::TIM22; 66type T = peripherals::TIM22;
67#[cfg(time_driver_tim23)]
68type T = peripherals::TIM23;
69#[cfg(time_driver_tim24)]
70type T = peripherals::TIM24;
57 71
58foreach_interrupt! { 72foreach_interrupt! {
73 (TIM1, timer, $block:ident, UP, $irq:ident) => {
74 #[cfg(time_driver_tim1)]
75 #[cfg(feature = "rt")]
76 #[interrupt]
77 fn $irq() {
78 DRIVER.on_interrupt()
79 }
80 };
81 (TIM1, timer, $block:ident, CC, $irq:ident) => {
82 #[cfg(time_driver_tim1)]
83 #[cfg(feature = "rt")]
84 #[interrupt]
85 fn $irq() {
86 DRIVER.on_interrupt()
87 }
88 };
59 (TIM2, timer, $block:ident, UP, $irq:ident) => { 89 (TIM2, timer, $block:ident, UP, $irq:ident) => {
60 #[cfg(time_driver_tim2)] 90 #[cfg(time_driver_tim2)]
61 #[cfg(feature = "rt")] 91 #[cfg(feature = "rt")]
@@ -88,16 +118,24 @@ foreach_interrupt! {
88 DRIVER.on_interrupt() 118 DRIVER.on_interrupt()
89 } 119 }
90 }; 120 };
91 (TIM9, timer, $block:ident, UP, $irq:ident) => { 121 (TIM8, timer, $block:ident, UP, $irq:ident) => {
92 #[cfg(time_driver_tim9)] 122 #[cfg(time_driver_tim8)]
93 #[cfg(feature = "rt")] 123 #[cfg(feature = "rt")]
94 #[interrupt] 124 #[interrupt]
95 fn $irq() { 125 fn $irq() {
96 DRIVER.on_interrupt() 126 DRIVER.on_interrupt()
97 } 127 }
98 }; 128 };
99 (TIM11, timer, $block:ident, UP, $irq:ident) => { 129 (TIM8, timer, $block:ident, CC, $irq:ident) => {
100 #[cfg(time_driver_tim11)] 130 #[cfg(time_driver_tim8)]
131 #[cfg(feature = "rt")]
132 #[interrupt]
133 fn $irq() {
134 DRIVER.on_interrupt()
135 }
136 };
137 (TIM9, timer, $block:ident, UP, $irq:ident) => {
138 #[cfg(time_driver_tim9)]
101 #[cfg(feature = "rt")] 139 #[cfg(feature = "rt")]
102 #[interrupt] 140 #[interrupt]
103 fn $irq() { 141 fn $irq() {
@@ -120,6 +158,22 @@ foreach_interrupt! {
120 DRIVER.on_interrupt() 158 DRIVER.on_interrupt()
121 } 159 }
122 }; 160 };
161 (TIM20, timer, $block:ident, UP, $irq:ident) => {
162 #[cfg(time_driver_tim20)]
163 #[cfg(feature = "rt")]
164 #[interrupt]
165 fn $irq() {
166 DRIVER.on_interrupt()
167 }
168 };
169 (TIM20, timer, $block:ident, CC, $irq:ident) => {
170 #[cfg(time_driver_tim20)]
171 #[cfg(feature = "rt")]
172 #[interrupt]
173 fn $irq() {
174 DRIVER.on_interrupt()
175 }
176 };
123 (TIM21, timer, $block:ident, UP, $irq:ident) => { 177 (TIM21, timer, $block:ident, UP, $irq:ident) => {
124 #[cfg(time_driver_tim21)] 178 #[cfg(time_driver_tim21)]
125 #[cfg(feature = "rt")] 179 #[cfg(feature = "rt")]
@@ -136,6 +190,22 @@ foreach_interrupt! {
136 DRIVER.on_interrupt() 190 DRIVER.on_interrupt()
137 } 191 }
138 }; 192 };
193 (TIM23, timer, $block:ident, UP, $irq:ident) => {
194 #[cfg(time_driver_tim23)]
195 #[cfg(feature = "rt")]
196 #[interrupt]
197 fn $irq() {
198 DRIVER.on_interrupt()
199 }
200 };
201 (TIM24, timer, $block:ident, UP, $irq:ident) => {
202 #[cfg(time_driver_tim24)]
203 #[cfg(feature = "rt")]
204 #[interrupt]
205 fn $irq() {
206 DRIVER.on_interrupt()
207 }
208 };
139} 209}
140 210
141// Clock timekeeping works with something we call "periods", which are time intervals 211// Clock timekeeping works with something we call "periods", which are time intervals
@@ -234,8 +304,16 @@ impl RtcDriver {
234 w.set_ccie(0, true); 304 w.set_ccie(0, true);
235 }); 305 });
236 306
237 <T as BasicInstance>::Interrupt::unpend(); 307 <T as CoreInstance>::Interrupt::unpend();
238 unsafe { <T as BasicInstance>::Interrupt::enable() }; 308 unsafe { <T as CoreInstance>::Interrupt::enable() };
309
310 #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))]
311 {
312 <T as AdvancedControlInstance>::CaptureCompareInterrupt::unpend();
313 unsafe {
314 <T as AdvancedControlInstance>::CaptureCompareInterrupt::enable();
315 }
316 }
239 317
240 r.cr1().modify(|w| w.set_cen(true)); 318 r.cr1().modify(|w| w.set_cen(true));
241 } 319 }
@@ -251,7 +329,7 @@ impl RtcDriver {
251 // Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT. 329 // Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT.
252 // Other approaches such as writing all zeros, or RMWing won't work, they can 330 // Other approaches such as writing all zeros, or RMWing won't work, they can
253 // miss interrupts. 331 // miss interrupts.
254 r.sr().write_value(regs::SrGp(!sr.0)); 332 r.sr().write_value(regs::SrGp16(!sr.0));
255 333
256 // Overflow 334 // Overflow
257 if sr.uif() { 335 if sr.uif() {
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 71d7110b5..72f1ec864 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -23,7 +23,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
23 23
24macro_rules! complementary_channel_impl { 24macro_rules! complementary_channel_impl {
25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
26 impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { 26 impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
27 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 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 { 28 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
29 into_ref!(pin); 29 into_ref!(pin);
@@ -54,6 +54,7 @@ pub struct ComplementaryPwm<'d, T> {
54 54
55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver. 56 /// Create a new complementary PWM driver.
57 #[allow(clippy::too_many_arguments)]
57 pub fn new( 58 pub fn new(
58 tim: impl Peripheral<P = T> + 'd, 59 tim: impl Peripheral<P = T> + 'd,
59 _ch1: Option<PwmPin<'d, T, Ch1>>, 60 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -83,14 +84,13 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
83 84
84 this.inner.enable_outputs(); 85 this.inner.enable_outputs();
85 86
86 this.inner 87 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
87 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); 88 .iter()
88 this.inner 89 .for_each(|&channel| {
89 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); 90 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
90 this.inner 91 this.inner.set_output_compare_preload(channel, true);
91 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); 92 });
92 this.inner 93
93 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
94 this 94 this
95 } 95 }
96 96
@@ -165,7 +165,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C
165 } 165 }
166 166
167 fn get_period(&self) -> Self::Time { 167 fn get_period(&self) -> Self::Time {
168 self.inner.get_frequency().into() 168 self.inner.get_frequency()
169 } 169 }
170 170
171 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 171 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index d07fd2776..8530c5229 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,5 +1,37 @@
1//! Timers, PWM, quadrature decoder. 1//! Timers, PWM, quadrature decoder.
2 2//!
3
4//! Timer inheritance
5//!
6
7// sealed:
8//
9// Core -------------------------> 1CH -------------------------> 1CH_CMP
10// | | ^ |
11// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV
12// | | | ^ | | ^ ^
13// | | +------|--|--------------|-----------+ |
14// | +--------------------+ +--------------|-----------|---------+
15// | | | |
16// | +--------------------------------------|-----------+
17// +----------------------------------------------------+
18
19//! ```text
20//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance
21//! |
22//! +--> CaptureCompare32bitInstance
23//! ```
24//!
25//! Mapping:
26//!
27//! | trait | timer |
28//! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- |
29//! | [BasicInstance] | Basic Timer |
30//! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer |
31//! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer |
32//! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer |
33
34#[cfg(not(stm32l0))]
3pub mod complementary_pwm; 35pub mod complementary_pwm;
4pub mod qei; 36pub mod qei;
5pub mod simple_pwm; 37pub mod simple_pwm;
@@ -19,32 +51,32 @@ pub mod low_level {
19pub(crate) mod sealed { 51pub(crate) mod sealed {
20 use super::*; 52 use super::*;
21 53
22 /// Basic 16-bit timer instance. 54 /// Virtual Core 16-bit timer instance.
23 pub trait Basic16bitInstance: RccPeripheral { 55 pub trait CoreInstance: RccPeripheral {
24 /// Interrupt for this timer. 56 /// Interrupt for this timer.
25 type Interrupt: interrupt::typelevel::Interrupt; 57 type Interrupt: interrupt::typelevel::Interrupt;
26 58
27 /// Get access to the basic 16bit timer registers. 59 /// Get access to the virutal core 16bit timer registers.
28 /// 60 ///
29 /// Note: This works even if the timer is more capable, because registers 61 /// 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 62 /// 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 63 /// for a given set of capabilities, and having it transparently work with
32 /// more capable timers. 64 /// more capable timers.
33 fn regs() -> crate::pac::timer::TimBasic; 65 fn regs_core() -> crate::pac::timer::TimCore;
34 66
35 /// Start the timer. 67 /// Start the timer.
36 fn start(&mut self) { 68 fn start(&self) {
37 Self::regs().cr1().modify(|r| r.set_cen(true)); 69 Self::regs_core().cr1().modify(|r| r.set_cen(true));
38 } 70 }
39 71
40 /// Stop the timer. 72 /// Stop the timer.
41 fn stop(&mut self) { 73 fn stop(&self) {
42 Self::regs().cr1().modify(|r| r.set_cen(false)); 74 Self::regs_core().cr1().modify(|r| r.set_cen(false));
43 } 75 }
44 76
45 /// Reset the counter value to 0 77 /// Reset the counter value to 0
46 fn reset(&mut self) { 78 fn reset(&self) {
47 Self::regs().cnt().write(|r| r.set_cnt(0)); 79 Self::regs_core().cnt().write(|r| r.set_cnt(0));
48 } 80 }
49 81
50 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. 82 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
@@ -53,7 +85,7 @@ pub(crate) mod sealed {
53 /// the timer counter will wrap around at the same frequency as is being set. 85 /// the timer counter will wrap around at the same frequency as is being set.
54 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved 86 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
55 /// because it needs to count up and down. 87 /// because it needs to count up and down.
56 fn set_frequency(&mut self, frequency: Hertz) { 88 fn set_frequency(&self, frequency: Hertz) {
57 let f = frequency.0; 89 let f = frequency.0;
58 let timer_f = Self::frequency().0; 90 let timer_f = Self::frequency().0;
59 assert!(f > 0); 91 assert!(f > 0);
@@ -64,7 +96,7 @@ pub(crate) mod sealed {
64 // the timer counts `0..=arr`, we want it to count `0..divide_by` 96 // the timer counts `0..=arr`, we want it to count `0..divide_by`
65 let arr = unwrap!(u16::try_from(divide_by - 1)); 97 let arr = unwrap!(u16::try_from(divide_by - 1));
66 98
67 let regs = Self::regs(); 99 let regs = Self::regs_core();
68 regs.psc().write(|r| r.set_psc(psc)); 100 regs.psc().write(|r| r.set_psc(psc));
69 regs.arr().write(|r| r.set_arr(arr)); 101 regs.arr().write(|r| r.set_arr(arr));
70 102
@@ -76,8 +108,8 @@ pub(crate) mod sealed {
76 /// Clear update interrupt. 108 /// Clear update interrupt.
77 /// 109 ///
78 /// Returns whether the update interrupt flag was set. 110 /// Returns whether the update interrupt flag was set.
79 fn clear_update_interrupt(&mut self) -> bool { 111 fn clear_update_interrupt(&self) -> bool {
80 let regs = Self::regs(); 112 let regs = Self::regs_core();
81 let sr = regs.sr().read(); 113 let sr = regs.sr().read();
82 if sr.uif() { 114 if sr.uif() {
83 regs.sr().modify(|r| { 115 regs.sr().modify(|r| {
@@ -90,30 +122,20 @@ pub(crate) mod sealed {
90 } 122 }
91 123
92 /// Enable/disable the update interrupt. 124 /// Enable/disable the update interrupt.
93 fn enable_update_interrupt(&mut self, enable: bool) { 125 fn enable_update_interrupt(&self, enable: bool) {
94 Self::regs().dier().modify(|r| r.set_uie(enable)); 126 Self::regs_core().dier().modify(|r| r.set_uie(enable));
95 }
96
97 /// Enable/disable the update dma.
98 fn enable_update_dma(&mut self, enable: bool) {
99 Self::regs().dier().modify(|r| r.set_ude(enable));
100 }
101
102 /// Get the update dma enable/disable state.
103 fn get_update_dma_state(&self) -> bool {
104 Self::regs().dier().read().ude()
105 } 127 }
106 128
107 /// Enable/disable autoreload preload. 129 /// Enable/disable autoreload preload.
108 fn set_autoreload_preload(&mut self, enable: bool) { 130 fn set_autoreload_preload(&self, enable: bool) {
109 Self::regs().cr1().modify(|r| r.set_arpe(enable)); 131 Self::regs_core().cr1().modify(|r| r.set_arpe(enable));
110 } 132 }
111 133
112 /// Get the timer frequency. 134 /// Get the timer frequency.
113 fn get_frequency(&self) -> Hertz { 135 fn get_frequency(&self) -> Hertz {
114 let timer_f = Self::frequency(); 136 let timer_f = Self::frequency();
115 137
116 let regs = Self::regs(); 138 let regs = Self::regs_core();
117 let arr = regs.arr().read().arr(); 139 let arr = regs.arr().read().arr();
118 let psc = regs.psc().read().psc(); 140 let psc = regs.psc().read().psc();
119 141
@@ -121,91 +143,101 @@ pub(crate) mod sealed {
121 } 143 }
122 } 144 }
123 145
124 /// Gneral-purpose 16-bit timer instance. 146 /// Virtual Basic without CR2 16-bit timer instance.
125 pub trait GeneralPurpose16bitInstance: Basic16bitInstance { 147 pub trait BasicNoCr2Instance: CoreInstance {
126 /// Get access to the general purpose 16bit timer registers. 148 /// Get access to the Baisc 16bit timer registers.
127 /// 149 ///
128 /// Note: This works even if the timer is more capable, because registers 150 /// Note: This works even if the timer is more capable, because registers
129 /// for the less capable timers are a subset. This allows writing a driver 151 /// for the less capable timers are a subset. This allows writing a driver
130 /// for a given set of capabilities, and having it transparently work with 152 /// for a given set of capabilities, and having it transparently work with
131 /// more capable timers. 153 /// more capable timers.
132 fn regs_gp16() -> crate::pac::timer::TimGp16; 154 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2;
133
134 /// Set counting mode.
135 fn set_counting_mode(&mut self, mode: CountingMode) {
136 let (cms, dir) = mode.into();
137 155
138 let timer_enabled = Self::regs().cr1().read().cen(); 156 /// Enable/disable the update dma.
139 // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running. 157 fn enable_update_dma(&self, enable: bool) {
140 // Changing direction is discouraged while the timer is running. 158 Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
141 assert!(!timer_enabled);
142
143 Self::regs_gp16().cr1().modify(|r| r.set_dir(dir));
144 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
145 }
146
147 /// Get counting mode.
148 fn get_counting_mode(&self) -> CountingMode {
149 let cr1 = Self::regs_gp16().cr1().read();
150 (cr1.cms(), cr1.dir()).into()
151 } 159 }
152 160
153 /// Set clock divider. 161 /// Get the update dma enable/disable state.
154 fn set_clock_division(&mut self, ckd: vals::Ckd) { 162 fn get_update_dma_state(&self) -> bool {
155 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); 163 Self::regs_basic_no_cr2().dier().read().ude()
156 } 164 }
157 } 165 }
158 166
159 /// Gneral-purpose 32-bit timer instance. 167 /// Basic 16-bit timer instance.
160 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { 168 pub trait BasicInstance: BasicNoCr2Instance {
161 /// Get access to the general purpose 32bit timer registers. 169 /// Get access to the Baisc 16bit timer registers.
162 /// 170 ///
163 /// Note: This works even if the timer is more capable, because registers 171 /// Note: This works even if the timer is more capable, because registers
164 /// for the less capable timers are a subset. This allows writing a driver 172 /// for the less capable timers are a subset. This allows writing a driver
165 /// for a given set of capabilities, and having it transparently work with 173 /// for a given set of capabilities, and having it transparently work with
166 /// more capable timers. 174 /// more capable timers.
167 fn regs_gp32() -> crate::pac::timer::TimGp32; 175 fn regs_basic() -> crate::pac::timer::TimBasic;
176 }
168 177
169 /// Set timer frequency. 178 /// Gneral-purpose 1 channel 16-bit timer instance.
170 fn set_frequency(&mut self, frequency: Hertz) { 179 pub trait GeneralPurpose1ChannelInstance: CoreInstance {
171 let f = frequency.0; 180 /// Get access to the general purpose 1 channel 16bit timer registers.
172 assert!(f > 0); 181 ///
173 let timer_f = Self::frequency().0; 182 /// Note: This works even if the timer is more capable, because registers
174 let pclk_ticks_per_timer_period = (timer_f / f) as u64; 183 /// for the less capable timers are a subset. This allows writing a driver
175 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); 184 /// for a given set of capabilities, and having it transparently work with
176 let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()); 185 /// more capable timers.
186 fn regs_1ch() -> crate::pac::timer::Tim1ch;
177 187
178 let regs = Self::regs_gp32(); 188 /// Set clock divider.
179 regs.psc().write(|r| r.set_psc(psc)); 189 fn set_clock_division(&self, ckd: vals::Ckd) {
180 regs.arr().write(|r| r.set_arr(arr)); 190 Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
191 }
181 192
182 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 193 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
183 regs.egr().write(|r| r.set_ug(true)); 194 fn get_max_compare_value(&self) -> u16 {
184 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 195 Self::regs_1ch().arr().read().arr()
185 } 196 }
197 }
186 198
187 /// Get timer frequency. 199 /// Gneral-purpose 1 channel 16-bit timer instance.
188 fn get_frequency(&self) -> Hertz { 200 pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance {
189 let timer_f = Self::frequency(); 201 /// Get access to the general purpose 2 channel 16bit timer registers.
202 ///
203 /// Note: This works even if the timer is more capable, because registers
204 /// for the less capable timers are a subset. This allows writing a driver
205 /// for a given set of capabilities, and having it transparently work with
206 /// more capable timers.
207 fn regs_2ch() -> crate::pac::timer::Tim2ch;
208 }
190 209
191 let regs = Self::regs_gp32(); 210 /// Gneral-purpose 16-bit timer instance.
192 let arr = regs.arr().read().arr(); 211 pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance {
193 let psc = regs.psc().read().psc(); 212 /// Get access to the general purpose 16bit timer registers.
213 ///
214 /// Note: This works even if the timer is more capable, because registers
215 /// for the less capable timers are a subset. This allows writing a driver
216 /// for a given set of capabilities, and having it transparently work with
217 /// more capable timers.
218 fn regs_gp16() -> crate::pac::timer::TimGp16;
194 219
195 timer_f / arr / (psc + 1) 220 /// Set counting mode.
221 fn set_counting_mode(&self, mode: CountingMode) {
222 let (cms, dir) = mode.into();
223
224 let timer_enabled = Self::regs_core().cr1().read().cen();
225 // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
226 // Changing direction is discouraged while the timer is running.
227 assert!(!timer_enabled);
228
229 Self::regs_gp16().cr1().modify(|r| r.set_dir(dir));
230 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
196 } 231 }
197 }
198 232
199 /// Advanced control timer instance. 233 /// Get counting mode.
200 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { 234 fn get_counting_mode(&self) -> CountingMode {
201 /// Get access to the advanced timer registers. 235 let cr1 = Self::regs_gp16().cr1().read();
202 fn regs_advanced() -> crate::pac::timer::TimAdv; 236 (cr1.cms(), cr1.dir()).into()
203 } 237 }
204 238
205 /// Capture/Compare 16-bit timer instance.
206 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
207 /// Set input capture filter. 239 /// Set input capture filter.
208 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { 240 fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) {
209 let raw_channel = channel.index(); 241 let raw_channel = channel.index();
210 Self::regs_gp16() 242 Self::regs_gp16()
211 .ccmr_input(raw_channel / 2) 243 .ccmr_input(raw_channel / 2)
@@ -213,17 +245,17 @@ pub(crate) mod sealed {
213 } 245 }
214 246
215 /// Clear input interrupt. 247 /// Clear input interrupt.
216 fn clear_input_interrupt(&mut self, channel: Channel) { 248 fn clear_input_interrupt(&self, channel: Channel) {
217 Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); 249 Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
218 } 250 }
219 251
220 /// Enable input interrupt. 252 /// Enable input interrupt.
221 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { 253 fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
222 Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); 254 Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
223 } 255 }
224 256
225 /// Set input capture prescaler. 257 /// Set input capture prescaler.
226 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { 258 fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) {
227 let raw_channel = channel.index(); 259 let raw_channel = channel.index();
228 Self::regs_gp16() 260 Self::regs_gp16()
229 .ccmr_input(raw_channel / 2) 261 .ccmr_input(raw_channel / 2)
@@ -231,7 +263,7 @@ pub(crate) mod sealed {
231 } 263 }
232 264
233 /// Set input TI selection. 265 /// Set input TI selection.
234 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { 266 fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) {
235 let raw_channel = channel.index(); 267 let raw_channel = channel.index();
236 Self::regs_gp16() 268 Self::regs_gp16()
237 .ccmr_input(raw_channel / 2) 269 .ccmr_input(raw_channel / 2)
@@ -239,7 +271,7 @@ pub(crate) mod sealed {
239 } 271 }
240 272
241 /// Set input capture mode. 273 /// Set input capture mode.
242 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { 274 fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) {
243 Self::regs_gp16().ccer().modify(|r| match mode { 275 Self::regs_gp16().ccer().modify(|r| match mode {
244 InputCaptureMode::Rising => { 276 InputCaptureMode::Rising => {
245 r.set_ccnp(channel.index(), false); 277 r.set_ccnp(channel.index(), false);
@@ -256,26 +288,23 @@ pub(crate) mod sealed {
256 }); 288 });
257 } 289 }
258 290
259 /// Enable timer outputs.
260 fn enable_outputs(&mut self);
261
262 /// Set output compare mode. 291 /// Set output compare mode.
263 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { 292 fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) {
264 let r = Self::regs_gp16();
265 let raw_channel: usize = channel.index(); 293 let raw_channel: usize = channel.index();
266 r.ccmr_output(raw_channel / 2) 294 Self::regs_gp16()
295 .ccmr_output(raw_channel / 2)
267 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 296 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
268 } 297 }
269 298
270 /// Set output polarity. 299 /// Set output polarity.
271 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 300 fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
272 Self::regs_gp16() 301 Self::regs_gp16()
273 .ccer() 302 .ccer()
274 .modify(|w| w.set_ccp(channel.index(), polarity.into())); 303 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
275 } 304 }
276 305
277 /// Enable/disable a channel. 306 /// Enable/disable a channel.
278 fn enable_channel(&mut self, channel: Channel, enable: bool) { 307 fn enable_channel(&self, channel: Channel, enable: bool) {
279 Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); 308 Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
280 } 309 }
281 310
@@ -285,81 +314,174 @@ pub(crate) mod sealed {
285 } 314 }
286 315
287 /// Set compare value for a channel. 316 /// Set compare value for a channel.
288 fn set_compare_value(&mut self, channel: Channel, value: u16) { 317 fn set_compare_value(&self, channel: Channel, value: u16) {
289 Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); 318 Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
290 } 319 }
291 320
292 /// Get capture value for a channel. 321 /// Get capture value for a channel.
293 fn get_capture_value(&mut self, channel: Channel) -> u16 { 322 fn get_capture_value(&self, channel: Channel) -> u16 {
294 Self::regs_gp16().ccr(channel.index()).read().ccr() 323 Self::regs_gp16().ccr(channel.index()).read().ccr()
295 } 324 }
296 325
297 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
298 fn get_max_compare_value(&self) -> u16 {
299 Self::regs_gp16().arr().read().arr()
300 }
301
302 /// Get compare value for a channel. 326 /// Get compare value for a channel.
303 fn get_compare_value(&self, channel: Channel) -> u16 { 327 fn get_compare_value(&self, channel: Channel) -> u16 {
304 Self::regs_gp16().ccr(channel.index()).read().ccr() 328 Self::regs_gp16().ccr(channel.index()).read().ccr()
305 } 329 }
306 330
307 /// Set output compare preload. 331 /// Set output compare preload.
308 fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { 332 fn set_output_compare_preload(&self, channel: Channel, preload: bool) {
309 let channel_index = channel.index(); 333 let channel_index = channel.index();
310 Self::regs_gp16() 334 Self::regs_gp16()
311 .ccmr_output(channel_index / 2) 335 .ccmr_output(channel_index / 2)
312 .modify(|w| w.set_ocpe(channel_index % 2, preload)); 336 .modify(|w| w.set_ocpe(channel_index % 2, preload));
313 } 337 }
314 }
315 338
316 /// Capture/Compare 16-bit timer instance with complementary pin support. 339 /// Get capture compare DMA selection
317 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { 340 fn get_cc_dma_selection(&self) -> super::vals::Ccds {
318 /// Set complementary output polarity. 341 Self::regs_gp16().cr2().read().ccds()
319 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
320 Self::regs_advanced()
321 .ccer()
322 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
323 } 342 }
324 343
325 /// Set clock divider for the dead time. 344 /// Set capture compare DMA selection
326 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { 345 fn set_cc_dma_selection(&self, ccds: super::vals::Ccds) {
327 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 346 Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
328 } 347 }
329 348
330 /// Set dead time, as a fraction of the max duty value. 349 /// Get capture compare DMA enable state
331 fn set_dead_time_value(&mut self, value: u8) { 350 fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
332 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 351 Self::regs_gp16().dier().read().ccde(channel.index())
333 } 352 }
334 353
335 /// Enable/disable a complementary channel. 354 /// Set capture compare DMA enable state
336 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 355 fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
337 Self::regs_advanced() 356 Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
338 .ccer()
339 .modify(|w| w.set_ccne(channel.index(), enable));
340 } 357 }
341 } 358 }
342 359
343 /// Capture/Compare 32-bit timer instance. 360 #[cfg(not(stm32l0))]
344 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { 361 /// Gneral-purpose 32-bit timer instance.
362 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
363 /// Get access to the general purpose 32bit timer registers.
364 ///
365 /// Note: This works even if the timer is more capable, because registers
366 /// for the less capable timers are a subset. This allows writing a driver
367 /// for a given set of capabilities, and having it transparently work with
368 /// more capable timers.
369 fn regs_gp32() -> crate::pac::timer::TimGp32;
370
371 /// Set timer frequency.
372 fn set_frequency(&self, frequency: Hertz) {
373 let f = frequency.0;
374 assert!(f > 0);
375 let timer_f = Self::frequency().0;
376 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
377 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
378 let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
379
380 let regs = Self::regs_gp32();
381 regs.psc().write(|r| r.set_psc(psc));
382 regs.arr().write_value(arr);
383
384 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
385 regs.egr().write(|r| r.set_ug(true));
386 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
387 }
388
389 /// Get timer frequency.
390 fn get_frequency(&self) -> Hertz {
391 let timer_f = Self::frequency();
392
393 let regs = Self::regs_gp32();
394 let arr = regs.arr().read();
395 let psc = regs.psc().read().psc();
396
397 timer_f / arr / (psc + 1)
398 }
399
345 /// Set comapre value for a channel. 400 /// Set comapre value for a channel.
346 fn set_compare_value(&mut self, channel: Channel, value: u32) { 401 fn set_compare_value(&self, channel: Channel, value: u32) {
347 Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); 402 Self::regs_gp32().ccr(channel.index()).write_value(value);
348 } 403 }
349 404
350 /// Get capture value for a channel. 405 /// Get capture value for a channel.
351 fn get_capture_value(&mut self, channel: Channel) -> u32 { 406 fn get_capture_value(&self, channel: Channel) -> u32 {
352 Self::regs_gp32().ccr(channel.index()).read().ccr() 407 Self::regs_gp32().ccr(channel.index()).read()
353 } 408 }
354 409
355 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. 410 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
356 fn get_max_compare_value(&self) -> u32 { 411 fn get_max_compare_value(&self) -> u32 {
357 Self::regs_gp32().arr().read().arr() 412 Self::regs_gp32().arr().read()
358 } 413 }
359 414
360 /// Get compare value for a channel. 415 /// Get compare value for a channel.
361 fn get_compare_value(&self, channel: Channel) -> u32 { 416 fn get_compare_value(&self, channel: Channel) -> u32 {
362 Self::regs_gp32().ccr(channel.index()).read().ccr() 417 Self::regs_gp32().ccr(channel.index()).read()
418 }
419 }
420
421 #[cfg(not(stm32l0))]
422 /// Gneral-purpose 1 channel with one complementary 16-bit timer instance.
423 pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance {
424 /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
425 ///
426 /// Note: This works even if the timer is more capable, because registers
427 /// for the less capable timers are a subset. This allows writing a driver
428 /// for a given set of capabilities, and having it transparently work with
429 /// more capable timers.
430 fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp;
431
432 /// Set clock divider for the dead time.
433 fn set_dead_time_clock_division(&self, value: vals::Ckd) {
434 Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
435 }
436
437 /// Set dead time, as a fraction of the max duty value.
438 fn set_dead_time_value(&self, value: u8) {
439 Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
440 }
441
442 /// Enable timer outputs.
443 fn enable_outputs(&self) {
444 Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true));
445 }
446 }
447
448 #[cfg(not(stm32l0))]
449 /// Gneral-purpose 2 channel with one complementary 16-bit timer instance.
450 pub trait GeneralPurpose2ChannelComplementaryInstance:
451 BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance
452 {
453 /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
454 ///
455 /// Note: This works even if the timer is more capable, because registers
456 /// for the less capable timers are a subset. This allows writing a driver
457 /// for a given set of capabilities, and having it transparently work with
458 /// more capable timers.
459 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp;
460 }
461
462 #[cfg(not(stm32l0))]
463 /// Advanced control timer instance.
464 pub trait AdvancedControlInstance:
465 GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance
466 {
467 /// Capture compare interrupt for this timer.
468 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
469
470 /// Get access to the advanced timer registers.
471 fn regs_advanced() -> crate::pac::timer::TimAdv;
472
473 /// Set complementary output polarity.
474 fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
475 Self::regs_advanced()
476 .ccer()
477 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
478 }
479
480 /// Enable/disable a complementary channel.
481 fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
482 Self::regs_advanced()
483 .ccer()
484 .modify(|w| w.set_ccne(channel.index(), enable));
363 } 485 }
364 } 486 }
365} 487}
@@ -450,20 +572,17 @@ pub enum CountingMode {
450impl CountingMode { 572impl CountingMode {
451 /// Return whether this mode is edge-aligned (up or down). 573 /// Return whether this mode is edge-aligned (up or down).
452 pub fn is_edge_aligned(&self) -> bool { 574 pub fn is_edge_aligned(&self) -> bool {
453 match self { 575 matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
454 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
455 _ => false,
456 }
457 } 576 }
458 577
459 /// Return whether this mode is center-aligned. 578 /// Return whether this mode is center-aligned.
460 pub fn is_center_aligned(&self) -> bool { 579 pub fn is_center_aligned(&self) -> bool {
461 match self { 580 matches!(
581 self,
462 CountingMode::CenterAlignedDownInterrupts 582 CountingMode::CenterAlignedDownInterrupts
463 | CountingMode::CenterAlignedUpInterrupts 583 | CountingMode::CenterAlignedUpInterrupts
464 | CountingMode::CenterAlignedBothInterrupts => true, 584 | CountingMode::CenterAlignedBothInterrupts
465 _ => false, 585 )
466 }
467 } 586 }
468} 587}
469 588
@@ -555,153 +674,291 @@ impl From<OutputPolarity> for bool {
555} 674}
556 675
557/// Basic 16-bit timer instance. 676/// Basic 16-bit timer instance.
558pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 677pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {}
559
560/// Gneral-purpose 16-bit timer instance.
561pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + Basic16bitInstance + 'static {}
562 678
563/// Gneral-purpose 32-bit timer instance. 679// It's just a General-purpose 16-bit timer instance.
564pub trait GeneralPurpose32bitInstance: 680/// Capture Compare timer instance.
565 sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static
566{
567}
568
569/// Advanced control timer instance.
570pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose16bitInstance + 'static {}
571
572/// Capture/Compare 16-bit timer instance.
573pub trait CaptureCompare16bitInstance: 681pub trait CaptureCompare16bitInstance:
574 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static 682 BasicInstance
683 + sealed::GeneralPurpose2ChannelInstance
684 + sealed::GeneralPurpose1ChannelInstance
685 + sealed::GeneralPurpose16bitInstance
686 + 'static
575{ 687{
576} 688}
577 689
578/// Capture/Compare 16-bit timer instance with complementary pin support. 690#[cfg(not(stm32l0))]
579pub trait ComplementaryCaptureCompare16bitInstance: 691// It's just a General-purpose 32-bit timer instance.
580 sealed::ComplementaryCaptureCompare16bitInstance + CaptureCompare16bitInstance + AdvancedControlInstance + 'static 692/// Capture Compare 32-bit timer instance.
693pub trait CaptureCompare32bitInstance:
694 CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static
581{ 695{
582} 696}
583 697
584/// Capture/Compare 32-bit timer instance. 698#[cfg(not(stm32l0))]
585pub trait CaptureCompare32bitInstance: 699// It's just a Advanced Control timer instance.
586 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static 700/// Complementary Capture Compare 32-bit timer instance.
701pub trait ComplementaryCaptureCompare16bitInstance:
702 CaptureCompare16bitInstance
703 + sealed::GeneralPurpose1ChannelComplementaryInstance
704 + sealed::GeneralPurpose2ChannelComplementaryInstance
705 + sealed::AdvancedControlInstance
706 + 'static
587{ 707{
588} 708}
589 709
590pin_trait!(Channel1Pin, CaptureCompare16bitInstance); 710pin_trait!(Channel1Pin, CaptureCompare16bitInstance);
591pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance);
592pin_trait!(Channel2Pin, CaptureCompare16bitInstance); 711pin_trait!(Channel2Pin, CaptureCompare16bitInstance);
593pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance);
594pin_trait!(Channel3Pin, CaptureCompare16bitInstance); 712pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
595pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance);
596pin_trait!(Channel4Pin, CaptureCompare16bitInstance); 713pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
597pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance);
598pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); 714pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
599pin_trait!(BreakInputPin, CaptureCompare16bitInstance); 715
600pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance); 716cfg_if::cfg_if! {
601pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); 717 if #[cfg(not(stm32l0))] {
602pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); 718 pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
603pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); 719 pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
604pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); 720 pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
721 pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
722
723 pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance);
724 pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance);
725
726 pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance);
727 pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance);
728
729 pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance);
730 pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance);
731 }
732}
605 733
606#[allow(unused)] 734#[allow(unused)]
607macro_rules! impl_basic_16bit_timer { 735macro_rules! impl_core_timer {
608 ($inst:ident, $irq:ident) => { 736 ($inst:ident, $irq:ident) => {
609 impl sealed::Basic16bitInstance for crate::peripherals::$inst { 737 impl sealed::CoreInstance for crate::peripherals::$inst {
610 type Interrupt = crate::interrupt::typelevel::$irq; 738 type Interrupt = crate::interrupt::typelevel::$irq;
611 739
612 fn regs() -> crate::pac::timer::TimBasic { 740 fn regs_core() -> crate::pac::timer::TimCore {
613 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } 741 unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) }
614 } 742 }
615 } 743 }
616 }; 744 };
617} 745}
618 746
619#[allow(unused)] 747#[allow(unused)]
620macro_rules! impl_32bit_timer { 748macro_rules! impl_basic_no_cr2_timer {
621 ($inst:ident) => { 749 ($inst:ident) => {
622 impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { 750 impl sealed::BasicNoCr2Instance for crate::peripherals::$inst {
623 fn regs_gp32() -> crate::pac::timer::TimGp32 { 751 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 {
624 crate::pac::$inst 752 unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) }
625 } 753 }
626 } 754 }
627 }; 755 };
628} 756}
629 757
630#[allow(unused)] 758#[allow(unused)]
631macro_rules! impl_compare_capable_16bit { 759macro_rules! impl_basic_timer {
632 ($inst:ident) => { 760 ($inst:ident) => {
633 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 761 impl sealed::BasicInstance for crate::peripherals::$inst {
634 fn enable_outputs(&mut self) {} 762 fn regs_basic() -> crate::pac::timer::TimBasic {
763 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
764 }
635 } 765 }
636 }; 766 };
637} 767}
638 768
639foreach_interrupt! { 769#[allow(unused)]
640 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 770macro_rules! impl_1ch_timer {
641 impl_basic_16bit_timer!($inst, $irq); 771 ($inst:ident) => {
642 impl Basic16bitInstance for crate::peripherals::$inst {} 772 impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst {
773 fn regs_1ch() -> crate::pac::timer::Tim1ch {
774 unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) }
775 }
776 }
643 }; 777 };
644 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 778}
645 impl_basic_16bit_timer!($inst, $irq);
646 impl_compare_capable_16bit!($inst);
647 impl Basic16bitInstance for crate::peripherals::$inst {}
648 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
649 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
650 779
651 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 780#[allow(unused)]
652 fn regs_gp16() -> crate::pac::timer::TimGp16 { 781macro_rules! impl_2ch_timer {
653 crate::pac::$inst 782 ($inst:ident) => {
783 impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst {
784 fn regs_2ch() -> crate::pac::timer::Tim2ch {
785 unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) }
654 } 786 }
655 } 787 }
656 }; 788 };
789}
657 790
658 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 791#[allow(unused)]
659 impl_basic_16bit_timer!($inst, $irq); 792macro_rules! impl_gp16_timer {
660 impl_32bit_timer!($inst); 793 ($inst:ident) => {
661 impl_compare_capable_16bit!($inst);
662 impl Basic16bitInstance for crate::peripherals::$inst {}
663 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
664 impl CaptureCompare32bitInstance for crate::peripherals::$inst {}
665 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
666 impl GeneralPurpose32bitInstance for crate::peripherals::$inst {}
667 impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {}
668
669 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 794 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
670 fn regs_gp16() -> crate::pac::timer::TimGp16 { 795 fn regs_gp16() -> crate::pac::timer::TimGp16 {
671 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } 796 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
672 } 797 }
673 } 798 }
674 }; 799 };
800}
675 801
676 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 802#[allow(unused)]
677 impl_basic_16bit_timer!($inst, $irq); 803macro_rules! impl_gp32_timer {
804 ($inst:ident) => {
805 impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst {
806 fn regs_gp32() -> crate::pac::timer::TimGp32 {
807 crate::pac::$inst
808 }
809 }
810 };
811}
678 812
679 impl Basic16bitInstance for crate::peripherals::$inst {} 813#[allow(unused)]
680 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} 814macro_rules! impl_1ch_cmp_timer {
681 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 815 ($inst:ident) => {
682 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 816 impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {
683 impl AdvancedControlInstance for crate::peripherals::$inst {} 817 fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp {
684 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 818 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
685 fn enable_outputs(&mut self) {
686 use crate::timer::sealed::AdvancedControlInstance;
687 let r = Self::regs_advanced();
688 r.bdtr().modify(|w| w.set_moe(true));
689 } 819 }
690 } 820 }
691 impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 821 };
692 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 822}
693 fn regs_gp16() -> crate::pac::timer::TimGp16 { 823
694 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } 824#[allow(unused)]
825macro_rules! impl_2ch_cmp_timer {
826 ($inst:ident) => {
827 impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {
828 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp {
829 unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
695 } 830 }
696 } 831 }
832 };
833}
697 834
835#[allow(unused)]
836macro_rules! impl_adv_timer {
837 ($inst:ident, $irq:ident) => {
698 impl sealed::AdvancedControlInstance for crate::peripherals::$inst { 838 impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
839 type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq;
840
699 fn regs_advanced() -> crate::pac::timer::TimAdv { 841 fn regs_advanced() -> crate::pac::timer::TimAdv {
700 crate::pac::$inst 842 unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) }
701 } 843 }
702 } 844 }
703 }; 845 };
704} 846}
705 847
848foreach_interrupt! {
849
850 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
851 impl_core_timer!($inst, $irq);
852 impl_basic_no_cr2_timer!($inst);
853 impl_basic_timer!($inst);
854 impl BasicInstance for crate::peripherals::$inst {}
855 };
856
857 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
858 impl_core_timer!($inst, $irq);
859 impl_basic_no_cr2_timer!($inst);
860 impl_basic_timer!($inst);
861 impl_1ch_timer!($inst);
862 impl_2ch_timer!($inst);
863 impl_gp16_timer!($inst);
864 impl BasicInstance for crate::peripherals::$inst {}
865 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
866 };
867
868
869 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
870 impl_core_timer!($inst, $irq);
871 impl_basic_no_cr2_timer!($inst);
872 impl_basic_timer!($inst);
873 impl_1ch_timer!($inst);
874 impl_2ch_timer!($inst);
875 impl_gp16_timer!($inst);
876 impl BasicInstance for crate::peripherals::$inst {}
877 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
878 };
879
880 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
881 impl_core_timer!($inst, $irq);
882 impl_basic_no_cr2_timer!($inst);
883 impl_basic_timer!($inst);
884 impl_1ch_timer!($inst);
885 impl_2ch_timer!($inst);
886 impl_gp16_timer!($inst);
887 impl BasicInstance for crate::peripherals::$inst {}
888 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
889 };
890
891 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
892 impl_core_timer!($inst, $irq);
893 impl_basic_no_cr2_timer!($inst);
894 impl_basic_timer!($inst);
895 impl_1ch_timer!($inst);
896 impl_2ch_timer!($inst);
897 impl_gp16_timer!($inst);
898 impl_gp32_timer!($inst);
899 impl BasicInstance for crate::peripherals::$inst {}
900 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
901 impl CaptureCompare32bitInstance for crate::peripherals::$inst {}
902 };
903
904 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
905 impl_core_timer!($inst, $irq);
906 impl_basic_no_cr2_timer!($inst);
907 impl_basic_timer!($inst);
908 impl_1ch_timer!($inst);
909 impl_2ch_timer!($inst);
910 impl_gp16_timer!($inst);
911 impl_1ch_cmp_timer!($inst);
912 impl_2ch_cmp_timer!($inst);
913 impl BasicInstance for crate::peripherals::$inst {}
914 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
915 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
916 };
917 ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => {
918 impl_adv_timer!($inst, $irq);
919 };
920
921
922 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
923 impl_core_timer!($inst, $irq);
924 impl_basic_no_cr2_timer!($inst);
925 impl_basic_timer!($inst);
926 impl_1ch_timer!($inst);
927 impl_2ch_timer!($inst);
928 impl_gp16_timer!($inst);
929 impl_1ch_cmp_timer!($inst);
930 impl_2ch_cmp_timer!($inst);
931 impl BasicInstance for crate::peripherals::$inst {}
932 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
933 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
934 };
935 ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => {
936 impl_adv_timer!($inst, $irq);
937 };
938
939
940 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
941 impl_core_timer!($inst, $irq);
942 impl_basic_no_cr2_timer!($inst);
943 impl_basic_timer!($inst);
944 impl_1ch_timer!($inst);
945 impl_2ch_timer!($inst);
946 impl_gp16_timer!($inst);
947 impl_1ch_cmp_timer!($inst);
948 impl_2ch_cmp_timer!($inst);
949 impl BasicInstance for crate::peripherals::$inst {}
950 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
951 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
952 };
953 ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => {
954 impl_adv_timer!($inst, $irq);
955 };
956}
957
706// Update Event trigger DMA for every timer 958// Update Event trigger DMA for every timer
707dma_trait!(UpDma, Basic16bitInstance); 959dma_trait!(UpDma, BasicInstance);
960
961dma_trait!(Ch1Dma, CaptureCompare16bitInstance);
962dma_trait!(Ch2Dma, CaptureCompare16bitInstance);
963dma_trait!(Ch3Dma, CaptureCompare16bitInstance);
964dma_trait!(Ch4Dma, CaptureCompare16bitInstance);
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 80f10424c..1acba504e 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -84,13 +84,12 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
84 this.set_frequency(freq); 84 this.set_frequency(freq);
85 this.inner.start(); 85 this.inner.start();
86 86
87 this.inner.enable_outputs();
88
89 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 87 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
90 .iter() 88 .iter()
91 .for_each(|&channel| { 89 .for_each(|&channel| {
92 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); 90 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
93 this.inner.set_output_compare_preload(channel, true) 91
92 this.inner.set_output_compare_preload(channel, true);
94 }); 93 });
95 94
96 this 95 this
@@ -151,11 +150,16 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
151 self.inner.set_output_polarity(channel, polarity); 150 self.inner.set_output_polarity(channel, polarity);
152 } 151 }
153 152
153 /// Set the output compare mode for a given channel.
154 pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
155 self.inner.set_output_compare_mode(channel, mode);
156 }
157
154 /// Generate a sequence of PWM waveform 158 /// Generate a sequence of PWM waveform
155 /// 159 ///
156 /// Note: 160 /// Note:
157 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 161 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
158 pub async fn gen_waveform( 162 pub async fn waveform_up(
159 &mut self, 163 &mut self,
160 dma: impl Peripheral<P = impl super::UpDma<T>>, 164 dma: impl Peripheral<P = impl super::UpDma<T>>,
161 channel: Channel, 165 channel: Channel,
@@ -197,7 +201,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
197 &mut dma, 201 &mut dma,
198 req, 202 req,
199 duty, 203 duty,
200 T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _, 204 T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _,
201 dma_transfer_option, 205 dma_transfer_option,
202 ) 206 )
203 .await 207 .await
@@ -221,6 +225,95 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
221 } 225 }
222} 226}
223 227
228macro_rules! impl_waveform_chx {
229 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
230 impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
231 /// Generate a sequence of PWM waveform
232 ///
233 /// Note:
234 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
235 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
236 use super::vals::Ccds;
237
238 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
239
240 into_ref!(dma);
241
242 #[allow(clippy::let_unit_value)] // eg. stm32f334
243 let req = dma.request();
244
245 let cc_channel = super::Channel::$cc_ch;
246
247 let original_duty_state = self.get_duty(cc_channel);
248 let original_enable_state = self.is_enabled(cc_channel);
249 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE;
250 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
251
252 // redirect CC DMA request onto Update Event
253 if !original_cc_dma_on_update {
254 self.inner.set_cc_dma_selection(Ccds::ONUPDATE)
255 }
256
257 if !original_cc_dma_enabled {
258 self.inner.set_cc_dma_enable_state(cc_channel, true);
259 }
260
261 if !original_enable_state {
262 self.enable(cc_channel);
263 }
264
265 unsafe {
266 #[cfg(not(any(bdma, gpdma)))]
267 use crate::dma::{Burst, FifoThreshold};
268 use crate::dma::{Transfer, TransferOptions};
269
270 let dma_transfer_option = TransferOptions {
271 #[cfg(not(any(bdma, gpdma)))]
272 fifo_threshold: Some(FifoThreshold::Full),
273 #[cfg(not(any(bdma, gpdma)))]
274 mburst: Burst::Incr8,
275 ..Default::default()
276 };
277
278 Transfer::new_write(
279 &mut dma,
280 req,
281 duty,
282 T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _,
283 dma_transfer_option,
284 )
285 .await
286 };
287
288 // restore output compare state
289 if !original_enable_state {
290 self.disable(cc_channel);
291 }
292
293 self.set_duty(cc_channel, original_duty_state);
294
295 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
296 // this can almost always trigger a DMA FIFO error.
297 //
298 // optional TODO:
299 // clean FEIF after disable UDE
300 if !original_cc_dma_enabled {
301 self.inner.set_cc_dma_enable_state(cc_channel, false);
302 }
303
304 if !original_cc_dma_on_update {
305 self.inner.set_cc_dma_selection(Ccds::ONCOMPARE)
306 }
307 }
308 }
309 };
310}
311
312impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1);
313impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
314impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
315impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
316
224impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { 317impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> {
225 type Channel = Channel; 318 type Channel = Channel;
226 type Time = Hertz; 319 type Time = Hertz;
@@ -235,7 +328,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d,
235 } 328 }
236 329
237 fn get_period(&self) -> Self::Time { 330 fn get_period(&self) -> Self::Time {
238 self.inner.get_frequency().into() 331 self.inner.get_frequency()
239 } 332 }
240 333
241 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 334 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 962547bd7..c11e3382f 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,5 +1,6 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::slice; 2use core::slice;
3use core::sync::atomic::{AtomicBool, Ordering};
3use core::task::Poll; 4use core::task::Poll;
4 5
5use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 6use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
@@ -46,8 +47,10 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
46 let mut rx_writer = state.rx_buf.writer(); 47 let mut rx_writer = state.rx_buf.writer();
47 let buf = rx_writer.push_slice(); 48 let buf = rx_writer.push_slice();
48 if !buf.is_empty() { 49 if !buf.is_empty() {
49 buf[0] = dr.unwrap(); 50 if let Some(byte) = dr {
50 rx_writer.push_done(1); 51 buf[0] = byte;
52 rx_writer.push_done(1);
53 }
51 } else { 54 } else {
52 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 55 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
53 } 56 }
@@ -61,6 +64,22 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
61 state.rx_waker.wake(); 64 state.rx_waker.wake();
62 } 65 }
63 66
67 // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC)
68 // indicates that all bytes are pushed out from the FIFO.
69 // For other usart variants it shows that last byte from the buffer was just sent.
70 if sr_val.tc() {
71 // For others it is cleared above with `clear_interrupt_flags`.
72 #[cfg(any(usart_v1, usart_v2))]
73 sr(r).modify(|w| w.set_tc(false));
74
75 r.cr1().modify(|w| {
76 w.set_tcie(false);
77 });
78
79 state.tx_done.store(true, Ordering::Release);
80 state.tx_waker.wake();
81 }
82
64 // TX 83 // TX
65 if sr(r).read().txe() { 84 if sr(r).read().txe() {
66 let mut tx_reader = state.tx_buf.reader(); 85 let mut tx_reader = state.tx_buf.reader();
@@ -69,11 +88,18 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
69 r.cr1().modify(|w| { 88 r.cr1().modify(|w| {
70 w.set_txeie(true); 89 w.set_txeie(true);
71 }); 90 });
91
92 // Enable transmission complete interrupt when last byte is going to be sent out.
93 if buf.len() == 1 {
94 r.cr1().modify(|w| {
95 w.set_tcie(true);
96 });
97 }
98
72 tdr(r).write_volatile(buf[0].into()); 99 tdr(r).write_volatile(buf[0].into());
73 tx_reader.pop_done(1); 100 tx_reader.pop_done(1);
74 state.tx_waker.wake();
75 } else { 101 } else {
76 // Disable interrupt until we have something to transmit again 102 // Disable interrupt until we have something to transmit again.
77 r.cr1().modify(|w| { 103 r.cr1().modify(|w| {
78 w.set_txeie(false); 104 w.set_txeie(false);
79 }); 105 });
@@ -82,23 +108,27 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
82 } 108 }
83} 109}
84 110
85/// Buffered UART State 111pub(crate) use sealed::State;
86pub struct State { 112pub(crate) mod sealed {
87 rx_waker: AtomicWaker, 113 use super::*;
88 rx_buf: RingBuffer, 114 pub struct State {
89 115 pub(crate) rx_waker: AtomicWaker,
90 tx_waker: AtomicWaker, 116 pub(crate) rx_buf: RingBuffer,
91 tx_buf: RingBuffer, 117 pub(crate) tx_waker: AtomicWaker,
92} 118 pub(crate) tx_buf: RingBuffer,
119 pub(crate) tx_done: AtomicBool,
120 }
93 121
94impl State { 122 impl State {
95 /// Create new state 123 /// Create new state
96 pub const fn new() -> Self { 124 pub const fn new() -> Self {
97 Self { 125 Self {
98 rx_buf: RingBuffer::new(), 126 rx_buf: RingBuffer::new(),
99 tx_buf: RingBuffer::new(), 127 tx_buf: RingBuffer::new(),
100 rx_waker: AtomicWaker::new(), 128 rx_waker: AtomicWaker::new(),
101 tx_waker: AtomicWaker::new(), 129 tx_waker: AtomicWaker::new(),
130 tx_done: AtomicBool::new(true),
131 }
102 } 132 }
103 } 133 }
104} 134}
@@ -110,11 +140,15 @@ pub struct BufferedUart<'d, T: BasicInstance> {
110} 140}
111 141
112/// Tx-only buffered UART 142/// Tx-only buffered UART
143///
144/// Created with [BufferedUart::split]
113pub struct BufferedUartTx<'d, T: BasicInstance> { 145pub struct BufferedUartTx<'d, T: BasicInstance> {
114 phantom: PhantomData<&'d mut T>, 146 phantom: PhantomData<&'d mut T>,
115} 147}
116 148
117/// Rx-only buffered UART 149/// Rx-only buffered UART
150///
151/// Created with [BufferedUart::split]
118pub struct BufferedUartRx<'d, T: BasicInstance> { 152pub struct BufferedUartRx<'d, T: BasicInstance> {
119 phantom: PhantomData<&'d mut T>, 153 phantom: PhantomData<&'d mut T>,
120} 154}
@@ -364,6 +398,8 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
364 async fn write(&self, buf: &[u8]) -> Result<usize, Error> { 398 async fn write(&self, buf: &[u8]) -> Result<usize, Error> {
365 poll_fn(move |cx| { 399 poll_fn(move |cx| {
366 let state = T::buffered_state(); 400 let state = T::buffered_state();
401 state.tx_done.store(false, Ordering::Release);
402
367 let empty = state.tx_buf.is_empty(); 403 let empty = state.tx_buf.is_empty();
368 404
369 let mut tx_writer = unsafe { state.tx_buf.writer() }; 405 let mut tx_writer = unsafe { state.tx_buf.writer() };
@@ -389,7 +425,8 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
389 async fn flush(&self) -> Result<(), Error> { 425 async fn flush(&self) -> Result<(), Error> {
390 poll_fn(move |cx| { 426 poll_fn(move |cx| {
391 let state = T::buffered_state(); 427 let state = T::buffered_state();
392 if !state.tx_buf.is_empty() { 428
429 if !state.tx_done.load(Ordering::Acquire) {
393 state.tx_waker.register(cx.waker()); 430 state.tx_waker.register(cx.waker());
394 return Poll::Pending; 431 return Poll::Pending;
395 } 432 }
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 4391bfef7..b852f0176 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -7,17 +7,19 @@ use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::PeripheralRef; 7use embassy_hal_internal::PeripheralRef;
8use futures::future::{select, Either}; 8use futures::future::{select, Either};
9 9
10use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, RxDma, UartRx}; 10use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx};
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 14/// Rx-only Ring-buffered UART Driver
15pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { 15///
16/// Created with [UartRx::into_ring_buffered]
17pub struct RingBufferedUartRx<'d, T: BasicInstance> {
16 _peri: PeripheralRef<'d, T>, 18 _peri: PeripheralRef<'d, T>,
17 ring_buf: ReadableRingBuffer<'d, RxDma, u8>, 19 ring_buf: ReadableRingBuffer<'d, u8>,
18} 20}
19 21
20impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUartRx<'d, T, RxDma> { 22impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> {
21 type Config = Config; 23 type Config = Config;
22 type ConfigError = ConfigError; 24 type ConfigError = ConfigError;
23 25
@@ -30,7 +32,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
30 /// Turn the `UartRx` into a buffered uart which can continously receive in the background 32 /// Turn the `UartRx` into a buffered uart which can continously receive in the background
31 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the 33 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
32 /// DMA controller, and must be large enough to prevent overflows. 34 /// DMA controller, and must be large enough to prevent overflows.
33 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { 35 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> {
34 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 36 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
35 37
36 let request = self.rx_dma.request(); 38 let request = self.rx_dma.request();
@@ -49,7 +51,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
49 } 51 }
50} 52}
51 53
52impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> { 54impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
53 /// Clear the ring buffer and start receiving in the background 55 /// Clear the ring buffer and start receiving in the background
54 pub fn start(&mut self) -> Result<(), Error> { 56 pub fn start(&mut self) -> Result<(), Error> {
55 // Clear the ring buffer so that it is ready to receive data 57 // Clear the ring buffer so that it is ready to receive data
@@ -206,7 +208,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
206 } 208 }
207} 209}
208 210
209impl<T: BasicInstance, RxDma: super::RxDma<T>> Drop for RingBufferedUartRx<'_, T, RxDma> { 211impl<T: BasicInstance> Drop for RingBufferedUartRx<'_, T> {
210 fn drop(&mut self) { 212 fn drop(&mut self) {
211 self.teardown_uart(); 213 self.teardown_uart();
212 214
@@ -243,18 +245,16 @@ fn clear_idle_flag(r: Regs) -> Sr {
243 sr 245 sr
244} 246}
245 247
246impl<T, Rx> embedded_io_async::ErrorType for RingBufferedUartRx<'_, T, Rx> 248impl<T> embedded_io_async::ErrorType for RingBufferedUartRx<'_, T>
247where 249where
248 T: BasicInstance, 250 T: BasicInstance,
249 Rx: RxDma<T>,
250{ 251{
251 type Error = Error; 252 type Error = Error;
252} 253}
253 254
254impl<T, Rx> embedded_io_async::Read for RingBufferedUartRx<'_, T, Rx> 255impl<T> embedded_io_async::Read for RingBufferedUartRx<'_, T>
255where 256where
256 T: BasicInstance, 257 T: BasicInstance,
257 Rx: RxDma<T>,
258{ 258{
259 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 259 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
260 self.read(buf).await 260 self.read(buf).await
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index f39915906..be321a19b 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -264,7 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> {
264 264
265 let regs = T::regs(); 265 let regs = T::regs();
266 266
267 #[cfg(any(stm32l5, stm32wb))] 267 #[cfg(any(stm32l4, stm32l5, stm32wb))]
268 crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); 268 crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
269 269
270 #[cfg(pwr_h5)] 270 #[cfg(pwr_h5)]
@@ -280,7 +280,7 @@ impl<'d, T: Instance> Driver<'d, T> {
280 #[cfg(time)] 280 #[cfg(time)]
281 embassy_time::block_for(embassy_time::Duration::from_millis(100)); 281 embassy_time::block_for(embassy_time::Duration::from_millis(100));
282 #[cfg(not(time))] 282 #[cfg(not(time))]
283 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10); 283 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10);
284 284
285 #[cfg(not(usb_v4))] 285 #[cfg(not(usb_v4))]
286 regs.btable().write(|w| w.set_btable(0)); 286 regs.btable().write(|w| w.set_btable(0));
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 190fb274f..373697ec8 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -606,13 +606,6 @@ impl<'d, T: Instance> Bus<'d, T> {
606 // Wait for USB power to stabilize 606 // Wait for USB power to stabilize
607 while !crate::pac::PWR.cr3().read().usb33rdy() {} 607 while !crate::pac::PWR.cr3().read().usb33rdy() {}
608 608
609 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
610 critical_section::with(|_| {
611 crate::pac::RCC
612 .d2ccip2r()
613 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
614 });
615
616 // Enable ULPI clock if external PHY is used 609 // Enable ULPI clock if external PHY is used
617 let ulpien = !self.phy_type.internal(); 610 let ulpien = !self.phy_type.internal();
618 critical_section::with(|_| { 611 critical_section::with(|_| {
@@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> {
645 638
646 // Wait for USB power to stabilize 639 // Wait for USB power to stabilize
647 while !crate::pac::PWR.svmsr().read().vddusbrdy() {} 640 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
648
649 // Select HSI48 as USB clock source.
650 critical_section::with(|_| {
651 crate::pac::RCC.ccipr1().modify(|w| {
652 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
653 })
654 });
655 } 641 }
656 642
657 <T as RccPeripheral>::enable_and_reset(); 643 <T as RccPeripheral>::enable_and_reset();
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index dc701ef64..2ff0db09e 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -42,9 +42,13 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
42 // Prescaler value 42 // Prescaler value
43 let psc = 2u16.pow(psc_power); 43 let psc = 2u16.pow(psc_power);
44 44
45 #[cfg(not(iwdg_v3))]
46 assert!(psc <= 256, "IWDG prescaler should be no more than 256");
47 #[cfg(iwdg_v3)] // H5, U5, WBA
48 assert!(psc <= 1024, "IWDG prescaler should be no more than 1024");
49
45 // Convert prescaler power to PR register value 50 // Convert prescaler power to PR register value
46 let pr = psc_power as u8 - 2; 51 let pr = psc_power as u8 - 2;
47 assert!(pr <= 0b110);
48 52
49 // Reload value 53 // Reload value
50 let rl = reload_value(psc, timeout_us); 54 let rl = reload_value(psc, timeout_us);
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index ff7129303..01db0d09a 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -507,6 +507,16 @@ where
507 Receiver { channel: self } 507 Receiver { channel: self }
508 } 508 }
509 509
510 /// Get a sender for this channel using dynamic dispatch.
511 pub fn dyn_sender(&self) -> DynamicSender<'_, T> {
512 DynamicSender { channel: self }
513 }
514
515 /// Get a receiver for this channel using dynamic dispatch.
516 pub fn dyn_receiver(&self) -> DynamicReceiver<'_, T> {
517 DynamicReceiver { channel: self }
518 }
519
510 /// Send a value, waiting until there is capacity. 520 /// Send a value, waiting until there is capacity.
511 /// 521 ///
512 /// Sending completes when the value has been pushed to the channel's queue. 522 /// Sending completes when the value has been pushed to the channel's queue.
@@ -648,7 +658,7 @@ mod tests {
648 } 658 }
649 659
650 #[test] 660 #[test]
651 fn dynamic_dispatch() { 661 fn dynamic_dispatch_into() {
652 let c = Channel::<NoopRawMutex, u32, 3>::new(); 662 let c = Channel::<NoopRawMutex, u32, 3>::new();
653 let s: DynamicSender<'_, u32> = c.sender().into(); 663 let s: DynamicSender<'_, u32> = c.sender().into();
654 let r: DynamicReceiver<'_, u32> = c.receiver().into(); 664 let r: DynamicReceiver<'_, u32> = c.receiver().into();
@@ -657,6 +667,16 @@ mod tests {
657 assert_eq!(r.try_receive().unwrap(), 1); 667 assert_eq!(r.try_receive().unwrap(), 1);
658 } 668 }
659 669
670 #[test]
671 fn dynamic_dispatch_constructor() {
672 let c = Channel::<NoopRawMutex, u32, 3>::new();
673 let s = c.dyn_sender();
674 let r = c.dyn_receiver();
675
676 assert!(s.try_send(1).is_ok());
677 assert_eq!(r.try_receive().unwrap(), 1);
678 }
679
660 #[futures_test::test] 680 #[futures_test::test]
661 async fn receiver_receives_given_try_send_async() { 681 async fn receiver_receives_given_try_send_async() {
662 let executor = ThreadPool::new().unwrap(); 682 let executor = ThreadPool::new().unwrap();
diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs
index bd75c0135..e77678c24 100644
--- a/embassy-sync/src/priority_channel.rs
+++ b/embassy-sync/src/priority_channel.rs
@@ -325,7 +325,7 @@ where
325/// 325///
326/// Sent data may be reordered based on their priorty within the channel. 326/// Sent data may be reordered based on their priorty within the channel.
327/// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`] 327/// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`]
328/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be recieved as `[3, 2, 1]`. 328/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be received as `[3, 2, 1]`.
329pub struct PriorityChannel<M, T, K, const N: usize> 329pub struct PriorityChannel<M, T, K, const N: usize>
330where 330where
331 T: Ord, 331 T: Ord,
diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs
index d95ffa7c9..81e60c42b 100644
--- a/embassy-sync/src/ring_buffer.rs
+++ b/embassy-sync/src/ring_buffer.rs
@@ -3,7 +3,7 @@ use core::ops::Range;
3pub struct RingBuffer<const N: usize> { 3pub struct RingBuffer<const N: usize> {
4 start: usize, 4 start: usize,
5 end: usize, 5 end: usize,
6 empty: bool, 6 full: bool,
7} 7}
8 8
9impl<const N: usize> RingBuffer<N> { 9impl<const N: usize> RingBuffer<N> {
@@ -11,13 +11,13 @@ impl<const N: usize> RingBuffer<N> {
11 Self { 11 Self {
12 start: 0, 12 start: 0,
13 end: 0, 13 end: 0,
14 empty: true, 14 full: false,
15 } 15 }
16 } 16 }
17 17
18 pub fn push_buf(&mut self) -> Range<usize> { 18 pub fn push_buf(&mut self) -> Range<usize> {
19 if self.start == self.end && !self.empty { 19 if self.is_full() {
20 trace!(" ringbuf: push_buf empty"); 20 trace!(" ringbuf: push_buf full");
21 return 0..0; 21 return 0..0;
22 } 22 }
23 23
@@ -38,11 +38,11 @@ impl<const N: usize> RingBuffer<N> {
38 } 38 }
39 39
40 self.end = self.wrap(self.end + n); 40 self.end = self.wrap(self.end + n);
41 self.empty = false; 41 self.full = self.start == self.end;
42 } 42 }
43 43
44 pub fn pop_buf(&mut self) -> Range<usize> { 44 pub fn pop_buf(&mut self) -> Range<usize> {
45 if self.empty { 45 if self.is_empty() {
46 trace!(" ringbuf: pop_buf empty"); 46 trace!(" ringbuf: pop_buf empty");
47 return 0..0; 47 return 0..0;
48 } 48 }
@@ -64,20 +64,20 @@ impl<const N: usize> RingBuffer<N> {
64 } 64 }
65 65
66 self.start = self.wrap(self.start + n); 66 self.start = self.wrap(self.start + n);
67 self.empty = self.start == self.end; 67 self.full = false;
68 } 68 }
69 69
70 pub fn is_full(&self) -> bool { 70 pub fn is_full(&self) -> bool {
71 self.start == self.end && !self.empty 71 self.full
72 } 72 }
73 73
74 pub fn is_empty(&self) -> bool { 74 pub fn is_empty(&self) -> bool {
75 self.empty 75 self.start == self.end && !self.full
76 } 76 }
77 77
78 #[allow(unused)] 78 #[allow(unused)]
79 pub fn len(&self) -> usize { 79 pub fn len(&self) -> usize {
80 if self.empty { 80 if self.is_empty() {
81 0 81 0
82 } else if self.start < self.end { 82 } else if self.start < self.end {
83 self.end - self.start 83 self.end - self.start
@@ -89,7 +89,7 @@ impl<const N: usize> RingBuffer<N> {
89 pub fn clear(&mut self) { 89 pub fn clear(&mut self) {
90 self.start = 0; 90 self.start = 0;
91 self.end = 0; 91 self.end = 0;
92 self.empty = true; 92 self.full = false;
93 } 93 }
94 94
95 fn wrap(&self, n: usize) -> usize { 95 fn wrap(&self, n: usize) -> usize {
diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs
index f704cbd5d..cfce9a571 100644
--- a/embassy-sync/src/zerocopy_channel.rs
+++ b/embassy-sync/src/zerocopy_channel.rs
@@ -1,10 +1,7 @@
1//! A zero-copy queue for sending values between asynchronous tasks. 1//! A zero-copy queue for sending values between asynchronous tasks.
2//! 2//!
3//! It can be used concurrently by multiple producers (senders) and multiple 3//! It can be used concurrently by a producer (sender) and a
4//! consumers (receivers), i.e. it is an "MPMC channel". 4//! consumer (receiver), i.e. it is an "SPSC channel".
5//!
6//! Receivers are competing for messages. So a message that is received by
7//! one receiver is not received by any other.
8//! 5//!
9//! This queue takes a Mutex type so that various 6//! This queue takes a Mutex type so that various
10//! targets can be attained. For example, a ThreadModeMutex can be used 7//! targets can be attained. For example, a ThreadModeMutex can be used
diff --git a/embassy-time/src/delay.rs b/embassy-time/src/delay.rs
index 7ef5961f0..f77859d4a 100644
--- a/embassy-time/src/delay.rs
+++ b/embassy-time/src/delay.rs
@@ -13,6 +13,7 @@ pub fn block_for(duration: Duration) {
13/// the amount provided, but accuracy can be affected by many factors, including interrupt usage. 13/// the amount provided, but accuracy can be affected by many factors, including interrupt usage.
14/// Make sure to use a suitable tick rate for your use case. The tick rate is defined by the currently 14/// Make sure to use a suitable tick rate for your use case. The tick rate is defined by the currently
15/// active driver. 15/// active driver.
16#[derive(Clone)]
16pub struct Delay; 17pub struct Delay;
17 18
18impl embedded_hal_1::delay::DelayNs for Delay { 19impl embedded_hal_1::delay::DelayNs for Delay {
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index d27eb92f6..3c8575ee9 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -32,7 +32,7 @@ pub use delay::{block_for, Delay};
32pub use duration::Duration; 32pub use duration::Duration;
33pub use embassy_time_driver::TICK_HZ; 33pub use embassy_time_driver::TICK_HZ;
34pub use instant::Instant; 34pub use instant::Instant;
35pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; 35pub use timer::{with_deadline, with_timeout, Ticker, TimeoutError, Timer};
36 36
37const fn gcd(a: u64, b: u64) -> u64 { 37const fn gcd(a: u64, b: u64) -> u64 {
38 if b == 0 { 38 if b == 0 {
diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs
index 565a65cb8..daa4c1699 100644
--- a/embassy-time/src/timer.rs
+++ b/embassy-time/src/timer.rs
@@ -8,7 +8,7 @@ use futures_util::{pin_mut, Stream};
8 8
9use crate::{Duration, Instant}; 9use crate::{Duration, Instant};
10 10
11/// Error returned by [`with_timeout`] on timeout. 11/// Error returned by [`with_timeout`] and [`with_deadline`] on timeout.
12#[derive(Debug, Clone, PartialEq, Eq)] 12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))] 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14pub struct TimeoutError; 14pub struct TimeoutError;
@@ -26,6 +26,19 @@ pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Out
26 } 26 }
27} 27}
28 28
29/// Runs a given future with a deadline time.
30///
31/// If the future completes before the deadline, its output is returned. Otherwise, on timeout,
32/// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned.
33pub async fn with_deadline<F: Future>(at: Instant, fut: F) -> Result<F::Output, TimeoutError> {
34 let timeout_fut = Timer::at(at);
35 pin_mut!(fut);
36 match select(fut, timeout_fut).await {
37 Either::Left((r, _)) => Ok(r),
38 Either::Right(_) => Err(TimeoutError),
39 }
40}
41
29/// A future that completes at a specified [Instant](struct.Instant.html). 42/// A future that completes at a specified [Instant](struct.Instant.html).
30#[must_use = "futures do nothing unless you `.await` or poll them"] 43#[must_use = "futures do nothing unless you `.await` or poll them"]
31pub struct Timer { 44pub struct Timer {
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index 1ca5fea42..4d6ffeb5f 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -12,14 +12,24 @@ categories = [
12 "asynchronous" 12 "asynchronous"
13] 13]
14 14
15# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15[package.metadata.embassy_docs]
16src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-v$VERSION/embassy-usb-dfu/src/"
17src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-dfu/src/"
18features = ["defmt", "cortex-m"]
19target = "thumbv7em-none-eabi"
20flavors = [
21 { name = "dfu", features = [ "dfu" ] },
22 { name = "application", features = [ "application" ] },
23]
24
25[package.metadata.docs.rs]
26features = ["defmt", "cortex-m", "dfu"]
16 27
17[dependencies] 28[dependencies]
18bitflags = "2.4.1" 29bitflags = "2.4.1"
19cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } 30cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
20defmt = { version = "0.3.5", optional = true } 31defmt = { version = "0.3.5", optional = true }
21embassy-boot = { version = "0.2.0", path = "../embassy-boot" } 32embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
22# embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
23embassy-futures = { version = "0.1.1", path = "../embassy-futures" } 33embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
24embassy-sync = { version = "0.5.0", path = "../embassy-sync" } 34embassy-sync = { version = "0.5.0", path = "../embassy-sync" }
25embassy-time = { version = "0.3.0", path = "../embassy-time" } 35embassy-time = { version = "0.3.0", path = "../embassy-time" }
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
index 45d780bf8..da5ff0f36 100644
--- a/embassy-usb-logger/src/lib.rs
+++ b/embassy-usb-logger/src/lib.rs
@@ -6,7 +6,7 @@ use core::fmt::Write as _;
6 6
7use embassy_futures::join::join; 7use embassy_futures::join::join;
8use embassy_sync::pipe::Pipe; 8use embassy_sync::pipe::Pipe;
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State};
10use embassy_usb::driver::Driver; 10use embassy_usb::driver::Driver;
11use embassy_usb::{Builder, Config}; 11use embassy_usb::{Builder, Config};
12use log::{Metadata, Record}; 12use log::{Metadata, Record};
@@ -37,6 +37,9 @@ impl<'d> LoggerState<'d> {
37 } 37 }
38} 38}
39 39
40/// The packet size used in the usb logger, to be used with `create_future_from_class`
41pub const MAX_PACKET_SIZE: u8 = 64;
42
40/// The logger handle, which contains a pipe with configurable size for buffering log messages. 43/// The logger handle, which contains a pipe with configurable size for buffering log messages.
41pub struct UsbLogger<const N: usize> { 44pub struct UsbLogger<const N: usize> {
42 buffer: Pipe<CS, N>, 45 buffer: Pipe<CS, N>,
@@ -54,7 +57,6 @@ impl<const N: usize> UsbLogger<N> {
54 D: Driver<'d>, 57 D: Driver<'d>,
55 Self: 'd, 58 Self: 'd,
56 { 59 {
57 const MAX_PACKET_SIZE: u8 = 64;
58 let mut config = Config::new(0xc0de, 0xcafe); 60 let mut config = Config::new(0xc0de, 0xcafe);
59 config.manufacturer = Some("Embassy"); 61 config.manufacturer = Some("Embassy");
60 config.product = Some("USB-serial logger"); 62 config.product = Some("USB-serial logger");
@@ -87,22 +89,46 @@ impl<const N: usize> UsbLogger<N> {
87 let mut device = builder.build(); 89 let mut device = builder.build();
88 loop { 90 loop {
89 let run_fut = device.run(); 91 let run_fut = device.run();
90 let log_fut = async { 92 let class_fut = self.run_logger_class(&mut sender, &mut receiver);
91 let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; 93 join(run_fut, class_fut).await;
92 sender.wait_connection().await; 94 }
93 loop { 95 }
94 let len = self.buffer.read(&mut rx[..]).await; 96
95 let _ = sender.write_packet(&rx[..len]).await; 97 async fn run_logger_class<'d, D>(&self, sender: &mut Sender<'d, D>, receiver: &mut Receiver<'d, D>)
96 } 98 where
97 }; 99 D: Driver<'d>,
98 let discard_fut = async { 100 {
99 let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; 101 let log_fut = async {
100 receiver.wait_connection().await; 102 let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize];
101 loop { 103 sender.wait_connection().await;
102 let _ = receiver.read_packet(&mut discard_buf).await; 104 loop {
105 let len = self.buffer.read(&mut rx[..]).await;
106 let _ = sender.write_packet(&rx[..len]).await;
107 if len as u8 == MAX_PACKET_SIZE {
108 let _ = sender.write_packet(&[]).await;
103 } 109 }
104 }; 110 }
105 join(run_fut, join(log_fut, discard_fut)).await; 111 };
112 let discard_fut = async {
113 let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize];
114 receiver.wait_connection().await;
115 loop {
116 let _ = receiver.read_packet(&mut discard_buf).await;
117 }
118 };
119
120 join(log_fut, discard_fut).await;
121 }
122
123 /// Creates the futures needed for the logger from a given class
124 /// This can be used in cases where the usb device is already in use for another connection
125 pub async fn create_future_from_class<'d, D>(&'d self, class: CdcAcmClass<'d, D>)
126 where
127 D: Driver<'d>,
128 {
129 let (mut sender, mut receiver) = class.split();
130 loop {
131 self.run_logger_class(&mut sender, &mut receiver).await;
106 } 132 }
107 } 133 }
108} 134}
@@ -153,3 +179,27 @@ macro_rules! run {
153 let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; 179 let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await;
154 }; 180 };
155} 181}
182
183/// Initialize the USB serial logger from a serial class and return the future to run it.
184///
185/// Arguments specify the buffer size, log level and the serial class, respectively.
186///
187/// # Usage
188///
189/// ```
190/// embassy_usb_logger::with_class!(1024, log::LevelFilter::Info, class);
191/// ```
192///
193/// # Safety
194///
195/// This macro should only be invoked only once since it is setting the global logging state of the application.
196#[macro_export]
197macro_rules! with_class {
198 ( $x:expr, $l:expr, $p:ident ) => {{
199 static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new();
200 unsafe {
201 let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l));
202 }
203 LOGGER.create_future_from_class($p)
204 }};
205}
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 1b31b6145..fe5e36b32 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -56,5 +56,5 @@ log = { version = "0.4.14", optional = true }
56heapless = "0.8" 56heapless = "0.8"
57 57
58# for HID 58# for HID
59usbd-hid = { version = "0.6.0", optional = true } 59usbd-hid = { version = "0.7.0", optional = true }
60ssmarshal = { version = "1.0", default-features = false, optional = true } 60ssmarshal = { version = "1.0", default-features = false, optional = true }
diff --git a/embassy-usb/README.md b/embassy-usb/README.md
index 7411fcf52..d2adae4f5 100644
--- a/embassy-usb/README.md
+++ b/embassy-usb/README.md
@@ -9,7 +9,7 @@ Async USB device stack for embedded devices in Rust.
9- Suspend/resume, remote wakeup. 9- Suspend/resume, remote wakeup.
10- USB composite devices. 10- USB composite devices.
11- Ergonomic descriptor builder. 11- Ergonomic descriptor builder.
12- Ready-to-use implementations for a few USB classes (note you can still implement any class yourself oustide the crate). 12- Ready-to-use implementations for a few USB classes (note you can still implement any class yourself outside the crate).
13 - Serial ports (CDC ACM) 13 - Serial ports (CDC ACM)
14 - Ethernet (CDC NCM) 14 - Ethernet (CDC NCM)
15 - Human Interface Devices (HID) 15 - Human Interface Devices (HID)
diff --git a/examples/boot/.cargo/config.toml b/examples/boot/.cargo/config.toml
index de3a814f7..be1b73e45 100644
--- a/examples/boot/.cargo/config.toml
+++ b/examples/boot/.cargo/config.toml
@@ -1,6 +1,6 @@
1[unstable] 1[unstable]
2build-std = ["core"] 2#build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3#build-std-features = ["panic_immediate_abort"]
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index f3abfddbc..851a3d721 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -50,7 +50,7 @@ async fn main(_spawner: Spawner) {
50 let nvmc = Nvmc::new(p.NVMC); 50 let nvmc = Nvmc::new(p.NVMC);
51 let nvmc = Mutex::new(BlockingAsync::new(nvmc)); 51 let nvmc = Mutex::new(BlockingAsync::new(nvmc));
52 52
53 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc); 53 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
54 let mut magic = [0; 4]; 54 let mut magic = [0; 4];
55 let mut updater = FirmwareUpdater::new(config, &mut magic); 55 let mut updater = FirmwareUpdater::new(config, &mut magic);
56 loop { 56 loop {
diff --git a/examples/boot/application/rp/.cargo/config.toml b/examples/boot/application/rp/.cargo/config.toml
index cd8d1ef02..22ab3a5c1 100644
--- a/examples/boot/application/rp/.cargo/config.toml
+++ b/examples/boot/application/rp/.cargo/config.toml
@@ -1,6 +1,6 @@
1[unstable] 1[unstable]
2build-std = ["core"] 2#build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3#build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "probe-rs run --chip RP2040" 6runner = "probe-rs run --chip RP2040"
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index 3f0bf90e2..ede0c07da 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -36,7 +36,7 @@ async fn main(_s: Spawner) {
36 let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH); 36 let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH);
37 let flash = Mutex::new(RefCell::new(flash)); 37 let flash = Mutex::new(RefCell::new(flash));
38 38
39 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 39 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
40 let mut aligned = AlignedBuffer([0; 1]); 40 let mut aligned = AlignedBuffer([0; 1]);
41 let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0); 41 let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0);
42 42
diff --git a/examples/boot/application/stm32f3/memory.x b/examples/boot/application/stm32f3/memory.x
index f51875766..02ebe3ecf 100644
--- a/examples/boot/application/stm32f3/memory.x
+++ b/examples/boot/application/stm32f3/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 66K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index 96ae5c47b..8858ae3da 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::flash::{Flash, WRITE_SIZE}; 10use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 11use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
13use panic_reset as _; 13use panic_reset as _;
14 14
@@ -23,13 +23,12 @@ async fn main(_spawner: Spawner) {
23 let flash = Flash::new_blocking(p.FLASH); 23 let flash = Flash::new_blocking(p.FLASH);
24 let flash = Mutex::new(BlockingAsync::new(flash)); 24 let flash = Mutex::new(BlockingAsync::new(flash));
25 25
26 let button = Input::new(p.PC13, Pull::Up); 26 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
27 let mut button = ExtiInput::new(button, p.EXTI13);
28 27
29 let mut led = Output::new(p.PA5, Level::Low, Speed::Low); 28 let mut led = Output::new(p.PA5, Level::Low, Speed::Low);
30 led.set_high(); 29 led.set_high();
31 30
32 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
33 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 32 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
34 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 33 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
35 button.wait_for_falling_edge().await; 34 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index a6107386a..d3df11fe4 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -9,7 +9,7 @@ use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdater
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Level, Output, Pull, Speed};
13use embassy_sync::blocking_mutex::Mutex; 13use embassy_sync::blocking_mutex::Mutex;
14use embedded_storage::nor_flash::NorFlash; 14use embedded_storage::nor_flash::NorFlash;
15use panic_reset as _; 15use panic_reset as _;
@@ -25,13 +25,12 @@ async fn main(_spawner: Spawner) {
25 let flash = Flash::new_blocking(p.FLASH); 25 let flash = Flash::new_blocking(p.FLASH);
26 let flash = Mutex::new(RefCell::new(flash)); 26 let flash = Mutex::new(RefCell::new(flash));
27 27
28 let button = Input::new(p.PC13, Pull::Down); 28 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
29 let mut button = ExtiInput::new(button, p.EXTI13);
30 29
31 let mut led = Output::new(p.PB7, Level::Low, Speed::Low); 30 let mut led = Output::new(p.PB7, Level::Low, Speed::Low);
32 led.set_high(); 31 led.set_high();
33 32
34 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
35 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
36 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0);
37 let writer = updater.prepare_update().unwrap(); 36 let writer = updater.prepare_update().unwrap();
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index b73506cf3..f61ac1f71 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -9,7 +9,7 @@ use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdater
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Level, Output, Pull, Speed};
13use embassy_sync::blocking_mutex::Mutex; 13use embassy_sync::blocking_mutex::Mutex;
14use embedded_storage::nor_flash::NorFlash; 14use embedded_storage::nor_flash::NorFlash;
15use panic_reset as _; 15use panic_reset as _;
@@ -25,13 +25,12 @@ async fn main(_spawner: Spawner) {
25 let flash = Flash::new_blocking(p.FLASH); 25 let flash = Flash::new_blocking(p.FLASH);
26 let flash = Mutex::new(RefCell::new(flash)); 26 let flash = Mutex::new(RefCell::new(flash));
27 27
28 let button = Input::new(p.PC13, Pull::Down); 28 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
29 let mut button = ExtiInput::new(button, p.EXTI13);
30 29
31 let mut led = Output::new(p.PB14, Level::Low, Speed::Low); 30 let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
32 led.set_high(); 31 led.set_high();
33 32
34 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
35 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
36 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0);
37 let writer = updater.prepare_update().unwrap(); 36 let writer = updater.prepare_update().unwrap();
diff --git a/examples/boot/application/stm32l0/memory.x b/examples/boot/application/stm32l0/memory.x
index a99330145..8866506a8 100644
--- a/examples/boot/application/stm32l0/memory.x
+++ b/examples/boot/application/stm32l0/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 66K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
9} 9}
10 10
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index 02f74bdef..f066c1139 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::flash::{Flash, WRITE_SIZE}; 10use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 11use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
13use embassy_time::Timer; 13use embassy_time::Timer;
14use panic_reset as _; 14use panic_reset as _;
@@ -24,14 +24,13 @@ async fn main(_spawner: Spawner) {
24 let flash = Flash::new_blocking(p.FLASH); 24 let flash = Flash::new_blocking(p.FLASH);
25 let flash = Mutex::new(BlockingAsync::new(flash)); 25 let flash = Mutex::new(BlockingAsync::new(flash));
26 26
27 let button = Input::new(p.PB2, Pull::Up); 27 let mut button = ExtiInput::new(p.PB2, p.EXTI2, Pull::Up);
28 let mut button = ExtiInput::new(button, p.EXTI2);
29 28
30 let mut led = Output::new(p.PB5, Level::Low, Speed::Low); 29 let mut led = Output::new(p.PB5, Level::Low, Speed::Low);
31 30
32 led.set_high(); 31 led.set_high();
33 32
34 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
35 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
36 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
37 button.wait_for_falling_edge().await; 36 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32l1/memory.x b/examples/boot/application/stm32l1/memory.x
index a99330145..caa525278 100644
--- a/examples/boot/application/stm32l1/memory.x
+++ b/examples/boot/application/stm32l1/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 46K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08013800, LENGTH = 54K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
9} 9}
10 10
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index 02f74bdef..f066c1139 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::flash::{Flash, WRITE_SIZE}; 10use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 11use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
13use embassy_time::Timer; 13use embassy_time::Timer;
14use panic_reset as _; 14use panic_reset as _;
@@ -24,14 +24,13 @@ async fn main(_spawner: Spawner) {
24 let flash = Flash::new_blocking(p.FLASH); 24 let flash = Flash::new_blocking(p.FLASH);
25 let flash = Mutex::new(BlockingAsync::new(flash)); 25 let flash = Mutex::new(BlockingAsync::new(flash));
26 26
27 let button = Input::new(p.PB2, Pull::Up); 27 let mut button = ExtiInput::new(p.PB2, p.EXTI2, Pull::Up);
28 let mut button = ExtiInput::new(button, p.EXTI2);
29 28
30 let mut led = Output::new(p.PB5, Level::Low, Speed::Low); 29 let mut led = Output::new(p.PB5, Level::Low, Speed::Low);
31 30
32 led.set_high(); 31 led.set_high();
33 32
34 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
35 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
36 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
37 button.wait_for_falling_edge().await; 36 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32l4/memory.x b/examples/boot/application/stm32l4/memory.x
index f51875766..e1d4e7fa8 100644
--- a/examples/boot/application/stm32l4/memory.x
+++ b/examples/boot/application/stm32l4/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index 892446968..a0079ee33 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::flash::{Flash, WRITE_SIZE}; 10use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 11use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
13use panic_reset as _; 13use panic_reset as _;
14 14
@@ -23,13 +23,12 @@ async fn main(_spawner: Spawner) {
23 let flash = Flash::new_blocking(p.FLASH); 23 let flash = Flash::new_blocking(p.FLASH);
24 let flash = Mutex::new(BlockingAsync::new(flash)); 24 let flash = Mutex::new(BlockingAsync::new(flash));
25 25
26 let button = Input::new(p.PC13, Pull::Up); 26 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
27 let mut button = ExtiInput::new(button, p.EXTI13);
28 27
29 let mut led = Output::new(p.PB14, Level::Low, Speed::Low); 28 let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
30 led.set_high(); 29 led.set_high();
31 30
32 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
33 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 32 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
34 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 33 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
35 button.wait_for_falling_edge().await; 34 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32wb-dfu/README.md b/examples/boot/application/stm32wb-dfu/README.md
index c8dce0387..7f656cde6 100644
--- a/examples/boot/application/stm32wb-dfu/README.md
+++ b/examples/boot/application/stm32wb-dfu/README.md
@@ -1,29 +1,9 @@
1# Examples using bootloader 1# Examples using bootloader
2 2
3Example for STM32WL demonstrating the bootloader. The example consists of application binaries, 'a' 3Example for STM32WB demonstrating the USB DFU application.
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 4
14## Usage 5## Usage
15 6
16``` 7```
17# Flash bootloader 8cargo flash --release --chip STM32WB55RGVx
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``` 9```
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index b2ccb9e1a..37c3d7d90 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
30 let flash = Flash::new_blocking(p.FLASH); 30 let flash = Flash::new_blocking(p.FLASH);
31 let flash = Mutex::new(RefCell::new(flash)); 31 let flash = Mutex::new(RefCell::new(flash));
32 32
33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
34 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
35 let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0); 35 let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0);
36 firmware_state.mark_booted().expect("Failed to mark booted"); 36 firmware_state.mark_booted().expect("Failed to mark booted");
diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x
index f51875766..e1d4e7fa8 100644
--- a/examples/boot/application/stm32wl/memory.x
+++ b/examples/boot/application/stm32wl/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index d9665e6ee..2fb16bdc4 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -8,7 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::flash::{Flash, WRITE_SIZE}; 10use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 11use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_sync::mutex::Mutex; 12use embassy_sync::mutex::Mutex;
13use panic_reset as _; 13use panic_reset as _;
14 14
@@ -23,13 +23,12 @@ async fn main(_spawner: Spawner) {
23 let flash = Flash::new_blocking(p.FLASH); 23 let flash = Flash::new_blocking(p.FLASH);
24 let flash = Mutex::new(BlockingAsync::new(flash)); 24 let flash = Mutex::new(BlockingAsync::new(flash));
25 25
26 let button = Input::new(p.PA0, Pull::Up); 26 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up);
27 let mut button = ExtiInput::new(button, p.EXTI0);
28 27
29 let mut led = Output::new(p.PB9, Level::Low, Speed::Low); 28 let mut led = Output::new(p.PB9, Level::Low, Speed::Low);
30 led.set_high(); 29 led.set_high();
31 30
32 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
33 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 32 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
34 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 33 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
35 button.wait_for_falling_edge().await; 34 button.wait_for_falling_edge().await;
diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml
index c292846aa..58acd1a49 100644
--- a/examples/boot/bootloader/nrf/.cargo/config.toml
+++ b/examples/boot/bootloader/nrf/.cargo/config.toml
@@ -1,6 +1,6 @@
1[unstable] 1[unstable]
2build-std = ["core"] 2#build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3#build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6#runner = "./fruitrunner" 6#runner = "./fruitrunner"
@@ -8,7 +8,7 @@ runner = "probe-rs run --chip nrf52840_xxAA"
8 8
9rustflags = [ 9rustflags = [
10 # Code-size optimizations. 10 # Code-size optimizations.
11 "-Z", "trap-unreachable=no", 11 #"-Z", "trap-unreachable=no",
12 #"-C", "no-vectorize-loops", 12 #"-C", "no-vectorize-loops",
13 "-C", "force-frame-pointers=yes", 13 "-C", "force-frame-pointers=yes",
14] 14]
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 74e2e293f..67c700437 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -31,7 +31,7 @@ fn main() -> ! {
31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); 31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
32 let flash = Mutex::new(RefCell::new(flash)); 32 let flash = Mutex::new(RefCell::new(flash));
33 33
34 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 34 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
35 let active_offset = config.active.offset(); 35 let active_offset = config.active.offset();
36 let bl: BootLoader = BootLoader::prepare(config); 36 let bl: BootLoader = BootLoader::prepare(config);
37 37
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
index c0e75d1ea..25b1657b8 100644
--- a/examples/boot/bootloader/rp/src/main.rs
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -27,7 +27,7 @@ fn main() -> ! {
27 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8)); 27 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8));
28 let flash = Mutex::new(RefCell::new(flash)); 28 let flash = Mutex::new(RefCell::new(flash));
29 29
30 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 30 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
31 let active_offset = config.active.offset(); 31 let active_offset = config.active.offset();
32 let bl: BootLoader = BootLoader::prepare(config); 32 let bl: BootLoader = BootLoader::prepare(config);
33 33
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
new file mode 100644
index 000000000..313187adc
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
@@ -0,0 +1,57 @@
1[package]
2edition = "2021"
3name = "stm32-bootloader-dual-bank-flash-example"
4version = "0.1.0"
5description = "Example bootloader for dual-bank flash STM32 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 = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = [
15 "inline-asm",
16 "critical-section-single-core",
17] }
18embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
19cortex-m-rt = { version = "0.7" }
20embedded-storage = "0.3.1"
21embedded-storage-async = "0.4.0"
22cfg-if = "1.0.0"
23
24[features]
25defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"]
26debug = ["defmt-rtt", "defmt"]
27
28[profile.dev]
29debug = 2
30debug-assertions = true
31incremental = false
32opt-level = 'z'
33overflow-checks = true
34
35[profile.release]
36codegen-units = 1
37debug = 2
38debug-assertions = false
39incremental = false
40lto = 'fat'
41opt-level = 'z'
42overflow-checks = false
43
44# do not optimize proc-macro crates = faster builds from scratch
45[profile.dev.build-override]
46codegen-units = 8
47debug = false
48debug-assertions = false
49opt-level = 0
50overflow-checks = false
51
52[profile.release.build-override]
53codegen-units = 8
54debug = false
55debug-assertions = false
56opt-level = 0
57overflow-checks = false
diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md
new file mode 100644
index 000000000..3de3171cd
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/README.md
@@ -0,0 +1,44 @@
1# STM32 dual-bank flash Bootloader
2
3## Overview
4
5This bootloader leverages `embassy-boot` to interact with the flash.
6This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series.
7Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device.
8
9Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions.
10
11## Memory Configuration
12
13In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment.
14For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks.
15
16### Symbol Definitions
17
18The bootloader's state and active symbols are anchored to the flash origin of **bank 1**:
19
20- `__bootloader_state_start` and `__bootloader_state_end`
21- `__bootloader_active_start` and `__bootloader_active_end`
22
23In contrast, the Device Firmware Upgrade (DFU) symbols are aligned with the DFU flash origin in **bank 2**:
24
25- `__bootloader_dfu_start` and `__bootloader_dfu_end`
26
27```rust
28__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(**FLASH**);
29__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(**FLASH**);
30
31__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(**FLASH**);
32__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(**FLASH**);
33
34__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(**DFU**);
35__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(**DFU**);
36```
37
38## Flashing the Bootloader
39
40To flash the bootloader onto your STM32H747XI device, use the following command:
41
42```bash
43cargo flash --features embassy-stm32/stm32h747xi-cm7 --release --chip STM32H747XIHx
44```
diff --git a/examples/boot/bootloader/stm32-dual-bank/build.rs b/examples/boot/bootloader/stm32-dual-bank/build.rs
new file mode 100644
index 000000000..fd605991f
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/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/stm32-dual-bank/memory.x b/examples/boot/bootloader/stm32-dual-bank/memory.x
new file mode 100644
index 000000000..665da7139
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/memory.x
@@ -0,0 +1,18 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 128K
5 BOOTLOADER_STATE : ORIGIN = 0x08020000, LENGTH = 128K
6 ACTIVE : ORIGIN = 0x08040000, LENGTH = 512K
7 DFU : ORIGIN = 0x08100000, LENGTH = 640K
8 RAM (rwx) : ORIGIN = 0x24000000, LENGTH = 512K
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(DFU);
18__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(DFU);
diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
new file mode 100644
index 000000000..4d2e82d26
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
@@ -0,0 +1,53 @@
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};
11use embassy_sync::blocking_mutex::Mutex;
12
13#[entry]
14fn main() -> ! {
15 let p = embassy_stm32::init(Default::default());
16
17 // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
18 // as it prevents a hard fault when accessing flash 'too early' after boot.
19 /*
20 for i in 0..10000000 {
21 cortex_m::asm::nop();
22 }
23 */
24
25 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
26 let flash_bank1 = Mutex::new(RefCell::new(layout.bank1_region));
27 let flash_bank2 = Mutex::new(RefCell::new(layout.bank2_region));
28
29 let config = BootLoaderConfig::from_linkerfile_blocking(&flash_bank1, &flash_bank2, &flash_bank1);
30 let active_offset = config.active.offset();
31 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
32
33 unsafe { bl.load(BANK1_REGION.base + active_offset) }
34}
35
36#[no_mangle]
37#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
38unsafe extern "C" fn HardFault() {
39 cortex_m::peripheral::SCB::sys_reset();
40}
41
42#[exception]
43unsafe fn DefaultHandler(_: i16) -> ! {
44 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
45 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
46
47 panic!("DefaultHandler #{:?}", irqn);
48}
49
50#[panic_handler]
51fn panic(_info: &core::panic::PanicInfo) -> ! {
52 cortex_m::asm::udf();
53}
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 5fd9ea588..99a7a6a6b 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -25,7 +25,7 @@ fn main() -> ! {
25 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); 25 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
26 let flash = Mutex::new(RefCell::new(layout.bank1_region)); 26 let flash = Mutex::new(RefCell::new(layout.bank1_region));
27 27
28 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 28 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
29 let active_offset = config.active.offset(); 29 let active_offset = config.active.offset();
30 let bl = BootLoader::prepare::<_, _, _, 2048>(config); 30 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
31 31
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 96635afa2..854f94d85 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] } 12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } 13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md
index a82b730b9..d5c6ea57c 100644
--- a/examples/boot/bootloader/stm32wb-dfu/README.md
+++ b/examples/boot/bootloader/stm32wb-dfu/README.md
@@ -7,5 +7,5 @@ The bootloader uses `embassy-boot` to interact with the flash.
7Flash the bootloader 7Flash the bootloader
8 8
9``` 9```
10cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx 10cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx
11``` 11```
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index a7ab813b6..d989fbfdf 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -35,7 +35,7 @@ fn main() -> ! {
35 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); 35 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
36 let flash = Mutex::new(RefCell::new(layout.bank1_region)); 36 let flash = Mutex::new(RefCell::new(layout.bank1_region));
37 37
38 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 38 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
39 let active_offset = config.active.offset(); 39 let active_offset = config.active.offset();
40 let bl = BootLoader::prepare::<_, _, _, 2048>(config); 40 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
41 if bl.state == State::DfuDetach { 41 if bl.state == State::DfuDetach {
@@ -45,7 +45,7 @@ fn main() -> ! {
45 config.product = Some("USB-DFU Bootloader example"); 45 config.product = Some("USB-DFU Bootloader example");
46 config.serial_number = Some("1235678"); 46 config.serial_number = Some("1235678");
47 47
48 let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 48 let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
49 let mut buffer = AlignedBuffer([0; WRITE_SIZE]); 49 let mut buffer = AlignedBuffer([0; WRITE_SIZE]);
50 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); 50 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]);
51 51
diff --git a/examples/nrf51/.cargo/config.toml b/examples/nrf51/.cargo/config.toml
new file mode 100644
index 000000000..1671f5db1
--- /dev/null
+++ b/examples/nrf51/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF51422_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF51422_xxAA"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
new file mode 100644
index 000000000..06c3d20cb
--- /dev/null
+++ b/examples/nrf51/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf51-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
11
12defmt = "0.3"
13defmt-rtt = "0.4"
14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7"
17panic-probe = { version = "0.3", features = ["print-defmt"] }
18
19[profile.release]
20debug = 2
diff --git a/examples/nrf51/build.rs b/examples/nrf51/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf51/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf51/memory.x b/examples/nrf51/memory.x
new file mode 100644
index 000000000..98b3c792f
--- /dev/null
+++ b/examples/nrf51/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 128K
4 RAM : ORIGIN = 0x20000000, LENGTH = 16K
5}
diff --git a/examples/nrf51/src/bin/blinky.rs b/examples/nrf51/src/bin/blinky.rs
new file mode 100644
index 000000000..7c12ffcbc
--- /dev/null
+++ b/examples/nrf51/src/bin/blinky.rs
@@ -0,0 +1,20 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::gpio::{Level, Output, OutputDrive};
6use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut led = Output::new(p.P0_21, Level::Low, OutputDrive::Standard);
13
14 loop {
15 led.set_high();
16 Timer::after_millis(300).await;
17 led.set_low();
18 Timer::after_millis(300).await;
19 }
20}
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index abb995be6..4ab5c7b7c 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -28,7 +28,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
28futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 28futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
29rand = { version = "0.8.4", default-features = false } 29rand = { version = "0.8.4", default-features = false }
30embedded-storage = "0.3.1" 30embedded-storage = "0.3.1"
31usbd-hid = "0.6.0" 31usbd-hid = "0.7.0"
32serde = { version = "1.0.136", default-features = false } 32serde = { version = "1.0.136", default-features = false }
33embedded-hal = { version = "1.0" } 33embedded-hal = { version = "1.0" }
34embedded-hal-async = { version = "1.0" } 34embedded-hal-async = { version = "1.0" }
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index a8e64b38a..279f32edc 100644
--- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -24,10 +24,7 @@ bind_interrupts!(struct Irqs {
24#[embassy_executor::task] 24#[embassy_executor::task]
25async fn net_task( 25async fn net_task(
26 stack: &'static Stack< 26 stack: &'static Stack<
27 Enc28j60< 27 Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>,
28 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>,
29 Output<'static, peripherals::P0_13>,
30 >,
31 >, 28 >,
32) -> ! { 29) -> ! {
33 stack.run().await 30 stack.run().await
@@ -71,12 +68,7 @@ async fn main(spawner: Spawner) {
71 // Init network stack 68 // Init network stack
72 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 69 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
73 static STACK: StaticCell< 70 static STACK: StaticCell<
74 Stack< 71 Stack<Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>>,
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(); 72 > = StaticCell::new();
81 let stack = STACK.init(Stack::new( 73 let stack = STACK.init(Stack::new(
82 device, 74 device,
diff --git a/examples/nrf52840/src/bin/gpiote_port.rs b/examples/nrf52840/src/bin/gpiote_port.rs
index c1afe2f20..0dddb1a97 100644
--- a/examples/nrf52840/src/bin/gpiote_port.rs
+++ b/examples/nrf52840/src/bin/gpiote_port.rs
@@ -3,11 +3,11 @@
3 3
4use defmt::{info, unwrap}; 4use defmt::{info, unwrap};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; 6use embassy_nrf::gpio::{Input, Pull};
7use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
8 8
9#[embassy_executor::task(pool_size = 4)] 9#[embassy_executor::task(pool_size = 4)]
10async fn button_task(n: usize, mut pin: Input<'static, AnyPin>) { 10async fn button_task(n: usize, mut pin: Input<'static>) {
11 loop { 11 loop {
12 pin.wait_for_low().await; 12 pin.wait_for_low().await;
13 info!("Button {:?} pressed!", n); 13 info!("Button {:?} pressed!", n);
@@ -21,10 +21,10 @@ async fn main(spawner: Spawner) {
21 let p = embassy_nrf::init(Default::default()); 21 let p = embassy_nrf::init(Default::default());
22 info!("Starting!"); 22 info!("Starting!");
23 23
24 let btn1 = Input::new(p.P0_11.degrade(), Pull::Up); 24 let btn1 = Input::new(p.P0_11, Pull::Up);
25 let btn2 = Input::new(p.P0_12.degrade(), Pull::Up); 25 let btn2 = Input::new(p.P0_12, Pull::Up);
26 let btn3 = Input::new(p.P0_24.degrade(), Pull::Up); 26 let btn3 = Input::new(p.P0_24, Pull::Up);
27 let btn4 = Input::new(p.P0_25.degrade(), Pull::Up); 27 let btn4 = Input::new(p.P0_25, Pull::Up);
28 28
29 unwrap!(spawner.spawn(button_task(1, btn1))); 29 unwrap!(spawner.spawn(button_task(1, btn1)));
30 unwrap!(spawner.spawn(button_task(2, btn2))); 30 unwrap!(spawner.spawn(button_task(2, btn2)));
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 45850b4a4..3e86590c4 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -8,7 +8,7 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_futures::select::{select, Either}; 10use embassy_futures::select::{select, Either};
11use embassy_nrf::gpio::{Input, Pin, Pull}; 11use embassy_nrf::gpio::{Input, Pull};
12use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; 12use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
13use embassy_nrf::usb::Driver; 13use embassy_nrf::usb::Driver;
14use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 14use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
@@ -97,7 +97,7 @@ async fn main(_spawner: Spawner) {
97 } 97 }
98 }; 98 };
99 99
100 let mut button = Input::new(p.P0_11.degrade(), Pull::Up); 100 let mut button = Input::new(p.P0_11, Pull::Up);
101 101
102 let (reader, mut writer) = hid.split(); 102 let (reader, mut writer) = hid.split();
103 103
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index fc2086f75..00bd50081 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -5,7 +5,7 @@ use defmt::{info, unwrap, warn};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources}; 7use embassy_net::{Stack, StackResources};
8use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; 8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
9use embassy_nrf::rng::Rng; 9use embassy_nrf::rng::Rng;
10use embassy_nrf::spim::{self, Spim}; 10use embassy_nrf::spim::{self, Spim};
11use embassy_nrf::{bind_interrupts, peripherals}; 11use embassy_nrf::{bind_interrupts, peripherals};
@@ -27,9 +27,9 @@ bind_interrupts!(struct Irqs {
27async fn wifi_task( 27async fn wifi_task(
28 runner: hosted::Runner< 28 runner: hosted::Runner<
29 'static, 29 'static,
30 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>, Delay>, 30 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>,
31 Input<'static, AnyPin>, 31 Input<'static>,
32 Output<'static, peripherals::P1_05>, 32 Output<'static>,
33 >, 33 >,
34) -> ! { 34) -> ! {
35 runner.run().await 35 runner.run().await
@@ -50,8 +50,8 @@ async fn main(spawner: Spawner) {
50 let sck = p.P0_29; 50 let sck = p.P0_29;
51 let mosi = p.P0_30; 51 let mosi = p.P0_30;
52 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); 52 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
53 let handshake = Input::new(p.P1_01.degrade(), Pull::Up); 53 let handshake = Input::new(p.P1_01, Pull::Up);
54 let ready = Input::new(p.P1_04.degrade(), Pull::None); 54 let ready = Input::new(p.P1_04, Pull::None);
55 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); 55 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
56 56
57 let mut config = spim::Config::default(); 57 let mut config = spim::Config::default();
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 56b9c8018..24aa560d5 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -24,7 +24,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25rand = { version = "0.8.4", default-features = false } 25rand = { version = "0.8.4", default-features = false }
26embedded-storage = "0.3.1" 26embedded-storage = "0.3.1"
27usbd-hid = "0.6.0" 27usbd-hid = "0.7.0"
28serde = { version = "1.0.136", default-features = false } 28serde = { version = "1.0.136", default-features = false }
29 29
30[profile.release] 30[profile.release]
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index e1092dba4..585349506 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -36,7 +36,7 @@ display-interface = "0.4.1"
36byte-slice-cast = { version = "1.2.0", default-features = false } 36byte-slice-cast = { version = "1.2.0", default-features = false }
37smart-leds = "0.3.0" 37smart-leds = "0.3.0"
38heapless = "0.8" 38heapless = "0.8"
39usbd-hid = "0.6.1" 39usbd-hid = "0.7.0"
40 40
41embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 41embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
42embedded-hal-async = "1.0" 42embedded-hal-async = "1.0"
diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs
index a03f3a592..a57b513d6 100644
--- a/examples/rp/src/bin/blinky_two_tasks.rs
+++ b/examples/rp/src/bin/blinky_two_tasks.rs
@@ -14,7 +14,7 @@ use embassy_time::{Duration, Ticker};
14use gpio::{AnyPin, Level, Output}; 14use gpio::{AnyPin, Level, Output};
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static, AnyPin>>>; 17type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static>>>;
18static LED: LedType = Mutex::new(None); 18static LED: LedType = Mutex::new(None);
19 19
20#[embassy_executor::main] 20#[embassy_executor::main]
diff --git a/examples/rp/src/bin/debounce.rs b/examples/rp/src/bin/debounce.rs
new file mode 100644
index 000000000..0077f19fc
--- /dev/null
+++ b/examples/rp/src/bin/debounce.rs
@@ -0,0 +1,80 @@
1//! This example shows the ease of debouncing a button with async rust.
2//! Hook up a button or switch between pin 9 and ground.
3
4#![no_std]
5#![no_main]
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::gpio::{Input, Level, Pull};
10use embassy_time::{with_deadline, Duration, Instant, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13pub struct Debouncer<'a> {
14 input: Input<'a>,
15 debounce: Duration,
16}
17
18impl<'a> Debouncer<'a> {
19 pub fn new(input: Input<'a>, debounce: Duration) -> Self {
20 Self { input, debounce }
21 }
22
23 pub async fn debounce(&mut self) -> Level {
24 loop {
25 let l1 = self.input.get_level();
26
27 self.input.wait_for_any_edge().await;
28
29 Timer::after(self.debounce).await;
30
31 let l2 = self.input.get_level();
32 if l1 != l2 {
33 break l2;
34 }
35 }
36 }
37}
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) {
41 let p = embassy_rp::init(Default::default());
42 let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20));
43
44 info!("Debounce Demo");
45
46 loop {
47 // button pressed
48 btn.debounce().await;
49 let start = Instant::now();
50 info!("Button Press");
51
52 match with_deadline(start + Duration::from_secs(1), btn.debounce()).await {
53 // Button Released < 1s
54 Ok(_) => {
55 info!("Button pressed for: {}ms", start.elapsed().as_millis());
56 continue;
57 }
58 // button held for > 1s
59 Err(_) => {
60 info!("Button Held");
61 }
62 }
63
64 match with_deadline(start + Duration::from_secs(5), btn.debounce()).await {
65 // Button released <5s
66 Ok(_) => {
67 info!("Button pressed for: {}ms", start.elapsed().as_millis());
68 continue;
69 }
70 // button held for > >5s
71 Err(_) => {
72 info!("Button Long Held");
73 }
74 }
75
76 // wait for button release before handling another press
77 btn.debounce().await;
78 info!("Button pressed for: {}ms", start.elapsed().as_millis());
79 }
80}
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index a16ea0007..bd52cadca 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -13,7 +13,7 @@ use embassy_net_wiznet::chip::W5500;
13use embassy_net_wiznet::*; 13use embassy_net_wiznet::*;
14use embassy_rp::clocks::RoscRng; 14use embassy_rp::clocks::RoscRng;
15use embassy_rp::gpio::{Input, Level, Output, Pull}; 15use embassy_rp::gpio::{Input, Level, Output, Pull};
16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 16use embassy_rp::peripherals::SPI0;
17use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 17use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::{Delay, Duration}; 18use embassy_time::{Delay, Duration};
19use embedded_hal_bus::spi::ExclusiveDevice; 19use embedded_hal_bus::spi::ExclusiveDevice;
@@ -27,9 +27,9 @@ async fn ethernet_task(
27 runner: Runner< 27 runner: Runner<
28 'static, 28 'static,
29 W5500, 29 W5500,
30 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 30 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>,
31 Input<'static, PIN_21>, 31 Input<'static>,
32 Output<'static, PIN_20>, 32 Output<'static>,
33 >, 33 >,
34) -> ! { 34) -> ! {
35 runner.run().await 35 runner.run().await
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index 975b3d385..3e4fbd2e6 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -15,7 +15,7 @@ use embassy_net_wiznet::chip::W5500;
15use embassy_net_wiznet::*; 15use embassy_net_wiznet::*;
16use embassy_rp::clocks::RoscRng; 16use embassy_rp::clocks::RoscRng;
17use embassy_rp::gpio::{Input, Level, Output, Pull}; 17use embassy_rp::gpio::{Input, Level, Output, Pull};
18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 18use embassy_rp::peripherals::SPI0;
19use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 19use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
20use embassy_time::{Delay, Duration, Timer}; 20use embassy_time::{Delay, Duration, Timer};
21use embedded_hal_bus::spi::ExclusiveDevice; 21use embedded_hal_bus::spi::ExclusiveDevice;
@@ -29,9 +29,9 @@ async fn ethernet_task(
29 runner: Runner< 29 runner: Runner<
30 'static, 30 'static,
31 W5500, 31 W5500,
32 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 32 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>,
33 Input<'static, PIN_21>, 33 Input<'static>,
34 Output<'static, PIN_20>, 34 Output<'static>,
35 >, 35 >,
36) -> ! { 36) -> ! {
37 runner.run().await 37 runner.run().await
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 489af2c76..5532851f3 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -14,7 +14,7 @@ use embassy_net_wiznet::chip::W5500;
14use embassy_net_wiznet::*; 14use embassy_net_wiznet::*;
15use embassy_rp::clocks::RoscRng; 15use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull}; 16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 17use embassy_rp::peripherals::SPI0;
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::{Delay, Duration}; 19use embassy_time::{Delay, Duration};
20use embedded_hal_bus::spi::ExclusiveDevice; 20use embedded_hal_bus::spi::ExclusiveDevice;
@@ -28,9 +28,9 @@ async fn ethernet_task(
28 runner: Runner< 28 runner: Runner<
29 'static, 29 'static,
30 W5500, 30 W5500,
31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>,
32 Input<'static, PIN_21>, 32 Input<'static>,
33 Output<'static, PIN_20>, 33 Output<'static>,
34 >, 34 >,
35) -> ! { 35) -> ! {
36 runner.run().await 36 runner.run().await
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index 41bd7d077..adb1d8941 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -14,7 +14,7 @@ use embassy_net_wiznet::chip::W5500;
14use embassy_net_wiznet::*; 14use embassy_net_wiznet::*;
15use embassy_rp::clocks::RoscRng; 15use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull}; 16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 17use embassy_rp::peripherals::SPI0;
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::Delay; 19use embassy_time::Delay;
20use embedded_hal_bus::spi::ExclusiveDevice; 20use embedded_hal_bus::spi::ExclusiveDevice;
@@ -27,9 +27,9 @@ async fn ethernet_task(
27 runner: Runner< 27 runner: Runner<
28 'static, 28 'static,
29 W5500, 29 W5500,
30 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 30 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>,
31 Input<'static, PIN_21>, 31 Input<'static>,
32 Output<'static, PIN_20>, 32 Output<'static>,
33 >, 33 >,
34) -> ! { 34) -> ! {
35 runner.run().await 35 runner.run().await
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs
index 479f9a16a..9fffb4646 100644
--- a/examples/rp/src/bin/i2c_slave.rs
+++ b/examples/rp/src/bin/i2c_slave.rs
@@ -26,7 +26,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
26 loop { 26 loop {
27 let mut buf = [0u8; 128]; 27 let mut buf = [0u8; 128];
28 match dev.listen(&mut buf).await { 28 match dev.listen(&mut buf).await {
29 Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device recieved general call write: {}", buf[..len]), 29 Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]),
30 Ok(i2c_slave::Command::Read) => loop { 30 Ok(i2c_slave::Command::Read) => loop {
31 match dev.respond_to_read(&[state]).await { 31 match dev.respond_to_read(&[state]).await {
32 Ok(x) => match x { 32 Ok(x) => match x {
@@ -40,9 +40,9 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
40 Err(e) => error!("error while responding {}", e), 40 Err(e) => error!("error while responding {}", e),
41 } 41 }
42 }, 42 },
43 Ok(i2c_slave::Command::Write(len)) => info!("Device recieved write: {}", buf[..len]), 43 Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]),
44 Ok(i2c_slave::Command::WriteRead(len)) => { 44 Ok(i2c_slave::Command::WriteRead(len)) => {
45 info!("device recieved write read: {:x}", buf[..len]); 45 info!("device received write read: {:x}", buf[..len]);
46 match buf[0] { 46 match buf[0] {
47 // Set the state 47 // Set the state
48 0xC2 => { 48 0xC2 => {
@@ -110,7 +110,7 @@ async fn main(spawner: Spawner) {
110 let c_sda = p.PIN_1; 110 let c_sda = p.PIN_1;
111 let c_scl = p.PIN_0; 111 let c_scl = p.PIN_0;
112 let mut config = i2c::Config::default(); 112 let mut config = i2c::Config::default();
113 config.frequency = 5_000; 113 config.frequency = 1_000_000;
114 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); 114 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
115 115
116 unwrap!(spawner.spawn(controller_task(controller))); 116 unwrap!(spawner.spawn(controller_task(controller)));
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
index a1678d99a..c7b087476 100644
--- a/examples/rp/src/bin/multicore.rs
+++ b/examples/rp/src/bin/multicore.rs
@@ -9,7 +9,6 @@ use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_rp::gpio::{Level, Output}; 10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::multicore::{spawn_core1, Stack}; 11use embassy_rp::multicore::{spawn_core1, Stack};
12use embassy_rp::peripherals::PIN_25;
13use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 12use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
14use embassy_sync::channel::Channel; 13use embassy_sync::channel::Channel;
15use embassy_time::Timer; 14use embassy_time::Timer;
@@ -52,7 +51,7 @@ async fn core0_task() {
52} 51}
53 52
54#[embassy_executor::task] 53#[embassy_executor::task]
55async fn core1_task(mut led: Output<'static, PIN_25>) { 54async fn core1_task(mut led: Output<'static>) {
56 info!("Hello from core 1"); 55 info!("Hello from core 1");
57 loop { 56 loop {
58 match CHANNEL.receive().await { 57 match CHANNEL.receive().await {
diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs
new file mode 100644
index 000000000..cf60e5b30
--- /dev/null
+++ b/examples/rp/src/bin/pio_i2s.rs
@@ -0,0 +1,125 @@
1//! This example shows generating audio and sending it to a connected i2s DAC using the PIO
2//! module of the RP2040.
3//!
4//! Connect the i2s DAC as follows:
5//! bclk : GPIO 18
6//! lrc : GPIO 19
7//! din : GPIO 20
8//! Then hold down the boot select button to trigger a rising triangle waveform.
9
10#![no_std]
11#![no_main]
12
13use core::mem;
14
15use embassy_executor::Spawner;
16use embassy_rp::peripherals::PIO0;
17use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
18use embassy_rp::{bind_interrupts, Peripheral};
19use fixed::traits::ToFixed;
20use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 PIO0_IRQ_0 => InterruptHandler<PIO0>;
25});
26
27const SAMPLE_RATE: u32 = 48_000;
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let mut p = embassy_rp::init(Default::default());
32
33 // Setup pio state machine for i2s output
34 let mut pio = Pio::new(p.PIO0, Irqs);
35
36 #[rustfmt::skip]
37 let pio_program = pio_proc::pio_asm!(
38 ".side_set 2",
39 " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock
40 "left_data:",
41 " out pins, 1 side 0b00",
42 " jmp x-- left_data side 0b01",
43 " out pins 1 side 0b10",
44 " set x, 14 side 0b11",
45 "right_data:",
46 " out pins 1 side 0b10",
47 " jmp x-- right_data side 0b11",
48 " out pins 1 side 0b00",
49 );
50
51 let bit_clock_pin = p.PIN_18;
52 let left_right_clock_pin = p.PIN_19;
53 let data_pin = p.PIN_20;
54
55 let data_pin = pio.common.make_pio_pin(data_pin);
56 let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin);
57 let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin);
58
59 let cfg = {
60 let mut cfg = Config::default();
61 cfg.use_program(
62 &pio.common.load_program(&pio_program.program),
63 &[&bit_clock_pin, &left_right_clock_pin],
64 );
65 cfg.set_out_pins(&[&data_pin]);
66 const BIT_DEPTH: u32 = 16;
67 const CHANNELS: u32 = 2;
68 let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS;
69 cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed();
70 cfg.shift_out = ShiftConfig {
71 threshold: 32,
72 direction: ShiftDirection::Left,
73 auto_fill: true,
74 };
75 // join fifos to have twice the time to start the next dma transfer
76 cfg.fifo_join = FifoJoin::TxOnly;
77 cfg
78 };
79 pio.sm0.set_config(&cfg);
80 pio.sm0.set_pin_dirs(
81 embassy_rp::pio::Direction::Out,
82 &[&data_pin, &left_right_clock_pin, &bit_clock_pin],
83 );
84
85 // create two audio buffers (back and front) which will take turns being
86 // filled with new audio data and being sent to the pio fifo using dma
87 const BUFFER_SIZE: usize = 960;
88 static DMA_BUFFER: StaticCell<[u32; BUFFER_SIZE * 2]> = StaticCell::new();
89 let dma_buffer = DMA_BUFFER.init_with(|| [0u32; BUFFER_SIZE * 2]);
90 let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE);
91
92 // start pio state machine
93 pio.sm0.set_enable(true);
94 let tx = pio.sm0.tx();
95 let mut dma_ref = p.DMA_CH0.into_ref();
96
97 let mut fade_value: i32 = 0;
98 let mut phase: i32 = 0;
99
100 loop {
101 // trigger transfer of front buffer data to the pio fifo
102 // but don't await the returned future, yet
103 let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer);
104
105 // fade in audio when bootsel is pressed
106 let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 };
107
108 // fill back buffer with fresh audio samples before awaiting the dma future
109 for s in back_buffer.iter_mut() {
110 // exponential approach of fade_value => fade_target
111 fade_value += (fade_target - fade_value) >> 14;
112 // generate triangle wave with amplitude and frequency based on fade value
113 phase = (phase + (fade_value >> 22)) & 0xffff;
114 let triangle_sample = (phase as i16 as i32).abs() - 16384;
115 let sample = (triangle_sample * (fade_value >> 15)) >> 16;
116 // duplicate mono sample into lower and upper half of dma word
117 *s = (sample as u16 as u32) * 0x10001;
118 }
119
120 // now await the dma future. once the dma finishes, the next buffer needs to be queued
121 // within DMA_DEPTH / SAMPLE_RATE = 8 / 48000 seconds = 166us
122 dma_future.await;
123 mem::swap(&mut back_buffer, &mut front_buffer);
124 }
125}
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
index 9a97cb8a7..ac145933c 100644
--- a/examples/rp/src/bin/pio_ws2812.rs
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -12,7 +12,7 @@ use embassy_rp::pio::{
12 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, 12 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
13}; 13};
14use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; 14use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
15use embassy_time::Timer; 15use embassy_time::{Duration, Ticker, Timer};
16use fixed::types::U24F8; 16use fixed::types::U24F8;
17use fixed_macro::fixed; 17use fixed_macro::fixed;
18use smart_leds::RGB8; 18use smart_leds::RGB8;
@@ -107,6 +107,8 @@ impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
107 107
108 // DMA transfer 108 // DMA transfer
109 self.sm.tx().dma_push(self.dma.reborrow(), &words).await; 109 self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
110
111 Timer::after_micros(55).await;
110 } 112 }
111} 113}
112 114
@@ -143,6 +145,7 @@ async fn main(_spawner: Spawner) {
143 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); 145 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
144 146
145 // Loop forever making RGB values and pushing them out to the WS2812. 147 // Loop forever making RGB values and pushing them out to the WS2812.
148 let mut ticker = Ticker::every(Duration::from_millis(10));
146 loop { 149 loop {
147 for j in 0..(256 * 5) { 150 for j in 0..(256 * 5) {
148 debug!("New Colors:"); 151 debug!("New Colors:");
@@ -152,7 +155,7 @@ async fn main(_spawner: Spawner) {
152 } 155 }
153 ws2812.write(&data).await; 156 ws2812.write(&data).await;
154 157
155 Timer::after_millis(10).await; 158 ticker.next().await;
156 } 159 }
157 } 160 }
158} 161}
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs
new file mode 100644
index 000000000..afebd8813
--- /dev/null
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,182 @@
1#![no_std]
2#![no_main]
3
4use core::sync::atomic::{AtomicBool, Ordering};
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_futures::join::join;
9use embassy_rp::bind_interrupts;
10use embassy_rp::clocks::RoscRng;
11use embassy_rp::gpio::{Input, Pull};
12use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_time::Timer;
15use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
16use embassy_usb::control::OutResponse;
17use embassy_usb::{Builder, Config, Handler};
18use rand::Rng;
19use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs {
23 USBCTRL_IRQ => InterruptHandler<USB>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_rp::init(Default::default());
29 // Create the driver, from the HAL.
30 let driver = Driver::new(p.USB, Irqs);
31
32 // Create embassy-usb Config
33 let mut config = Config::new(0xc0de, 0xcafe);
34 config.manufacturer = Some("Embassy");
35 config.product = Some("HID keyboard example");
36 config.serial_number = Some("12345678");
37 config.max_power = 100;
38 config.max_packet_size_0 = 64;
39
40 // Create embassy-usb DeviceBuilder using the driver and config.
41 // It needs some buffers for building the descriptors.
42 let mut device_descriptor = [0; 256];
43 let mut config_descriptor = [0; 256];
44 let mut bos_descriptor = [0; 256];
45 // You can also add a Microsoft OS descriptor.
46 let mut msos_descriptor = [0; 256];
47 let mut control_buf = [0; 64];
48 let request_handler = MyRequestHandler {};
49 let mut device_handler = MyDeviceHandler::new();
50
51 let mut state = State::new();
52
53 let mut builder = Builder::new(
54 driver,
55 config,
56 &mut device_descriptor,
57 &mut config_descriptor,
58 &mut bos_descriptor,
59 &mut msos_descriptor,
60 &mut control_buf,
61 );
62
63 builder.handler(&mut device_handler);
64
65 // Create classes on the builder.
66 let config = embassy_usb::class::hid::Config {
67 report_descriptor: MouseReport::desc(),
68 request_handler: Some(&request_handler),
69 poll_ms: 60,
70 max_packet_size: 64,
71 };
72 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
73
74 // Build the builder.
75 let mut usb = builder.build();
76
77 // Run the USB device.
78 let usb_fut = usb.run();
79
80 // Set up the signal pin that will be used to trigger the keyboard.
81 let mut signal_pin = Input::new(p.PIN_16, Pull::None);
82
83 // Enable the schmitt trigger to slightly debounce.
84 signal_pin.set_schmitt(true);
85
86 let (reader, mut writer) = hid.split();
87
88 // Do stuff with the class!
89 let in_fut = async {
90 let mut rng = RoscRng;
91
92 loop {
93 // every 1 second
94 _ = Timer::after_secs(1).await;
95 let report = MouseReport {
96 buttons: 0,
97 x: rng.gen_range(-100..100), // random small x movement
98 y: rng.gen_range(-100..100), // random small y movement
99 wheel: 0,
100 pan: 0,
101 };
102 // Send the report.
103 match writer.write_serialize(&report).await {
104 Ok(()) => {}
105 Err(e) => warn!("Failed to send report: {:?}", e),
106 }
107 }
108 };
109
110 let out_fut = async {
111 reader.run(false, &request_handler).await;
112 };
113
114 // Run everything concurrently.
115 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
116 join(usb_fut, join(in_fut, out_fut)).await;
117}
118
119struct MyRequestHandler {}
120
121impl RequestHandler for MyRequestHandler {
122 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
123 info!("Get report for {:?}", id);
124 None
125 }
126
127 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
128 info!("Set report for {:?}: {=[u8]}", id, data);
129 OutResponse::Accepted
130 }
131
132 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
133 info!("Set idle rate for {:?} to {:?}", id, dur);
134 }
135
136 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
137 info!("Get idle rate for {:?}", id);
138 None
139 }
140}
141
142struct MyDeviceHandler {
143 configured: AtomicBool,
144}
145
146impl MyDeviceHandler {
147 fn new() -> Self {
148 MyDeviceHandler {
149 configured: AtomicBool::new(false),
150 }
151 }
152}
153
154impl Handler for MyDeviceHandler {
155 fn enabled(&mut self, enabled: bool) {
156 self.configured.store(false, Ordering::Relaxed);
157 if enabled {
158 info!("Device enabled");
159 } else {
160 info!("Device disabled");
161 }
162 }
163
164 fn reset(&mut self) {
165 self.configured.store(false, Ordering::Relaxed);
166 info!("Bus reset, the Vbus current limit is 100mA");
167 }
168
169 fn addressed(&mut self, addr: u8) {
170 self.configured.store(false, Ordering::Relaxed);
171 info!("USB address set to: {}", addr);
172 }
173
174 fn configured(&mut self, configured: bool) {
175 self.configured.store(configured, Ordering::Relaxed);
176 if configured {
177 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
178 } else {
179 info!("Device is no longer configured, the Vbus current limit is 100mA.");
180 }
181 }
182}
diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs
new file mode 100644
index 000000000..4ba4fc25c
--- /dev/null
+++ b/examples/rp/src/bin/usb_serial_with_logger.rs
@@ -0,0 +1,117 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip as well as how to create multiple usb classes for one device
2//!
3//! This creates a USB serial port that echos. It will also print out logging information on a separate serial device
4
5#![no_std]
6#![no_main]
7
8use defmt::{info, panic};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_rp::bind_interrupts;
12use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, Instance, InterruptHandler};
14use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
15use embassy_usb::driver::EndpointError;
16use embassy_usb::{Builder, Config};
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>;
21});
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 info!("Hello there!");
26
27 let p = embassy_rp::init(Default::default());
28
29 // Create the driver, from the HAL.
30 let driver = Driver::new(p.USB, Irqs);
31
32 // Create embassy-usb Config
33 let mut config = Config::new(0xc0de, 0xcafe);
34 config.manufacturer = Some("Embassy");
35 config.product = Some("USB-serial example");
36 config.serial_number = Some("12345678");
37 config.max_power = 100;
38 config.max_packet_size_0 = 64;
39
40 // Required for windows compatibility.
41 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
42 config.device_class = 0xEF;
43 config.device_sub_class = 0x02;
44 config.device_protocol = 0x01;
45 config.composite_with_iads = true;
46
47 // Create embassy-usb DeviceBuilder using the driver and config.
48 // It needs some buffers for building the descriptors.
49 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256];
52 let mut control_buf = [0; 64];
53
54 let mut state = State::new();
55 let mut logger_state = State::new();
56
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut device_descriptor,
61 &mut config_descriptor,
62 &mut bos_descriptor,
63 &mut [], // no msos descriptors
64 &mut control_buf,
65 );
66
67 // Create classes on the builder.
68 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
69
70 // Create a class for the logger
71 let logger_class = CdcAcmClass::new(&mut builder, &mut logger_state, 64);
72
73 // Creates the logger and returns the logger future
74 // Note: You'll need to use log::info! afterwards instead of info! for this to work (this also applies to all the other log::* macros)
75 let log_fut = embassy_usb_logger::with_class!(1024, log::LevelFilter::Info, logger_class);
76
77 // Build the builder.
78 let mut usb = builder.build();
79
80 // Run the USB device.
81 let usb_fut = usb.run();
82
83 // Do stuff with the class!
84 let echo_fut = async {
85 loop {
86 class.wait_connection().await;
87 log::info!("Connected");
88 let _ = echo(&mut class).await;
89 log::info!("Disconnected");
90 }
91 };
92
93 // Run everything concurrently.
94 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
95 join(usb_fut, join(echo_fut, log_fut)).await;
96}
97
98struct Disconnected {}
99
100impl From<EndpointError> for Disconnected {
101 fn from(val: EndpointError) -> Self {
102 match val {
103 EndpointError::BufferOverflow => panic!("Buffer overflow"),
104 EndpointError::Disabled => Disconnected {},
105 }
106 }
107}
108
109async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
110 let mut buf = [0; 64];
111 loop {
112 let n = class.read_packet(&mut buf).await?;
113 let data = &buf[..n];
114 info!("data: {:x}", data);
115 class.write_packet(data).await?;
116 }
117}
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index 1bd75607e..b60852359 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -14,7 +14,7 @@ use embassy_net::tcp::TcpSocket;
14use embassy_net::{Config, Stack, StackResources}; 14use embassy_net::{Config, Stack, StackResources};
15use embassy_rp::bind_interrupts; 15use embassy_rp::bind_interrupts;
16use embassy_rp::gpio::{Level, Output}; 16use embassy_rp::gpio::{Level, Output};
17use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 17use embassy_rp::peripherals::{DMA_CH0, PIO0};
18use embassy_rp::pio::{InterruptHandler, Pio}; 18use embassy_rp::pio::{InterruptHandler, Pio};
19use embassy_time::Duration; 19use embassy_time::Duration;
20use embedded_io_async::Write; 20use embedded_io_async::Write;
@@ -26,9 +26,7 @@ bind_interrupts!(struct Irqs {
26}); 26});
27 27
28#[embassy_executor::task] 28#[embassy_executor::task]
29async fn wifi_task( 29async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
30 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
31) -> ! {
32 runner.run().await 30 runner.run().await
33} 31}
34 32
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
index 1ed74993c..18eefe41f 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -10,7 +10,7 @@ use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_rp::bind_interrupts; 11use embassy_rp::bind_interrupts;
12use embassy_rp::gpio::{Level, Output}; 12use embassy_rp::gpio::{Level, Output};
13use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 13use embassy_rp::peripherals::{DMA_CH0, PIO0};
14use embassy_rp::pio::{InterruptHandler, Pio}; 14use embassy_rp::pio::{InterruptHandler, Pio};
15use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use static_cell::StaticCell; 16use static_cell::StaticCell;
@@ -21,9 +21,7 @@ bind_interrupts!(struct Irqs {
21}); 21});
22 22
23#[embassy_executor::task] 23#[embassy_executor::task]
24async fn wifi_task( 24async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
25 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
26) -> ! {
27 runner.run().await 25 runner.run().await
28} 26}
29 27
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index 45bb5b76c..e0f85a6b0 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -13,7 +13,7 @@ use embassy_executor::Spawner;
13use embassy_net::Stack; 13use embassy_net::Stack;
14use embassy_rp::bind_interrupts; 14use embassy_rp::bind_interrupts;
15use embassy_rp::gpio::{Level, Output}; 15use embassy_rp::gpio::{Level, Output};
16use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 16use embassy_rp::peripherals::{DMA_CH0, PIO0};
17use embassy_rp::pio::{InterruptHandler, Pio}; 17use embassy_rp::pio::{InterruptHandler, Pio};
18use static_cell::StaticCell; 18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
@@ -23,9 +23,7 @@ bind_interrupts!(struct Irqs {
23}); 23});
24 24
25#[embassy_executor::task] 25#[embassy_executor::task]
26async fn wifi_task( 26async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
27 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
28) -> ! {
29 runner.run().await 27 runner.run().await
30} 28}
31 29
@@ -65,7 +63,7 @@ async fn main(spawner: Spawner) {
65 .set_power_management(cyw43::PowerManagementMode::PowerSave) 63 .set_power_management(cyw43::PowerManagementMode::PowerSave)
66 .await; 64 .await;
67 65
68 let mut scanner = control.scan().await; 66 let mut scanner = control.scan(Default::default()).await;
69 while let Some(bss) = scanner.next().await { 67 while let Some(bss) = scanner.next().await {
70 if let Ok(ssid_str) = str::from_utf8(&bss.ssid) { 68 if let Ok(ssid_str) = str::from_utf8(&bss.ssid) {
71 info!("scanned {} == {:x}", ssid_str, bss.bssid); 69 info!("scanned {} == {:x}", ssid_str, bss.bssid);
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index c346f1ded..f1afc4a00 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -14,7 +14,7 @@ use embassy_net::tcp::TcpSocket;
14use embassy_net::{Config, Stack, StackResources}; 14use embassy_net::{Config, Stack, StackResources};
15use embassy_rp::bind_interrupts; 15use embassy_rp::bind_interrupts;
16use embassy_rp::gpio::{Level, Output}; 16use embassy_rp::gpio::{Level, Output};
17use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 17use embassy_rp::peripherals::{DMA_CH0, PIO0};
18use embassy_rp::pio::{InterruptHandler, Pio}; 18use embassy_rp::pio::{InterruptHandler, Pio};
19use embassy_time::{Duration, Timer}; 19use embassy_time::{Duration, Timer};
20use embedded_io_async::Write; 20use embedded_io_async::Write;
@@ -29,9 +29,7 @@ const WIFI_NETWORK: &str = "EmbassyTest";
29const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; 29const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
30 30
31#[embassy_executor::task] 31#[embassy_executor::task]
32async fn wifi_task( 32async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
33 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
34) -> ! {
35 runner.run().await 33 runner.run().await
36} 34}
37 35
diff --git a/examples/std/README.md b/examples/std/README.md
index adc795928..e3a59d6ea 100644
--- a/examples/std/README.md
+++ b/examples/std/README.md
@@ -13,11 +13,11 @@ sudo ip -6 route add fe80::/64 dev tap0
13sudo ip -6 route add fdaa::/64 dev tap0 13sudo ip -6 route add fdaa::/64 dev tap0
14``` 14```
15 15
16Second, have something listening there. For example `nc -l 8000` 16Second, have something listening there. For example `nc -lp 8000`
17 17
18Then run the example located in the `examples` folder: 18Then run the example located in the `examples` folder:
19 19
20```sh 20```sh
21cd $EMBASSY_ROOT/examples/std/ 21cd $EMBASSY_ROOT/examples/std/
22cargo run --bin net -- --static-ip 22cargo run --bin net -- --static-ip
23``` \ No newline at end of file 23```
diff --git a/examples/stm32c0/src/bin/button_exti.rs b/examples/stm32c0/src/bin/button_exti.rs
index 1e970fdd6..34a08bbc6 100644
--- a/examples/stm32c0/src/bin/button_exti.rs
+++ b/examples/stm32c0/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Up); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 71b0eb683..c74980dc4 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -13,7 +13,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
13cortex-m-rt = "0.7.0" 13cortex-m-rt = "0.7.0"
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
16panic-probe = "0.3" 16panic-probe = { version = "0.3", features = ["print-defmt"] }
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.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 18embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
19embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 19embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
index 8fef062b3..c2fb143cd 100644
--- a/examples/stm32f0/src/bin/adc.rs
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -19,7 +19,7 @@ async fn main(_spawner: Spawner) {
19 info!("Hello World!"); 19 info!("Hello World!");
20 20
21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); 21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
22 adc.set_sample_time(SampleTime::Cycles71_5); 22 adc.set_sample_time(SampleTime::CYCLES71_5);
23 let mut pin = p.PA1; 23 let mut pin = p.PA1;
24 24
25 let mut vrefint = adc.enable_vref(&mut Delay); 25 let mut vrefint = adc.enable_vref(&mut Delay);
diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs
index 360d153c3..4465483d9 100644
--- a/examples/stm32f0/src/bin/button_controlled_blink.rs
+++ b/examples/stm32f0/src/bin/button_controlled_blink.rs
@@ -8,7 +8,7 @@ use core::sync::atomic::{AtomicU32, Ordering};
8use defmt::info; 8use defmt::info;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed}; 11use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Pull, Speed};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -36,8 +36,7 @@ async fn main(spawner: Spawner) {
36 36
37 // Configure the button pin and obtain handler. 37 // Configure the button pin and obtain handler.
38 // On the Nucleo F091RC there is a button connected to pin PC13. 38 // On the Nucleo F091RC there is a button connected to pin PC13.
39 let button = Input::new(p.PC13, Pull::None); 39 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::None);
40 let mut button = ExtiInput::new(button, p.EXTI13);
41 40
42 // Create and initialize a delay variable to manage delay loop 41 // Create and initialize a delay variable to manage delay loop
43 let mut del_var = 2000; 42 let mut del_var = 2000;
diff --git a/examples/stm32f0/src/bin/button_exti.rs b/examples/stm32f0/src/bin/button_exti.rs
index ce17c1a48..fd615a215 100644
--- a/examples/stm32f0/src/bin/button_exti.rs
+++ b/examples/stm32f0/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -13,8 +13,7 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
14 // Configure the button pin and obtain handler. 14 // Configure the button pin and obtain handler.
15 // On the Nucleo F091RC there is a button connected to pin PC13. 15 // On the Nucleo F091RC there is a button connected to pin PC13.
16 let button = Input::new(p.PC13, Pull::Down); 16 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
17 let mut button = ExtiInput::new(button, p.EXTI13);
18 17
19 info!("Press the USER button..."); 18 info!("Press the USER button...");
20 loop { 19 loop {
diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs
index 7b761ecc1..3c295612c 100644
--- a/examples/stm32f1/src/bin/hello.rs
+++ b/examples/stm32f1/src/bin/hello.rs
@@ -3,15 +3,13 @@
3 3
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz;
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! { 11async fn main(_spawner: Spawner) -> ! {
13 let mut config = Config::default(); 12 let config = Config::default();
14 config.rcc.sys_ck = Some(Hertz(36_000_000));
15 let _p = embassy_stm32::init(config); 13 let _p = embassy_stm32::init(config);
16 14
17 loop { 15 loop {
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index e28381893..1ae6c1dee 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -21,9 +21,23 @@ bind_interrupts!(struct Irqs {
21#[embassy_executor::main] 21#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 23 let mut config = Config::default();
24 config.rcc.hse = Some(Hertz(8_000_000)); 24 {
25 config.rcc.sys_ck = Some(Hertz(48_000_000)); 25 use embassy_stm32::rcc::*;
26 config.rcc.pclk1 = Some(Hertz(24_000_000)); 26 config.rcc.hse = Some(Hse {
27 freq: Hertz(8_000_000),
28 // Oscillator for bluepill, Bypass for nucleos.
29 mode: HseMode::Oscillator,
30 });
31 config.rcc.pll = Some(Pll {
32 src: PllSource::HSE,
33 prediv: PllPreDiv::DIV1,
34 mul: PllMul::MUL9,
35 });
36 config.rcc.sys = Sysclk::PLL1_P;
37 config.rcc.ahb_pre = AHBPrescaler::DIV1;
38 config.rcc.apb1_pre = APBPrescaler::DIV2;
39 config.rcc.apb2_pre = APBPrescaler::DIV1;
40 }
27 let mut p = embassy_stm32::init(config); 41 let mut p = embassy_stm32::init(config);
28 42
29 info!("Hello World!"); 43 info!("Hello World!");
diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs
index 2f7da4ef5..f5ed5d2c9 100644
--- a/examples/stm32f3/src/bin/button_events.rs
+++ b/examples/stm32f3/src/bin/button_events.rs
@@ -12,21 +12,20 @@
12use defmt::*; 12use defmt::*;
13use embassy_executor::Spawner; 13use embassy_executor::Spawner;
14use embassy_stm32::exti::ExtiInput; 14use embassy_stm32::exti::ExtiInput;
15use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed}; 15use embassy_stm32::gpio::{Level, Output, Pull, Speed};
16use embassy_stm32::peripherals::PA0;
17use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
18use embassy_sync::channel::Channel; 17use embassy_sync::channel::Channel;
19use embassy_time::{with_timeout, Duration, Timer}; 18use embassy_time::{with_timeout, Duration, Timer};
20use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
21 20
22struct Leds<'a> { 21struct Leds<'a> {
23 leds: [Output<'a, AnyPin>; 8], 22 leds: [Output<'a>; 8],
24 direction: i8, 23 direction: i8,
25 current_led: usize, 24 current_led: usize,
26} 25}
27 26
28impl<'a> Leds<'a> { 27impl<'a> Leds<'a> {
29 fn new(pins: [Output<'a, AnyPin>; 8]) -> Self { 28 fn new(pins: [Output<'a>; 8]) -> Self {
30 Self { 29 Self {
31 leds: pins, 30 leds: pins,
32 direction: 1, 31 direction: 1,
@@ -100,18 +99,17 @@ static CHANNEL: Channel<ThreadModeRawMutex, ButtonEvent, 4> = Channel::new();
100#[embassy_executor::main] 99#[embassy_executor::main]
101async fn main(spawner: Spawner) { 100async fn main(spawner: Spawner) {
102 let p = embassy_stm32::init(Default::default()); 101 let p = embassy_stm32::init(Default::default());
103 let button = Input::new(p.PA0, Pull::Down); 102 let button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Down);
104 let button = ExtiInput::new(button, p.EXTI0);
105 info!("Press the USER button..."); 103 info!("Press the USER button...");
106 let leds = [ 104 let leds = [
107 Output::new(p.PE9.degrade(), Level::Low, Speed::Low), 105 Output::new(p.PE9, Level::Low, Speed::Low),
108 Output::new(p.PE10.degrade(), Level::Low, Speed::Low), 106 Output::new(p.PE10, Level::Low, Speed::Low),
109 Output::new(p.PE11.degrade(), Level::Low, Speed::Low), 107 Output::new(p.PE11, Level::Low, Speed::Low),
110 Output::new(p.PE12.degrade(), Level::Low, Speed::Low), 108 Output::new(p.PE12, Level::Low, Speed::Low),
111 Output::new(p.PE13.degrade(), Level::Low, Speed::Low), 109 Output::new(p.PE13, Level::Low, Speed::Low),
112 Output::new(p.PE14.degrade(), Level::Low, Speed::Low), 110 Output::new(p.PE14, Level::Low, Speed::Low),
113 Output::new(p.PE15.degrade(), Level::Low, Speed::Low), 111 Output::new(p.PE15, Level::Low, Speed::Low),
114 Output::new(p.PE8.degrade(), Level::Low, Speed::Low), 112 Output::new(p.PE8, Level::Low, Speed::Low),
115 ]; 113 ];
116 let leds = Leds::new(leds); 114 let leds = Leds::new(leds);
117 115
@@ -127,7 +125,7 @@ async fn led_blinker(mut leds: Leds<'static>) {
127} 125}
128 126
129#[embassy_executor::task] 127#[embassy_executor::task]
130async fn button_waiter(mut button: ExtiInput<'static, PA0>) { 128async fn button_waiter(mut button: ExtiInput<'static>) {
131 const DOUBLE_CLICK_DELAY: u64 = 250; 129 const DOUBLE_CLICK_DELAY: u64 = 250;
132 const HOLD_DELAY: u64 = 1000; 130 const HOLD_DELAY: u64 = 1000;
133 131
diff --git a/examples/stm32f3/src/bin/button_exti.rs b/examples/stm32f3/src/bin/button_exti.rs
index 86ff68492..a55530e0e 100644
--- a/examples/stm32f3/src/bin/button_exti.rs
+++ b/examples/stm32f3/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PA0, Pull::Down); 15 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Down);
16 let mut button = ExtiInput::new(button, p.EXTI0);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32f3/src/bin/hello.rs b/examples/stm32f3/src/bin/hello.rs
index fd54da53d..3c295612c 100644
--- a/examples/stm32f3/src/bin/hello.rs
+++ b/examples/stm32f3/src/bin/hello.rs
@@ -3,16 +3,13 @@
3 3
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz;
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! { 11async fn main(_spawner: Spawner) -> ! {
13 let mut config = Config::default(); 12 let config = Config::default();
14 config.rcc.hse = Some(Hertz(8_000_000));
15 config.rcc.sysclk = Some(Hertz(16_000_000));
16 let _p = embassy_stm32::init(config); 13 let _p = embassy_stm32::init(config);
17 14
18 loop { 15 loop {
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index cf9ecedfa..ee1c43afd 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -21,11 +21,22 @@ bind_interrupts!(struct Irqs {
21#[embassy_executor::main] 21#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 23 let mut config = Config::default();
24 config.rcc.hse = Some(mhz(8)); 24 {
25 config.rcc.sysclk = Some(mhz(48)); 25 use embassy_stm32::rcc::*;
26 config.rcc.pclk1 = Some(mhz(24)); 26 config.rcc.hse = Some(Hse {
27 config.rcc.pclk2 = Some(mhz(24)); 27 freq: mhz(8),
28 config.rcc.pll48 = true; 28 mode: HseMode::Bypass,
29 });
30 config.rcc.pll = Some(Pll {
31 src: PllSource::HSE,
32 prediv: PllPreDiv::DIV1,
33 mul: PllMul::MUL9,
34 });
35 config.rcc.sys = Sysclk::PLL1_P;
36 config.rcc.ahb_pre = AHBPrescaler::DIV1;
37 config.rcc.apb1_pre = APBPrescaler::DIV2;
38 config.rcc.apb2_pre = APBPrescaler::DIV1;
39 }
29 let p = embassy_stm32::init(config); 40 let p = embassy_stm32::init(config);
30 41
31 info!("Hello World!"); 42 info!("Hello World!");
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs
index 063ee9dac..bd126ce68 100644
--- a/examples/stm32f334/src/bin/adc.rs
+++ b/examples/stm32f334/src/bin/adc.rs
@@ -5,7 +5,6 @@ use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC1; 7use embassy_stm32::peripherals::ADC1;
8use embassy_stm32::rcc::{AdcClockSource, Adcpres};
9use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
10use embassy_stm32::{adc, bind_interrupts, Config}; 9use embassy_stm32::{adc, bind_interrupts, Config};
11use embassy_time::{Delay, Timer}; 10use embassy_time::{Delay, Timer};
@@ -18,19 +17,30 @@ bind_interrupts!(struct Irqs {
18#[embassy_executor::main] 17#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! { 18async fn main(_spawner: Spawner) -> ! {
20 let mut config = Config::default(); 19 let mut config = Config::default();
21 config.rcc.sysclk = Some(mhz(64)); 20 {
22 config.rcc.hclk = Some(mhz(64)); 21 use embassy_stm32::rcc::*;
23 config.rcc.pclk1 = Some(mhz(32)); 22 config.rcc.hse = Some(Hse {
24 config.rcc.pclk2 = Some(mhz(64)); 23 freq: mhz(8),
25 config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); 24 mode: HseMode::Bypass,
26 25 });
26 config.rcc.pll = Some(Pll {
27 src: PllSource::HSE,
28 prediv: PllPreDiv::DIV1,
29 mul: PllMul::MUL9,
30 });
31 config.rcc.sys = Sysclk::PLL1_P;
32 config.rcc.ahb_pre = AHBPrescaler::DIV1;
33 config.rcc.apb1_pre = APBPrescaler::DIV2;
34 config.rcc.apb2_pre = APBPrescaler::DIV1;
35 config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1);
36 }
27 let mut p = embassy_stm32::init(config); 37 let mut p = embassy_stm32::init(config);
28 38
29 info!("create adc..."); 39 info!("create adc...");
30 40
31 let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); 41 let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay);
32 42
33 adc.set_sample_time(SampleTime::Cycles601_5); 43 adc.set_sample_time(SampleTime::CYCLES601_5);
34 44
35 info!("enable vrefint..."); 45 info!("enable vrefint...");
36 46
diff --git a/examples/stm32f334/src/bin/hello.rs b/examples/stm32f334/src/bin/hello.rs
index fd54da53d..3c295612c 100644
--- a/examples/stm32f334/src/bin/hello.rs
+++ b/examples/stm32f334/src/bin/hello.rs
@@ -3,16 +3,13 @@
3 3
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz;
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! { 11async fn main(_spawner: Spawner) -> ! {
13 let mut config = Config::default(); 12 let config = Config::default();
14 config.rcc.hse = Some(Hertz(8_000_000));
15 config.rcc.sysclk = Some(Hertz(16_000_000));
16 let _p = embassy_stm32::init(config); 13 let _p = embassy_stm32::init(config);
17 14
18 loop { 15 loop {
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs
index 850a0e335..a5c710aa2 100644
--- a/examples/stm32f334/src/bin/opamp.rs
+++ b/examples/stm32f334/src/bin/opamp.rs
@@ -6,7 +6,6 @@ use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::opamp::{OpAmp, OpAmpGain}; 7use embassy_stm32::opamp::{OpAmp, OpAmpGain};
8use embassy_stm32::peripherals::ADC2; 8use embassy_stm32::peripherals::ADC2;
9use embassy_stm32::rcc::{AdcClockSource, Adcpres};
10use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
11use embassy_stm32::{adc, bind_interrupts, Config}; 10use embassy_stm32::{adc, bind_interrupts, Config};
12use embassy_time::{Delay, Timer}; 11use embassy_time::{Delay, Timer};
@@ -19,12 +18,23 @@ bind_interrupts!(struct Irqs {
19#[embassy_executor::main] 18#[embassy_executor::main]
20async fn main(_spawner: Spawner) -> ! { 19async fn main(_spawner: Spawner) -> ! {
21 let mut config = Config::default(); 20 let mut config = Config::default();
22 config.rcc.sysclk = Some(mhz(64)); 21 {
23 config.rcc.hclk = Some(mhz(64)); 22 use embassy_stm32::rcc::*;
24 config.rcc.pclk1 = Some(mhz(32)); 23 config.rcc.hse = Some(Hse {
25 config.rcc.pclk2 = Some(mhz(64)); 24 freq: mhz(8),
26 config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); 25 mode: HseMode::Bypass,
27 26 });
27 config.rcc.pll = Some(Pll {
28 src: PllSource::HSE,
29 prediv: PllPreDiv::DIV1,
30 mul: PllMul::MUL9,
31 });
32 config.rcc.sys = Sysclk::PLL1_P;
33 config.rcc.ahb_pre = AHBPrescaler::DIV1;
34 config.rcc.apb1_pre = APBPrescaler::DIV2;
35 config.rcc.apb2_pre = APBPrescaler::DIV1;
36 config.rcc.adc = AdcClockSource::Pll(AdcPllPrescaler::DIV1);
37 }
28 let mut p = embassy_stm32::init(config); 38 let mut p = embassy_stm32::init(config);
29 39
30 info!("create adc..."); 40 info!("create adc...");
@@ -32,7 +42,7 @@ async fn main(_spawner: Spawner) -> ! {
32 let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); 42 let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay);
33 let mut opamp = OpAmp::new(p.OPAMP2); 43 let mut opamp = OpAmp::new(p.OPAMP2);
34 44
35 adc.set_sample_time(SampleTime::Cycles601_5); 45 adc.set_sample_time(SampleTime::CYCLES601_5);
36 46
37 info!("enable vrefint..."); 47 info!("enable vrefint...");
38 48
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index c149cad92..e6d1a6c02 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::hrtim::*; 6use embassy_stm32::hrtim::*;
7use embassy_stm32::rcc::HrtimClockSource;
8use embassy_stm32::time::{khz, mhz}; 7use embassy_stm32::time::{khz, mhz};
9use embassy_stm32::Config; 8use embassy_stm32::Config;
10use embassy_time::Timer; 9use embassy_time::Timer;
@@ -12,14 +11,27 @@ use {defmt_rtt as _, panic_probe as _};
12 11
13#[embassy_executor::main] 12#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
15 let mut config: Config = Default::default(); 14 let mut config = Config::default();
16 config.rcc.sysclk = Some(mhz(64)); 15 {
17 config.rcc.hclk = Some(mhz(64)); 16 use embassy_stm32::rcc::*;
18 config.rcc.pclk1 = Some(mhz(32)); 17 config.rcc.hse = Some(Hse {
19 config.rcc.pclk2 = Some(mhz(64)); 18 freq: mhz(8),
20 config.rcc.hrtim = HrtimClockSource::PllClk; 19 mode: HseMode::Bypass,
20 });
21 config.rcc.pll = Some(Pll {
22 src: PllSource::HSE,
23 prediv: PllPreDiv::DIV1,
24 mul: PllMul::MUL9,
25 });
26 config.rcc.sys = Sysclk::PLL1_P;
27 config.rcc.ahb_pre = AHBPrescaler::DIV1;
28 config.rcc.apb1_pre = APBPrescaler::DIV2;
29 config.rcc.apb2_pre = APBPrescaler::DIV1;
21 30
31 config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P;
32 }
22 let p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
34
23 info!("Hello World!"); 35 info!("Hello World!");
24 36
25 let ch1 = PwmPin::new_cha(p.PA8); 37 let ch1 = PwmPin::new_cha(p.PA8);
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index cd46fc85b..512158bef 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -27,6 +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"
30usbd-hid = "0.7.0"
30static_cell = "2" 31static_cell = "2"
31chrono = { version = "^0.4", default-features = false} 32chrono = { version = "^0.4", default-features = false}
32 33
diff --git a/examples/stm32f4/src/bin/button_exti.rs b/examples/stm32f4/src/bin/button_exti.rs
index 67751187d..2a546dac5 100644
--- a/examples/stm32f4/src/bin/button_exti.rs
+++ b/examples/stm32f4/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs
index abab07b6b..82d8a37ba 100644
--- a/examples/stm32f4/src/bin/rtc.rs
+++ b/examples/stm32f4/src/bin/rtc.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 loop { 28 loop {
29 let now: NaiveDateTime = rtc.now().unwrap().into(); 29 let now: NaiveDateTime = rtc.now().unwrap().into();
30 30
31 info!("{}", now.timestamp()); 31 info!("{}", now.and_utc().timestamp());
32 32
33 Timer::after_millis(1000).await; 33 Timer::after_millis(1000).await;
34 } 34 }
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
new file mode 100644
index 000000000..c98792880
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,148 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz;
7use embassy_stm32::usb_otg::Driver;
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
9use embassy_time::Timer;
10use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
11use embassy_usb::control::OutResponse;
12use embassy_usb::Builder;
13use futures::future::join;
14use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = Config::default();
24 {
25 use embassy_stm32::rcc::*;
26 config.rcc.hse = Some(Hse {
27 freq: Hertz(8_000_000),
28 mode: HseMode::Bypass,
29 });
30 config.rcc.pll_src = PllSource::HSE;
31 config.rcc.pll = Some(Pll {
32 prediv: PllPreDiv::DIV4,
33 mul: PllMul::MUL168,
34 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
35 divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
36 divr: None,
37 });
38 config.rcc.ahb_pre = AHBPrescaler::DIV1;
39 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.sys = Sysclk::PLL1_P;
42 }
43 let p = embassy_stm32::init(config);
44
45 // Create the driver, from the HAL.
46 let mut ep_out_buffer = [0u8; 256];
47 let mut config = embassy_stm32::usb_otg::Config::default();
48 config.vbus_detection = true;
49 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
50
51 // Create embassy-usb Config
52 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
53 config.manufacturer = Some("Embassy");
54 config.product = Some("HID mouse example");
55 config.serial_number = Some("12345678");
56
57 // Required for windows compatibility.
58 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
59 config.device_class = 0xEF;
60 config.device_sub_class = 0x02;
61 config.device_protocol = 0x01;
62 config.composite_with_iads = true;
63
64 // Create embassy-usb DeviceBuilder using the driver and config.
65 // It needs some buffers for building the descriptors.
66 let mut device_descriptor = [0; 256];
67 let mut config_descriptor = [0; 256];
68 let mut bos_descriptor = [0; 256];
69 let mut control_buf = [0; 64];
70
71 let request_handler = MyRequestHandler {};
72
73 let mut state = State::new();
74
75 let mut builder = Builder::new(
76 driver,
77 config,
78 &mut device_descriptor,
79 &mut config_descriptor,
80 &mut bos_descriptor,
81 &mut [], // no msos descriptors
82 &mut control_buf,
83 );
84
85 // Create classes on the builder.
86 let config = embassy_usb::class::hid::Config {
87 report_descriptor: MouseReport::desc(),
88 request_handler: Some(&request_handler),
89 poll_ms: 60,
90 max_packet_size: 8,
91 };
92
93 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
94
95 // Build the builder.
96 let mut usb = builder.build();
97
98 // Run the USB device.
99 let usb_fut = usb.run();
100
101 // Do stuff with the class!
102 let hid_fut = async {
103 let mut y: i8 = 5;
104 loop {
105 Timer::after_millis(500).await;
106
107 y = -y;
108 let report = MouseReport {
109 buttons: 0,
110 x: 0,
111 y,
112 wheel: 0,
113 pan: 0,
114 };
115 match writer.write_serialize(&report).await {
116 Ok(()) => {}
117 Err(e) => warn!("Failed to send report: {:?}", e),
118 }
119 }
120 };
121
122 // Run everything concurrently.
123 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
124 join(usb_fut, hid_fut).await;
125}
126
127struct MyRequestHandler {}
128
129impl RequestHandler for MyRequestHandler {
130 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
131 info!("Get report for {:?}", id);
132 None
133 }
134
135 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
136 info!("Set report for {:?}: {=[u8]}", id, data);
137 OutResponse::Accepted
138 }
139
140 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
141 info!("Set idle rate for {:?} to {:?}", id, dur);
142 }
143
144 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
145 info!("Get idle rate for {:?}", id);
146 None
147 }
148}
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index 239709253..6122cea2d 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) {
91 loop { 91 loop {
92 for &color in color_list { 92 for &color in color_list {
93 // with &mut, we can easily reuse same DMA channel multiple times 93 // with &mut, we can easily reuse same DMA channel multiple times
94 ws2812_pwm.gen_waveform(&mut dp.DMA1_CH2, pwm_channel, color).await; 94 ws2812_pwm.waveform_up(&mut dp.DMA1_CH2, pwm_channel, color).await;
95 // ws2812 need at least 50 us low level input to confirm the input data and change it's state 95 // ws2812 need at least 50 us low level input to confirm the input data and change it's state
96 Timer::after_micros(50).await; 96 Timer::after_micros(50).await;
97 // wait until ticker tick 97 // wait until ticker tick
diff --git a/examples/stm32f7/.cargo/config.toml b/examples/stm32f7/.cargo/config.toml
index 9088eea6e..086da2d78 100644
--- a/examples/stm32f7/.cargo/config.toml
+++ b/examples/stm32f7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32F767ZITx" 3runner = "probe-rs run --chip STM32F777ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 941ba38cd..305816a2b 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -5,8 +5,8 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32f767zi to your chip name, if necessary. 8# Change stm32f777zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
@@ -28,6 +28,9 @@ rand_core = "0.6.3"
28critical-section = "1.1" 28critical-section = "1.1"
29embedded-storage = "0.3.1" 29embedded-storage = "0.3.1"
30static_cell = "2" 30static_cell = "2"
31sha2 = { version = "0.10.8", default-features = false }
32hmac = "0.12.1"
33aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
31 34
32[profile.release] 35[profile.release]
33debug = 2 36debug = 2
diff --git a/examples/stm32f7/src/bin/button_exti.rs b/examples/stm32f7/src/bin/button_exti.rs
index 67751187d..2a546dac5 100644
--- a/examples/stm32f7/src/bin/button_exti.rs
+++ b/examples/stm32f7/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs
new file mode 100644
index 000000000..04927841a
--- /dev/null
+++ b/examples/stm32f7/src/bin/cryp.rs
@@ -0,0 +1,74 @@
1#![no_std]
2#![no_main]
3
4use aes_gcm::aead::heapless::Vec;
5use aes_gcm::aead::{AeadInPlace, KeyInit};
6use aes_gcm::Aes128Gcm;
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_stm32::cryp::*;
10use embassy_stm32::Config;
11use embassy_time::Instant;
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) -> ! {
16 let config = Config::default();
17 let p = embassy_stm32::init(config);
18
19 let payload: &[u8] = b"hello world";
20 let aad: &[u8] = b"additional data";
21
22 let hw_cryp = Cryp::new(p.CRYP);
23 let key: [u8; 16] = [0; 16];
24 let mut ciphertext: [u8; 11] = [0; 11];
25 let mut plaintext: [u8; 11] = [0; 11];
26 let iv: [u8; 12] = [0; 12];
27
28 let hw_start_time = Instant::now();
29
30 // Encrypt in hardware using AES-GCM 128-bit
31 let aes_gcm = AesGcm::new(&key, &iv);
32 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt);
33 hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true);
34 hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true);
35 let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt);
36
37 // Decrypt in hardware using AES-GCM 128-bit
38 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt);
39 hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true);
40 hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true);
41 let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt);
42
43 let hw_end_time = Instant::now();
44 let hw_execution_time = hw_end_time - hw_start_time;
45
46 info!("AES-GCM Ciphertext: {:?}", ciphertext);
47 info!("AES-GCM Plaintext: {:?}", plaintext);
48 assert_eq!(payload, plaintext);
49 assert_eq!(encrypt_tag, decrypt_tag);
50
51 let sw_start_time = Instant::now();
52
53 // Encrypt in software using AES-GCM 128-bit
54 let mut payload_vec: Vec<u8, 32> = Vec::from_slice(&payload).unwrap();
55 let cipher = Aes128Gcm::new(&key.into());
56 let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
57
58 assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]);
59 assert_eq!(
60 encrypt_tag,
61 payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]
62 );
63
64 // Decrypt in software using AES-GCM 128-bit
65 let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
66
67 let sw_end_time = Instant::now();
68 let sw_execution_time = sw_end_time - sw_start_time;
69
70 info!("Hardware Execution Time: {:?}", hw_execution_time);
71 info!("Software Execution Time: {:?}", sw_execution_time);
72
73 loop {}
74}
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 5bff48197..9a608e909 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _};
19 19
20bind_interrupts!(struct Irqs { 20bind_interrupts!(struct Irqs {
21 ETH => eth::InterruptHandler; 21 ETH => eth::InterruptHandler;
22 RNG => rng::InterruptHandler<peripherals::RNG>; 22 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
23}); 23});
24 24
25type Device = Ethernet<'static, ETH, GenericSMI>; 25type Device = Ethernet<'static, ETH, GenericSMI>;
diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs
new file mode 100644
index 000000000..c2d1a7158
--- /dev/null
+++ b/examples/stm32f7/src/bin/hash.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_stm32::hash::*;
7use embassy_stm32::{bind_interrupts, hash, peripherals, Config};
8use embassy_time::Instant;
9use hmac::{Hmac, Mac};
10use sha2::{Digest, Sha256};
11use {defmt_rtt as _, panic_probe as _};
12
13type HmacSha256 = Hmac<Sha256>;
14
15bind_interrupts!(struct Irqs {
16 HASH_RNG => hash::InterruptHandler<peripherals::HASH>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) -> ! {
21 let config = Config::default();
22 let p = embassy_stm32::init(config);
23
24 let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh";
25 let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr";
26
27 let mut hw_hasher = Hash::new(p.HASH, p.DMA2_CH7, Irqs);
28
29 let hw_start_time = Instant::now();
30
31 // Compute a digest in hardware.
32 let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None);
33 hw_hasher.update(&mut context, test_1).await;
34 hw_hasher.update(&mut context, test_2).await;
35 let mut hw_digest: [u8; 32] = [0; 32];
36 hw_hasher.finish(context, &mut hw_digest).await;
37
38 let hw_end_time = Instant::now();
39 let hw_execution_time = hw_end_time - hw_start_time;
40
41 let sw_start_time = Instant::now();
42
43 // Compute a digest in software.
44 let mut sw_hasher = Sha256::new();
45 sw_hasher.update(test_1);
46 sw_hasher.update(test_2);
47 let sw_digest = sw_hasher.finalize();
48
49 let sw_end_time = Instant::now();
50 let sw_execution_time = sw_end_time - sw_start_time;
51
52 info!("Hardware Digest: {:?}", hw_digest);
53 info!("Software Digest: {:?}", sw_digest[..]);
54 info!("Hardware Execution Time: {:?}", hw_execution_time);
55 info!("Software Execution Time: {:?}", sw_execution_time);
56 assert_eq!(hw_digest, sw_digest[..]);
57
58 let hmac_key: [u8; 64] = [0x55; 64];
59
60 // Compute HMAC in hardware.
61 let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key));
62 hw_hasher.update(&mut sha256hmac_context, test_1).await;
63 hw_hasher.update(&mut sha256hmac_context, test_2).await;
64 let mut hw_hmac: [u8; 32] = [0; 32];
65 hw_hasher.finish(sha256hmac_context, &mut hw_hmac).await;
66
67 // Compute HMAC in software.
68 let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap();
69 sw_mac.update(test_1);
70 sw_mac.update(test_2);
71 let sw_hmac = sw_mac.finalize().into_bytes();
72
73 info!("Hardware HMAC: {:?}", hw_hmac);
74 info!("Software HMAC: {:?}", sw_hmac[..]);
75 assert_eq!(hw_hmac, sw_hmac[..]);
76
77 loop {}
78}
diff --git a/examples/stm32g0/src/bin/button_exti.rs b/examples/stm32g0/src/bin/button_exti.rs
index 1e970fdd6..34a08bbc6 100644
--- a/examples/stm32g0/src/bin/button_exti.rs
+++ b/examples/stm32g0/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Up); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs
index 78a779e29..3ea06cdee 100644
--- a/examples/stm32g0/src/bin/hf_timer.rs
+++ b/examples/stm32g0/src/bin/hf_timer.rs
@@ -4,37 +4,36 @@
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
7use embassy_stm32::pac::rcc::vals::Tim1sel;
8use embassy_stm32::rcc::{ClockSrc, Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr};
9use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
10use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; 8use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
11use embassy_stm32::timer::simple_pwm::PwmPin; 9use embassy_stm32::timer::simple_pwm::PwmPin;
12use embassy_stm32::timer::Channel; 10use embassy_stm32::timer::Channel;
13use embassy_stm32::{pac, Config as PeripheralConfig}; 11use embassy_stm32::Config as PeripheralConfig;
14use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
15 13
16#[embassy_executor::main] 14#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
18 let mut rcc_config = RccConfig::default(); 16 let mut config = PeripheralConfig::default();
19 rcc_config.mux = ClockSrc::PLL(PllConfig { 17 {
20 source: PllSource::HSI, 18 use embassy_stm32::rcc::*;
21 m: Pllm::DIV1, 19 config.rcc.hsi = true;
22 n: Plln::MUL16, 20 config.rcc.pll = Some(Pll {
23 r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) 21 source: PllSource::HSI,
24 q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) 22 prediv: PllPreDiv::DIV1,
25 p: None, 23 mul: PllMul::MUL16,
26 }); 24 divp: None,
27 25 divq: Some(PllQDiv::DIV2), // 16 / 1 * 16 / 2 = 128 Mhz
28 let mut peripheral_config = PeripheralConfig::default(); 26 divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz
29 peripheral_config.rcc = rcc_config; 27 });
30 28 config.rcc.sys = Sysclk::PLL1_R;
31 let p = embassy_stm32::init(peripheral_config); 29
32 30 // configure TIM1 mux to select PLLQ as clock source
33 // configure TIM1 mux to select PLLQ as clock source 31 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
34 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf 32 // RM0444 page 210
35 // RM0444 page 210 33 // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
36 // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 34 config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q;
37 pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); 35 }
36 let p = embassy_stm32::init(config);
38 37
39 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); 38 let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
40 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); 39 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull);
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs
index f5aaa5624..8b9915626 100644
--- a/examples/stm32g0/src/bin/usb_serial.rs
+++ b/examples/stm32g0/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::rcc::{Hsi48Config, UsbSrc};
8use embassy_stm32::usb::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs {
19#[embassy_executor::main] 18#[embassy_executor::main]
20async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 20 let mut config = Config::default();
22 config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { 21 {
23 sync_from_usb: true, 22 use embassy_stm32::rcc::*;
24 ..Default::default() 23 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
25 })); 24 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
25 }
26 let p = embassy_stm32::init(config); 26 let p = embassy_stm32::init(config);
27 27
28 info!("Hello World!"); 28 info!("Hello World!");
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 895ad3e7c..64c749b9b 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.0", 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" }
15usbd-hid = "0.6.0" 15usbd-hid = "0.7.0"
16 16
17defmt = "0.3" 17defmt = "0.3"
18defmt-rtt = "0.4" 18defmt-rtt = "0.4"
@@ -20,9 +20,11 @@ defmt-rtt = "0.4"
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
22embedded-hal = "0.2.6" 22embedded-hal = "0.2.6"
23embedded-can = { version = "0.4" }
23panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 25futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.8", default-features = false } 26heapless = { version = "0.8", default-features = false }
27static_cell = "2.0.0"
26 28
27[profile.release] 29[profile.release]
28debug = 2 30debug = 2
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 35324d931..ae64bc8e4 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime}; 6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSource};
8use embassy_stm32::Config; 7use embassy_stm32::Config;
9use embassy_time::{Delay, Timer}; 8use embassy_time::{Delay, Timer};
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -12,25 +11,25 @@ use {defmt_rtt as _, panic_probe as _};
12#[embassy_executor::main] 11#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
14 let mut config = Config::default(); 13 let mut config = Config::default();
15 14 {
16 config.rcc.pll = Some(Pll { 15 use embassy_stm32::rcc::*;
17 source: PllSource::HSI, 16 config.rcc.pll = Some(Pll {
18 prediv_m: PllM::DIV4, 17 source: PllSource::HSI,
19 mul_n: PllN::MUL85, 18 prediv: PllPreDiv::DIV4,
20 div_p: None, 19 mul: PllMul::MUL85,
21 div_q: None, 20 divp: None,
22 // Main system clock at 170 MHz 21 divq: None,
23 div_r: Some(PllR::DIV2), 22 // Main system clock at 170 MHz
24 }); 23 divr: Some(PllRDiv::DIV2),
25 24 });
26 config.rcc.adc12_clock_source = AdcClockSource::SYS; 25 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
27 config.rcc.mux = ClockSrc::PLL; 26 config.rcc.sys = Sysclk::PLL1_R;
28 27 }
29 let mut p = embassy_stm32::init(config); 28 let mut p = embassy_stm32::init(config);
30 info!("Hello World!"); 29 info!("Hello World!");
31 30
32 let mut adc = Adc::new(p.ADC2, &mut Delay); 31 let mut adc = Adc::new(p.ADC2, &mut Delay);
33 adc.set_sample_time(SampleTime::Cycles32_5); 32 adc.set_sample_time(SampleTime::CYCLES32_5);
34 33
35 loop { 34 loop {
36 let measured = adc.read(&mut p.PA7); 35 let measured = adc.read(&mut p.PA7);
diff --git a/examples/stm32g4/src/bin/button_exti.rs b/examples/stm32g4/src/bin/button_exti.rs
index 67751187d..2a546dac5 100644
--- a/examples/stm32g4/src/bin/button_exti.rs
+++ b/examples/stm32g4/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
new file mode 100644
index 000000000..4373a89a8
--- /dev/null
+++ b/examples/stm32g4/src/bin/can.rs
@@ -0,0 +1,229 @@
1#![no_std]
2#![no_main]
3use defmt::*;
4use embassy_executor::Spawner;
5use embassy_stm32::peripherals::*;
6use embassy_stm32::time::Hertz;
7use embassy_stm32::{bind_interrupts, can, Config};
8use embassy_time::Timer;
9use static_cell::StaticCell;
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
14 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let mut config = Config::default();
20 {
21 use embassy_stm32::rcc::*;
22 config.rcc.hse = Some(Hse {
23 freq: Hertz(24_000_000),
24 mode: HseMode::Oscillator,
25 });
26 config.rcc.pll = Some(Pll {
27 source: PllSource::HSE,
28 prediv: PllPreDiv::DIV6,
29 mul: PllMul::MUL85,
30 divp: None,
31 divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
32 divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
33 });
34 config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
35 config.rcc.sys = Sysclk::PLL1_R;
36 }
37 let peripherals = embassy_stm32::init(config);
38
39 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
40
41 can.set_extended_filter(
42 can::filter::ExtendedFilterSlot::_0,
43 can::filter::ExtendedFilter::accept_all_into_fifo1(),
44 );
45
46 // 250k bps
47 can.set_bitrate(250_000);
48
49 let use_fd = false;
50
51 // 1M bps
52 if use_fd {
53 can.set_fd_data_bitrate(1_000_000, false);
54 }
55
56 info!("Configured");
57
58 let mut can = can.start(match use_fd {
59 true => can::FdcanOperatingMode::InternalLoopbackMode,
60 false => can::FdcanOperatingMode::NormalOperationMode,
61 });
62
63 let mut i = 0;
64 let mut last_read_ts = embassy_time::Instant::now();
65
66 loop {
67 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
68 info!("Writing frame");
69
70 _ = can.write(&frame).await;
71
72 match can.read().await {
73 Ok((rx_frame, ts)) => {
74 let delta = (ts - last_read_ts).as_millis();
75 last_read_ts = ts;
76 info!(
77 "Rx: {} {:02x} --- {}ms",
78 rx_frame.header().len(),
79 rx_frame.data()[0..rx_frame.header().len() as usize],
80 delta,
81 )
82 }
83 Err(_err) => error!("Error in frame"),
84 }
85
86 Timer::after_millis(250).await;
87
88 i += 1;
89 if i > 2 {
90 break;
91 }
92 }
93
94 // Use the FD API's even if we don't get FD packets.
95
96 loop {
97 if use_fd {
98 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
99 info!("Writing frame using FD API");
100 _ = can.write_fd(&frame).await;
101 } else {
102 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 8]).unwrap();
103 info!("Writing frame using FD API");
104 _ = can.write_fd(&frame).await;
105 }
106
107 match can.read_fd().await {
108 Ok((rx_frame, ts)) => {
109 let delta = (ts - last_read_ts).as_millis();
110 last_read_ts = ts;
111 info!(
112 "Rx: {} {:02x} --- using FD API {}ms",
113 rx_frame.header().len(),
114 rx_frame.data()[0..rx_frame.header().len() as usize],
115 delta,
116 )
117 }
118 Err(_err) => error!("Error in frame"),
119 }
120
121 Timer::after_millis(250).await;
122
123 i += 1;
124 if i > 4 {
125 break;
126 }
127 }
128 i = 0;
129 let (mut tx, mut rx) = can.split();
130 // With split
131 loop {
132 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
133 info!("Writing frame");
134 _ = tx.write(&frame).await;
135
136 match rx.read().await {
137 Ok((rx_frame, ts)) => {
138 let delta = (ts - last_read_ts).as_millis();
139 last_read_ts = ts;
140 info!(
141 "Rx: {} {:02x} --- {}ms",
142 rx_frame.header().len(),
143 rx_frame.data()[0..rx_frame.header().len() as usize],
144 delta,
145 )
146 }
147 Err(_err) => error!("Error in frame"),
148 }
149
150 Timer::after_millis(250).await;
151
152 i += 1;
153
154 if i > 2 {
155 break;
156 }
157 }
158
159 let can = can::Fdcan::join(tx, rx);
160
161 info!("\n\n\nBuffered\n");
162 if use_fd {
163 static TX_BUF: StaticCell<can::TxFdBuf<8>> = StaticCell::new();
164 static RX_BUF: StaticCell<can::RxFdBuf<10>> = StaticCell::new();
165 let mut can = can.buffered_fd(
166 TX_BUF.init(can::TxFdBuf::<8>::new()),
167 RX_BUF.init(can::RxFdBuf::<10>::new()),
168 );
169 loop {
170 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
171 info!("Writing frame");
172
173 _ = can.write(frame).await;
174
175 match can.read().await {
176 Ok((rx_frame, ts)) => {
177 let delta = (ts - last_read_ts).as_millis();
178 last_read_ts = ts;
179 info!(
180 "Rx: {} {:02x} --- {}ms",
181 rx_frame.header().len(),
182 rx_frame.data()[0..rx_frame.header().len() as usize],
183 delta,
184 )
185 }
186 Err(_err) => error!("Error in frame"),
187 }
188
189 Timer::after_millis(250).await;
190
191 i += 1;
192 }
193 } else {
194 static TX_BUF: StaticCell<can::TxBuf<8>> = StaticCell::new();
195 static RX_BUF: StaticCell<can::RxBuf<10>> = StaticCell::new();
196 let mut can = can.buffered(
197 TX_BUF.init(can::TxBuf::<8>::new()),
198 RX_BUF.init(can::RxBuf::<10>::new()),
199 );
200 loop {
201 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
202 info!("Writing frame");
203
204 // You can use any of these approaches to send. The writer makes it
205 // easy to share sending from multiple tasks.
206 //_ = can.write(frame).await;
207 //can.writer().try_write(frame).unwrap();
208 can.writer().write(frame).await;
209
210 match can.read().await {
211 Ok((rx_frame, ts)) => {
212 let delta = (ts - last_read_ts).as_millis();
213 last_read_ts = ts;
214 info!(
215 "Rx: {} {:02x} --- {}ms",
216 rx_frame.header().len(),
217 rx_frame.data()[0..rx_frame.header().len() as usize],
218 delta,
219 )
220 }
221 Err(_err) => error!("Error in frame"),
222 }
223
224 Timer::after_millis(250).await;
225
226 i += 1;
227 }
228 }
229}
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 46ebe0b0d..08ed95b34 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSource};
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
@@ -11,19 +10,20 @@ use {defmt_rtt as _, panic_probe as _};
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 11async fn main(_spawner: Spawner) {
13 let mut config = Config::default(); 12 let mut config = Config::default();
14 13 {
15 config.rcc.pll = Some(Pll { 14 use embassy_stm32::rcc::*;
16 source: PllSource::HSI, 15 config.rcc.hsi = true;
17 prediv_m: PllM::DIV4, 16 config.rcc.pll = Some(Pll {
18 mul_n: PllN::MUL85, 17 source: PllSource::HSI,
19 div_p: None, 18 prediv: PllPreDiv::DIV4,
20 div_q: None, 19 mul: PllMul::MUL85,
21 // Main system clock at 170 MHz 20 divp: None,
22 div_r: Some(PllR::DIV2), 21 divq: None,
23 }); 22 // Main system clock at 170 MHz
24 23 divr: Some(PllRDiv::DIV2),
25 config.rcc.mux = ClockSrc::PLL; 24 });
26 25 config.rcc.sys = Sysclk::PLL1_R;
26 }
27 let _p = embassy_stm32::init(config); 27 let _p = embassy_stm32::init(config);
28 info!("Hello World!"); 28 info!("Hello World!");
29 29
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index c26fa76b7..dc95aa6e5 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, Hsi48Config, Pll, PllM, PllN, PllQ, PllR, PllSource};
7use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::{self, Driver, Instance}; 7use embassy_stm32::usb::{self, Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, Config};
@@ -20,31 +19,27 @@ bind_interrupts!(struct Irqs {
20#[embassy_executor::main] 19#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
22 let mut config = Config::default(); 21 let mut config = Config::default();
23 22 {
24 // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. 23 use embassy_stm32::rcc::*;
25 const USE_HSI48: bool = true;
26
27 let plldivq = if USE_HSI48 { None } else { Some(PllQ::DIV6) };
28
29 config.rcc.pll = Some(Pll {
30 source: PllSource::HSE(Hertz(8_000_000)),
31 prediv_m: PllM::DIV2,
32 mul_n: PllN::MUL72,
33 div_p: None,
34 div_q: plldivq,
35 // Main system clock at 144 MHz
36 div_r: Some(PllR::DIV2),
37 });
38
39 config.rcc.mux = ClockSrc::PLL;
40
41 if USE_HSI48 {
42 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. 24 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
43 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true })); 25 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
44 } else { 26 config.rcc.hse = Some(Hse {
45 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ); 27 freq: Hertz(8_000_000),
28 mode: HseMode::Oscillator,
29 });
30 config.rcc.pll = Some(Pll {
31 source: PllSource::HSE,
32 prediv: PllPreDiv::DIV2,
33 mul: PllMul::MUL72,
34 divp: None,
35 divq: Some(PllQDiv::DIV6), // 48mhz
36 divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz
37 });
38 config.rcc.sys = Sysclk::PLL1_R;
39 config.rcc.boost = true; // BOOST!
40 config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
41 //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead.
46 } 42 }
47
48 let p = embassy_stm32::init(config); 43 let p = embassy_stm32::init(config);
49 44
50 info!("Hello World!"); 45 info!("Hello World!");
diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs
index 67751187d..2a546dac5 100644
--- a/examples/stm32h5/src/bin/button_exti.rs
+++ b/examples/stm32h5/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
new file mode 100644
index 000000000..643df27f9
--- /dev/null
+++ b/examples/stm32h5/src/bin/can.rs
@@ -0,0 +1,96 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::peripherals::*;
7use embassy_stm32::{bind_interrupts, can, rcc, Config};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
13 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 config.rcc.hse = Some(rcc::Hse {
20 freq: embassy_stm32::time::Hertz(25_000_000),
21 mode: rcc::HseMode::Oscillator,
22 });
23 config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE;
24
25 let peripherals = embassy_stm32::init(config);
26
27 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
28
29 // 250k bps
30 can.set_bitrate(250_000);
31
32 //let mut can = can.into_internal_loopback_mode();
33 let mut can = can.into_normal_mode();
34
35 info!("CAN Configured");
36
37 let mut i = 0;
38 let mut last_read_ts = embassy_time::Instant::now();
39
40 loop {
41 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
42 info!("Writing frame");
43 _ = can.write(&frame).await;
44
45 match can.read().await {
46 Ok((rx_frame, ts)) => {
47 let delta = (ts - last_read_ts).as_millis();
48 last_read_ts = ts;
49 info!(
50 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
51 rx_frame.data()[0],
52 rx_frame.data()[1],
53 rx_frame.data()[2],
54 rx_frame.data()[3],
55 delta,
56 )
57 }
58 Err(_err) => error!("Error in frame"),
59 }
60
61 Timer::after_millis(250).await;
62
63 i += 1;
64 if i > 3 {
65 break;
66 }
67 }
68
69 let (mut tx, mut rx) = can.split();
70 // With split
71 loop {
72 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
73 info!("Writing frame");
74 _ = tx.write(&frame).await;
75
76 match rx.read().await {
77 Ok((rx_frame, ts)) => {
78 let delta = (ts - last_read_ts).as_millis();
79 last_read_ts = ts;
80 info!(
81 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
82 rx_frame.data()[0],
83 rx_frame.data()[1],
84 rx_frame.data()[2],
85 rx_frame.data()[3],
86 delta,
87 )
88 }
89 Err(_err) => error!("Error in frame"),
90 }
91
92 Timer::after_millis(250).await;
93
94 i += 1;
95 }
96}
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 208493d8c..83477c8fa 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -5,7 +5,7 @@ use defmt::{panic, *};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz; 6use embassy_stm32::time::Hertz;
7use embassy_stm32::usb::{Driver, Instance}; 7use embassy_stm32::usb::{Driver, Instance};
8use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 11use embassy_usb::Builder;
@@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) {
41 config.rcc.apb3_pre = APBPrescaler::DIV4; 41 config.rcc.apb3_pre = APBPrescaler::DIV4;
42 config.rcc.sys = Sysclk::PLL1_P; 42 config.rcc.sys = Sysclk::PLL1_P;
43 config.rcc.voltage_scale = VoltageScale::Scale0; 43 config.rcc.voltage_scale = VoltageScale::Scale0;
44 config.rcc.mux.usbsel = mux::Usbsel::HSI48;
44 } 45 }
45 let p = embassy_stm32::init(config); 46 let p = embassy_stm32::init(config);
46 47
47 info!("Hello World!"); 48 info!("Hello World!");
48 49
49 pac::RCC.ccipr4().write(|w| {
50 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
51 });
52
53 // Create the driver, from the HAL. 50 // Create the driver, from the HAL.
54 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 51 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
55 52
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index fe6fe69a1..a5594d10c 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 38 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 39 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
40 config.rcc.voltage_scale = VoltageScale::Scale1; 40 config.rcc.voltage_scale = VoltageScale::Scale1;
41 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 41 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
42 } 42 }
43 let mut p = embassy_stm32::init(config); 43 let mut p = embassy_stm32::init(config);
44 44
@@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) {
46 46
47 let mut adc = Adc::new(p.ADC3, &mut Delay); 47 let mut adc = Adc::new(p.ADC3, &mut Delay);
48 48
49 adc.set_sample_time(SampleTime::Cycles32_5); 49 adc.set_sample_time(SampleTime::CYCLES32_5);
50 50
51 let mut vrefint_channel = adc.enable_vrefint(); 51 let mut vrefint_channel = adc.enable_vrefint();
52 52
diff --git a/examples/stm32h7/src/bin/button_exti.rs b/examples/stm32h7/src/bin/button_exti.rs
index 67751187d..2a546dac5 100644
--- a/examples/stm32h7/src/bin/button_exti.rs
+++ b/examples/stm32h7/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
new file mode 100644
index 000000000..13a6a5051
--- /dev/null
+++ b/examples/stm32h7/src/bin/can.rs
@@ -0,0 +1,96 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::peripherals::*;
7use embassy_stm32::{bind_interrupts, can, rcc, Config};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
13 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 config.rcc.hse = Some(rcc::Hse {
20 freq: embassy_stm32::time::Hertz(25_000_000),
21 mode: rcc::HseMode::Oscillator,
22 });
23 config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
24
25 let peripherals = embassy_stm32::init(config);
26
27 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
28
29 // 250k bps
30 can.set_bitrate(250_000);
31
32 //let mut can = can.into_internal_loopback_mode();
33 let mut can = can.into_normal_mode();
34
35 info!("CAN Configured");
36
37 let mut i = 0;
38 let mut last_read_ts = embassy_time::Instant::now();
39
40 loop {
41 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
42 info!("Writing frame");
43 _ = can.write(&frame).await;
44
45 match can.read().await {
46 Ok((rx_frame, ts)) => {
47 let delta = (ts - last_read_ts).as_millis();
48 last_read_ts = ts;
49 info!(
50 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
51 rx_frame.data()[0],
52 rx_frame.data()[1],
53 rx_frame.data()[2],
54 rx_frame.data()[3],
55 delta,
56 )
57 }
58 Err(_err) => error!("Error in frame"),
59 }
60
61 Timer::after_millis(250).await;
62
63 i += 1;
64 if i > 3 {
65 break;
66 }
67 }
68
69 let (mut tx, mut rx) = can.split();
70 // With split
71 loop {
72 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
73 info!("Writing frame");
74 _ = tx.write(&frame).await;
75
76 match rx.read().await {
77 Ok((rx_frame, ts)) => {
78 let delta = (ts - last_read_ts).as_millis();
79 last_read_ts = ts;
80 info!(
81 "Rx: {:x} {:x} {:x} {:x} --- NEW {}",
82 rx_frame.data()[0],
83 rx_frame.data()[1],
84 rx_frame.data()[2],
85 rx_frame.data()[3],
86 delta,
87 )
88 }
89 Err(_err) => error!("Error in frame"),
90 }
91
92 Timer::after_millis(250).await;
93
94 i += 1;
95 }
96}
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index a9bf46de0..a6f969aba 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -40,7 +40,7 @@ fn main() -> ! {
40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 40 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 41 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
42 config.rcc.voltage_scale = VoltageScale::Scale1; 42 config.rcc.voltage_scale = VoltageScale::Scale1;
43 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 43 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
44 } 44 }
45 let p = embassy_stm32::init(config); 45 let p = embassy_stm32::init(config);
46 46
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index 8e5c41a43..feec28993 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::Basic16bitInstance; 11use embassy_stm32::timer::low_level::BasicInstance;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
42 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 42 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
43 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 43 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
44 config.rcc.voltage_scale = VoltageScale::Scale1; 44 config.rcc.voltage_scale = VoltageScale::Scale1;
45 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 45 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
46 } 46 }
47 47
48 // Initialize the board and obtain a Peripherals instance 48 // Initialize the board and obtain a Peripherals instance
@@ -75,9 +75,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
75 dac.enable(); 75 dac.enable();
76 76
77 TIM6::enable_and_reset(); 77 TIM6::enable_and_reset();
78 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 78 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
79 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 79 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
80 TIM6::regs().cr1().modify(|w| { 80 TIM6::regs_basic().cr1().modify(|w| {
81 w.set_opm(false); 81 w.set_opm(false);
82 w.set_cen(true); 82 w.set_cen(true);
83 }); 83 });
@@ -112,9 +112,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
112 } 112 }
113 113
114 TIM7::enable_and_reset(); 114 TIM7::enable_and_reset();
115 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 115 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
116 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 116 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
117 TIM7::regs().cr1().modify(|w| { 117 TIM7::regs_basic().cr1().modify(|w| {
118 w.set_opm(false); 118 w.set_opm(false);
119 w.set_cen(true); 119 w.set_cen(true);
120 }); 120 });
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index dcc6e36e2..aeb169e19 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -65,6 +65,7 @@ async fn main(spawner: Spawner) -> ! {
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66 66
67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); 67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
68
68 let device = Ethernet::new( 69 let device = Ethernet::new(
69 PACKETS.init(PacketQueue::<16, 16>::new()), 70 PACKETS.init(PacketQueue::<16, 16>::new()),
70 p.ETH, 71 p.ETH,
diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs
new file mode 100644
index 000000000..de6ea522a
--- /dev/null
+++ b/examples/stm32h7/src/bin/eth_client_mii.rs
@@ -0,0 +1,142 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_net::tcp::client::{TcpClient, TcpClientState};
7use embassy_net::{Stack, StackResources};
8use embassy_stm32::eth::generic_smi::GenericSMI;
9use embassy_stm32::eth::{Ethernet, PacketQueue};
10use embassy_stm32::peripherals::ETH;
11use embassy_stm32::rng::Rng;
12use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
13use embassy_time::Timer;
14use embedded_io_async::Write;
15use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect};
16use rand_core::RngCore;
17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 ETH => eth::InterruptHandler;
22 RNG => rng::InterruptHandler<peripherals::RNG>;
23});
24
25type Device = Ethernet<'static, ETH, GenericSMI>;
26
27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! {
29 stack.run().await
30}
31
32#[embassy_executor::main]
33async fn main(spawner: Spawner) -> ! {
34 let mut config = Config::default();
35 {
36 use embassy_stm32::rcc::*;
37 config.rcc.hsi = Some(HSIPrescaler::DIV1);
38 config.rcc.csi = true;
39 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
40 config.rcc.pll1 = Some(Pll {
41 source: PllSource::HSI,
42 prediv: PllPreDiv::DIV4,
43 mul: PllMul::MUL50,
44 divp: Some(PllDiv::DIV2),
45 divq: None,
46 divr: None,
47 });
48 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
49 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
50 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
51 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
52 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
53 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
54 config.rcc.voltage_scale = VoltageScale::Scale1;
55 }
56 let p = embassy_stm32::init(config);
57 info!("Hello World!");
58
59 // Generate random seed.
60 let mut rng = Rng::new(p.RNG, Irqs);
61 let mut seed = [0; 8];
62 rng.fill_bytes(&mut seed);
63 let seed = u64::from_le_bytes(seed);
64
65 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
66
67 static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
68
69 let device = Ethernet::new_mii(
70 PACKETS.init(PacketQueue::<16, 16>::new()),
71 p.ETH,
72 Irqs,
73 p.PA1,
74 p.PC3,
75 p.PA2,
76 p.PC1,
77 p.PA7,
78 p.PC4,
79 p.PC5,
80 p.PB0,
81 p.PB1,
82 p.PG13,
83 p.PG12,
84 p.PC2,
85 p.PE2,
86 p.PG11,
87 GenericSMI::new(1),
88 mac_addr,
89 );
90 info!("Device created");
91
92 let config = embassy_net::Config::dhcpv4(Default::default());
93 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
94 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
95 // dns_servers: Vec::new(),
96 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
97 //});
98
99 // Init network stack
100 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new(
103 device,
104 config,
105 RESOURCES.init(StackResources::<3>::new()),
106 seed,
107 ));
108
109 // Launch network task
110 unwrap!(spawner.spawn(net_task(stack)));
111
112 // Ensure DHCP configuration is up before trying connect
113 stack.wait_config_up().await;
114
115 info!("Network task initialized");
116
117 let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
118 let client = TcpClient::new(&stack, &state);
119
120 loop {
121 // You need to start a server on the host machine, for example: `nc -l 8000`
122 let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 100, 1), 8000));
123
124 info!("connecting...");
125 let r = client.connect(addr).await;
126 if let Err(e) = r {
127 info!("connect error: {:?}", e);
128 Timer::after_secs(1).await;
129 continue;
130 }
131 let mut connection = r.unwrap();
132 info!("connected!");
133 loop {
134 let r = connection.write_all(b"Hello\n").await;
135 if let Err(e) = r {
136 info!("write error: {:?}", e);
137 break;
138 }
139 Timer::after_secs(1).await;
140 }
141 }
142}
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index cc508c3cf..049d9967d 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -113,11 +113,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
113 } 113 }
114 114
115 pub fn get_max_duty(&self) -> u32 { 115 pub fn get_max_duty(&self) -> u32 {
116 T::regs_gp32().arr().read().arr() 116 T::regs_gp32().arr().read()
117 } 117 }
118 118
119 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 119 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
120 defmt::assert!(duty < self.get_max_duty()); 120 defmt::assert!(duty < self.get_max_duty());
121 T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty)) 121 T::regs_gp32().ccr(channel.index()).write_value(duty)
122 } 122 }
123} 123}
diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs
index c6b9cf57e..0adb48877 100644
--- a/examples/stm32h7/src/bin/rtc.rs
+++ b/examples/stm32h7/src/bin/rtc.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
24 .unwrap(); 24 .unwrap();
25 25
26 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 26 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
27 info!("Got RTC! {:?}", now.timestamp()); 27 info!("Got RTC! {:?}", now.and_utc().timestamp());
28 28
29 rtc.set_datetime(now.into()).expect("datetime not set"); 29 rtc.set_datetime(now.into()).expect("datetime not set");
30 30
@@ -32,5 +32,5 @@ async fn main(_spawner: Spawner) {
32 Timer::after_millis(20000).await; 32 Timer::after_millis(20000).await;
33 33
34 let then: NaiveDateTime = rtc.now().unwrap().into(); 34 let then: NaiveDateTime = rtc.now().unwrap().into();
35 info!("Got RTC! {:?}", then.timestamp()); 35 info!("Got RTC! {:?}", then.and_utc().timestamp());
36} 36}
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs
new file mode 100644
index 000000000..97d41ca4b
--- /dev/null
+++ b/examples/stm32l0/src/bin/adc.rs
@@ -0,0 +1,40 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC;
8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 ADC1_COMP => adc::InterruptHandler<ADC>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!");
20
21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
22 adc.set_sample_time(SampleTime::CYCLES79_5);
23 let mut pin = p.PA1;
24
25 let mut vrefint = adc.enable_vref(&mut Delay);
26 let vrefint_sample = adc.read(&mut vrefint).await;
27 let convert_to_millivolts = |sample| {
28 // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
29 // 6.3.3 Embedded internal reference voltage
30 const VREFINT_MV: u32 = 1224; // mV
31
32 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
33 };
34
35 loop {
36 let v = adc.read(&mut pin).await;
37 info!("--> {} - {} mV", v, convert_to_millivolts(v));
38 Timer::after_millis(100).await;
39 }
40}
diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs
index f517fce04..4945da7ce 100644
--- a/examples/stm32l0/src/bin/button_exti.rs
+++ b/examples/stm32l0/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use embassy_stm32::Config; 8use embassy_stm32::Config;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -13,8 +13,7 @@ async fn main(_spawner: Spawner) {
13 let config = Config::default(); 13 let config = Config::default();
14 let p = embassy_stm32::init(config); 14 let p = embassy_stm32::init(config);
15 15
16 let button = Input::new(p.PB2, Pull::Up); 16 let mut button = ExtiInput::new(p.PB2, p.EXTI2, Pull::Up);
17 let mut button = ExtiInput::new(button, p.EXTI2);
18 17
19 info!("Press the USER button..."); 18 info!("Press the USER button...");
20 19
diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs
index 7b1e84cbc..f738ea358 100644
--- a/examples/stm32l1/src/bin/usb_serial.rs
+++ b/examples/stm32l1/src/bin/usb_serial.rs
@@ -27,7 +27,7 @@ async fn main(_spawner: Spawner) {
27 mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz 27 mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz
28 div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) 28 div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3)
29 }); 29 });
30 config.rcc.mux = ClockSrc::PLL1_R; 30 config.rcc.sys = Sysclk::PLL1_R;
31 } 31 }
32 32
33 let p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index d01e9f1b3..a9f4604aa 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::adc::{Adc, Resolution}; 5use embassy_stm32::adc::{Adc, Resolution};
6use embassy_stm32::pac; 6use embassy_stm32::Config;
7use embassy_time::Delay; 7use embassy_time::Delay;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -11,16 +11,16 @@ use {defmt_rtt as _, panic_probe as _};
11fn main() -> ! { 11fn main() -> ! {
12 info!("Hello World!"); 12 info!("Hello World!");
13 13
14 pac::RCC.ccipr().modify(|w| { 14 let mut config = Config::default();
15 w.set_adcsel(pac::rcc::vals::Adcsel::SYS); 15 {
16 }); 16 use embassy_stm32::rcc::*;
17 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); 17 config.rcc.mux.adcsel = mux::Adcsel::SYS;
18 18 }
19 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(config);
20 20
21 let mut adc = Adc::new(p.ADC1, &mut Delay); 21 let mut adc = Adc::new(p.ADC1, &mut Delay);
22 //adc.enable_vref(); 22 //adc.enable_vref();
23 adc.set_resolution(Resolution::EightBit); 23 adc.set_resolution(Resolution::BITS8);
24 let mut channel = p.PC0; 24 let mut channel = p.PC0;
25 25
26 loop { 26 loop {
diff --git a/examples/stm32l4/src/bin/button_exti.rs b/examples/stm32l4/src/bin/button_exti.rs
index 1e970fdd6..34a08bbc6 100644
--- a/examples/stm32l4/src/bin/button_exti.rs
+++ b/examples/stm32l4/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Up); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index 8e5098557..f227812cd 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::Basic16bitInstance; 11use embassy_stm32::timer::low_level::BasicInstance;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -46,9 +46,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
46 dac.enable(); 46 dac.enable();
47 47
48 TIM6::enable_and_reset(); 48 TIM6::enable_and_reset();
49 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 49 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
50 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 50 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
51 TIM6::regs().cr1().modify(|w| { 51 TIM6::regs_basic().cr1().modify(|w| {
52 w.set_opm(false); 52 w.set_opm(false);
53 w.set_cen(true); 53 w.set_cen(true);
54 }); 54 });
@@ -83,9 +83,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
83 } 83 }
84 84
85 TIM7::enable_and_reset(); 85 TIM7::enable_and_reset();
86 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 86 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
87 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 87 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
88 TIM7::regs().cr1().modify(|w| { 88 TIM7::regs_basic().cr1().modify(|w| {
89 w.set_opm(false); 89 w.set_opm(false);
90 w.set_cen(true); 90 w.set_cen(true);
91 }); 91 });
diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs
index 638b3e9e4..14d0e3c1e 100644
--- a/examples/stm32l4/src/bin/rng.rs
+++ b/examples/stm32l4/src/bin/rng.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource}; 6use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk};
7use embassy_stm32::rng::Rng; 7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs {
15#[embassy_executor::main] 15#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.mux = ClockSrc::PLL1_R; 18 config.rcc.sys = Sysclk::PLL1_R;
19 config.rcc.hsi = true; 19 config.rcc.hsi = true;
20 config.rcc.pll = Some(Pll { 20 config.rcc.pll = Some(Pll {
21 source: PllSource::HSI, 21 source: PllSource::HSI,
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
index 526620bfb..f554f0f78 100644
--- a/examples/stm32l4/src/bin/rtc.rs
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) {
15 let mut config = Config::default(); 15 let mut config = Config::default();
16 { 16 {
17 use embassy_stm32::rcc::*; 17 use embassy_stm32::rcc::*;
18 config.rcc.mux = ClockSrc::PLL1_R; 18 config.rcc.sys = Sysclk::PLL1_R;
19 config.rcc.hse = Some(Hse { 19 config.rcc.hse = Some(Hse {
20 freq: Hertz::mhz(8), 20 freq: Hertz::mhz(8),
21 mode: HseMode::Oscillator, 21 mode: HseMode::Oscillator,
@@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
40 .unwrap(); 40 .unwrap();
41 41
42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
43 info!("Got RTC! {:?}", now.timestamp()); 43 info!("Got RTC! {:?}", now.and_utc().timestamp());
44 44
45 rtc.set_datetime(now.into()).expect("datetime not set"); 45 rtc.set_datetime(now.into()).expect("datetime not set");
46 46
@@ -48,5 +48,5 @@ async fn main(_spawner: Spawner) {
48 Timer::after_millis(20000).await; 48 Timer::after_millis(20000).await;
49 49
50 let then: NaiveDateTime = rtc.now().unwrap().into(); 50 let then: NaiveDateTime = rtc.now().unwrap().into();
51 info!("Got RTC! {:?}", then.timestamp()); 51 info!("Got RTC! {:?}", then.and_utc().timestamp());
52} 52}
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 5b4cdfe5e..32bfab6eb 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -58,9 +58,9 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
58const HTTP_LISTEN_PORT: u16 = 80; 58const HTTP_LISTEN_PORT: u16 = 80;
59 59
60pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; 60pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>;
61pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static, peripherals::PB12>, Delay>; 61pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
62pub type SpeInt = exti::ExtiInput<'static, peripherals::PB11>; 62pub type SpeInt = exti::ExtiInput<'static>;
63pub type SpeRst = Output<'static, peripherals::PC7>; 63pub type SpeRst = Output<'static>;
64pub type Adin1110T = ADIN1110<SpeSpiCs>; 64pub type Adin1110T = ADIN1110<SpeSpiCs>;
65pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; 65pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>;
66 66
@@ -75,7 +75,7 @@ async fn main(spawner: Spawner) {
75 use embassy_stm32::rcc::*; 75 use embassy_stm32::rcc::*;
76 // 80Mhz clock (Source: 8 / SrcDiv: 1 * PllMul 20 / ClkDiv 2) 76 // 80Mhz clock (Source: 8 / SrcDiv: 1 * PllMul 20 / ClkDiv 2)
77 // 80MHz highest frequency for flash 0 wait. 77 // 80MHz highest frequency for flash 0 wait.
78 config.rcc.mux = ClockSrc::PLL1_R; 78 config.rcc.sys = Sysclk::PLL1_R;
79 config.rcc.hse = Some(Hse { 79 config.rcc.hse = Some(Hse {
80 freq: Hertz::mhz(8), 80 freq: Hertz::mhz(8),
81 mode: HseMode::Oscillator, 81 mode: HseMode::Oscillator,
@@ -134,8 +134,7 @@ async fn main(spawner: Spawner) {
134 let spe_cfg1 = Input::new(dp.PC9, Pull::None); 134 let spe_cfg1 = Input::new(dp.PC9, Pull::None);
135 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);
136 136
137 let spe_int = Input::new(dp.PB11, Pull::None); 137 let spe_int = exti::ExtiInput::new(dp.PB11, dp.EXTI11, Pull::None);
138 let spe_int = exti::ExtiInput::new(spe_int, dp.EXTI11);
139 138
140 let spe_spi_cs_n = Output::new(dp.PB12, Level::High, Speed::High); 139 let spe_spi_cs_n = Output::new(dp.PB12, Level::High, Speed::High);
141 let spe_spi_sclk = dp.PB13; 140 let spe_spi_sclk = dp.PB13;
@@ -298,7 +297,7 @@ async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net:
298} 297}
299 298
300#[embassy_executor::task] 299#[embassy_executor::task]
301async fn heartbeat_led(mut led: Output<'static, peripherals::PE6>) { 300async fn heartbeat_led(mut led: Output<'static>) {
302 let mut tmr = Ticker::every(Duration::from_hz(3)); 301 let mut tmr = Ticker::every(Duration::from_hz(3));
303 loop { 302 loop {
304 led.toggle(); 303 led.toggle();
@@ -308,7 +307,7 @@ async fn heartbeat_led(mut led: Output<'static, peripherals::PE6>) {
308 307
309// ADT7422 308// ADT7422
310#[embassy_executor::task] 309#[embassy_executor::task]
311async fn temp_task(temp_dev_i2c: TempSensI2c, mut led: Output<'static, peripherals::PG15>) -> ! { 310async fn temp_task(temp_dev_i2c: TempSensI2c, mut led: Output<'static>) -> ! {
312 let mut tmr = Ticker::every(Duration::from_hz(1)); 311 let mut tmr = Ticker::every(Duration::from_hz(1));
313 let mut temp_sens = ADT7422::new(temp_dev_i2c, 0x48).unwrap(); 312 let mut temp_sens = ADT7422::new(temp_dev_i2c, 0x48).unwrap();
314 313
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 8cc9a7aed..9247e56a1 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 23
24 let mut config = Config::default(); 24 let mut config = Config::default();
25 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB 25 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
26 config.rcc.mux = ClockSrc::PLL1_R; 26 config.rcc.sys = Sysclk::PLL1_R;
27 config.rcc.hsi = true; 27 config.rcc.hsi = true;
28 config.rcc.pll = Some(Pll { 28 config.rcc.pll = Some(Pll {
29 source: PllSource::HSI, 29 source: PllSource::HSI,
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 0c6beb72c..5bcee178f 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -13,7 +13,7 @@ embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["de
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.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16usbd-hid = "0.6.0" 16usbd-hid = "0.7.0"
17 17
18defmt = "0.3" 18defmt = "0.3"
19defmt-rtt = "0.4" 19defmt-rtt = "0.4"
diff --git a/examples/stm32l5/src/bin/button_exti.rs b/examples/stm32l5/src/bin/button_exti.rs
index 91d0ccc2e..e6639d22b 100644
--- a/examples/stm32l5/src/bin/button_exti.rs
+++ b/examples/stm32l5/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Down); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs
index 50da6c946..0a644e73d 100644
--- a/examples/stm32l5/src/bin/rng.rs
+++ b/examples/stm32l5/src/bin/rng.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllRDiv, PllSource}; 6use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, PllSource, Sysclk};
7use embassy_stm32::rng::Rng; 7use embassy_stm32::rng::Rng;
8use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, rng, Config};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs {
16async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
17 let mut config = Config::default(); 17 let mut config = Config::default();
18 config.rcc.hsi = true; 18 config.rcc.hsi = true;
19 config.rcc.mux = ClockSrc::PLL1_R; 19 config.rcc.sys = Sysclk::PLL1_R;
20 config.rcc.pll = Some(Pll { 20 config.rcc.pll = Some(Pll {
21 // 64Mhz clock (16 / 1 * 8 / 2) 21 // 64Mhz clock (16 / 1 * 8 / 2)
22 source: PllSource::HSI, 22 source: PllSource::HSI,
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 88060b6b0..f6d8b16d0 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -45,7 +45,7 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
45async fn main(spawner: Spawner) { 45async fn main(spawner: Spawner) {
46 let mut config = Config::default(); 46 let mut config = Config::default();
47 config.rcc.hsi = true; 47 config.rcc.hsi = true;
48 config.rcc.mux = ClockSrc::PLL1_R; 48 config.rcc.sys = Sysclk::PLL1_R;
49 config.rcc.pll = Some(Pll { 49 config.rcc.pll = Some(Pll {
50 // 80Mhz clock (16 / 1 * 10 / 2) 50 // 80Mhz clock (16 / 1 * 10 / 2)
51 source: PllSource::HSI, 51 source: PllSource::HSI,
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index 7c8a8ebfb..c51ed96e0 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs {
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 23 let mut config = Config::default();
24 config.rcc.hsi = true; 24 config.rcc.hsi = true;
25 config.rcc.mux = ClockSrc::PLL1_R; 25 config.rcc.sys = Sysclk::PLL1_R;
26 config.rcc.pll = Some(Pll { 26 config.rcc.pll = Some(Pll {
27 // 80Mhz clock (16 / 1 * 10 / 2) 27 // 80Mhz clock (16 / 1 * 10 / 2)
28 source: PllSource::HSI, 28 source: PllSource::HSI,
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 75053ce4b..87987f2ce 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs {
20async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 21 let mut config = Config::default();
22 config.rcc.hsi = true; 22 config.rcc.hsi = true;
23 config.rcc.mux = ClockSrc::PLL1_R; 23 config.rcc.sys = Sysclk::PLL1_R;
24 config.rcc.pll = Some(Pll { 24 config.rcc.pll = Some(Pll {
25 // 80Mhz clock (16 / 1 * 10 / 2) 25 // 80Mhz clock (16 / 1 * 10 / 2)
26 source: PllSource::HSI, 26 source: PllSource::HSI,
diff --git a/examples/stm32u5/src/bin/flash.rs b/examples/stm32u5/src/bin/flash.rs
new file mode 100644
index 000000000..e4fd6bb9c
--- /dev/null
+++ b/examples/stm32u5/src/bin/flash.rs
@@ -0,0 +1,55 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::flash::Flash;
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello Flash!");
14
15 const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000.
16
17 // wait a bit before accessing the flash
18 Timer::after_millis(300).await;
19
20 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
21
22 info!("Reading...");
23 let mut buf = [0u8; 32];
24 unwrap!(f.blocking_read(ADDR, &mut buf));
25 info!("Read: {=[u8]:x}", buf);
26
27 info!("Erasing...");
28 unwrap!(f.blocking_erase(ADDR, ADDR + 256 * 1024));
29
30 info!("Reading...");
31 let mut buf = [0u8; 32];
32 unwrap!(f.blocking_read(ADDR, &mut buf));
33 info!("Read after erase: {=[u8]:x}", buf);
34
35 info!("Writing...");
36 unwrap!(f.blocking_write(
37 ADDR,
38 &[
39 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
40 30, 31, 32
41 ]
42 ));
43
44 info!("Reading...");
45 let mut buf = [0u8; 32];
46 unwrap!(f.blocking_read(ADDR, &mut buf));
47 info!("Read: {=[u8]:x}", buf);
48 assert_eq!(
49 &buf[..],
50 &[
51 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
52 30, 31, 32
53 ]
54 );
55}
diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs
new file mode 100644
index 000000000..e376c6bc8
--- /dev/null
+++ b/examples/stm32u5/src/bin/i2c.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::i2c::I2c;
8use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _};
11
12const HTS221_ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F;
14
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
17 I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default());
23 let mut i2c = I2c::new(
24 p.I2C2,
25 p.PH4,
26 p.PH5,
27 Irqs,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33
34 let mut data = [0u8; 1];
35 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data));
36
37 // HTS221 data sheet is here: https://www.st.com/resource/en/datasheet/hts221.pdf
38 // 7.1 WHO_AM_I command is x0F which expected response xBC.
39 info!("Whoami: 0x{:02x}", data[0]);
40 assert_eq!(0xBC, data[0]);
41}
diff --git a/examples/stm32u5/src/bin/rng.rs b/examples/stm32u5/src/bin/rng.rs
new file mode 100644
index 000000000..3a5bce097
--- /dev/null
+++ b/examples/stm32u5/src/bin/rng.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::rng::Rng;
7use embassy_stm32::{bind_interrupts, peripherals, rng};
8use {defmt_rtt as _, panic_probe as _};
9
10bind_interrupts!(struct Irqs {
11 RNG => rng::InterruptHandler<peripherals::RNG>;
12});
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default());
17
18 info!("Hello World!");
19
20 let mut rng = Rng::new(p.RNG, Irqs);
21
22 let mut buf = [0u8; 16];
23 unwrap!(rng.async_fill_bytes(&mut buf).await);
24 info!("random bytes: {:02x}", buf);
25}
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index dca34fd0e..61851e5a2 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::*;
8use embassy_stm32::usb_otg::{Driver, Instance}; 7use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -22,22 +21,28 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 21 info!("Hello World!");
23 22
24 let mut config = Config::default(); 23 let mut config = Config::default();
25 config.rcc.mux = ClockSrc::PLL1_R(PllConfig { 24 {
26 source: PllSource::HSI, 25 use embassy_stm32::rcc::*;
27 m: Pllm::DIV2, 26 config.rcc.hsi = true;
28 n: Plln::MUL10, 27 config.rcc.pll1 = Some(Pll {
29 p: Plldiv::DIV1, 28 source: PllSource::HSI, // 16 MHz
30 q: Plldiv::DIV1, 29 prediv: PllPreDiv::DIV1,
31 r: Plldiv::DIV1, 30 mul: PllMul::MUL10,
32 }); 31 divp: None,
33 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB 32 divq: None,
33 divr: Some(PllDiv::DIV1), // 160 MHz
34 });
35 config.rcc.sys = Sysclk::PLL1_R;
36 config.rcc.voltage_range = VoltageScale::RANGE1;
37 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
38 }
34 39
35 let p = embassy_stm32::init(config); 40 let p = embassy_stm32::init(config);
36 41
37 // Create the driver, from the HAL. 42 // Create the driver, from the HAL.
38 let mut ep_out_buffer = [0u8; 256]; 43 let mut ep_out_buffer = [0u8; 256];
39 let mut config = embassy_stm32::usb_otg::Config::default(); 44 let mut config = embassy_stm32::usb_otg::Config::default();
40 config.vbus_detection = true; 45 config.vbus_detection = false;
41 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 46 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
42 47
43 // Create embassy-usb Config 48 // Create embassy-usb Config
diff --git a/examples/stm32wb/src/bin/button_exti.rs b/examples/stm32wb/src/bin/button_exti.rs
index d34dde3e9..2871fd55f 100644
--- a/examples/stm32wb/src/bin/button_exti.rs
+++ b/examples/stm32wb/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC4, Pull::Up); 15 let mut button = ExtiInput::new(p.PC4, p.EXTI4, Pull::Up);
16 let mut button = ExtiInput::new(button, p.EXTI4);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32wba/src/bin/button_exti.rs b/examples/stm32wba/src/bin/button_exti.rs
index 1e970fdd6..34a08bbc6 100644
--- a/examples/stm32wba/src/bin/button_exti.rs
+++ b/examples/stm32wba/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PC13, Pull::Up); 15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
16 let mut button = ExtiInput::new(button, p.EXTI13);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs
index e6ad4b80b..27d5330bd 100644
--- a/examples/stm32wl/src/bin/button_exti.rs
+++ b/examples/stm32wl/src/bin/button_exti.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::{Input, Pull}; 7use embassy_stm32::gpio::Pull;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -12,8 +12,7 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 let button = Input::new(p.PA0, Pull::Up); 15 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up);
16 let mut button = ExtiInput::new(button, p.EXTI0);
17 16
18 info!("Press the USER button..."); 17 info!("Press the USER button...");
19 18
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index 3610392be..8e9fe02b2 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 mode: HseMode::Bypass, 22 mode: HseMode::Bypass,
23 prescaler: HsePrescaler::DIV1, 23 prescaler: HsePrescaler::DIV1,
24 }); 24 });
25 config.rcc.mux = ClockSrc::PLL1_R; 25 config.rcc.sys = Sysclk::PLL1_R;
26 config.rcc.pll = Some(Pll { 26 config.rcc.pll = Some(Pll {
27 source: PllSource::HSE, 27 source: PllSource::HSE,
28 prediv: PllPreDiv::DIV2, 28 prediv: PllPreDiv::DIV2,
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index 4738d5770..cf7d6d220 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) {
21 mode: HseMode::Bypass, 21 mode: HseMode::Bypass,
22 prescaler: HsePrescaler::DIV1, 22 prescaler: HsePrescaler::DIV1,
23 }); 23 });
24 config.rcc.mux = ClockSrc::PLL1_R; 24 config.rcc.sys = Sysclk::PLL1_R;
25 config.rcc.pll = Some(Pll { 25 config.rcc.pll = Some(Pll {
26 source: PllSource::HSE, 26 source: PllSource::HSE,
27 prediv: PllPreDiv::DIV2, 27 prediv: PllPreDiv::DIV2,
@@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
40 .unwrap(); 40 .unwrap();
41 41
42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 42 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
43 info!("Got RTC! {:?}", now.timestamp()); 43 info!("Got RTC! {:?}", now.and_utc().timestamp());
44 44
45 rtc.set_datetime(now.into()).expect("datetime not set"); 45 rtc.set_datetime(now.into()).expect("datetime not set");
46 46
@@ -48,5 +48,5 @@ async fn main(_spawner: Spawner) {
48 Timer::after_millis(20000).await; 48 Timer::after_millis(20000).await;
49 49
50 let then: NaiveDateTime = rtc.now().unwrap().into(); 50 let then: NaiveDateTime = rtc.now().unwrap().into();
51 info!("Got RTC! {:?}", then.timestamp()); 51 info!("Got RTC! {:?}", then.and_utc().timestamp());
52} 52}
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
index 8e545834c..3637243a0 100644
--- a/examples/stm32wl/src/bin/uart_async.rs
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -20,7 +20,7 @@ but can be surely changed for your needs.
20#[embassy_executor::main] 20#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
22 let mut config = embassy_stm32::Config::default(); 22 let mut config = embassy_stm32::Config::default();
23 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; 23 config.rcc.sys = embassy_stm32::rcc::Sysclk::HSE;
24 let p = embassy_stm32::init(config); 24 let p = embassy_stm32::init(config);
25 25
26 defmt::info!("Starting system"); 26 defmt::info!("Starting system");
diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs
deleted file mode 100644
index 354d787b4..000000000
--- a/tests/nrf/src/bin/buffered_uart.rs
+++ /dev/null
@@ -1,78 +0,0 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf52840-dk");
4
5use defmt::{assert_eq, *};
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_nrf::buffered_uarte::{self, BufferedUarte};
9use embassy_nrf::{bind_interrupts, peripherals, uarte};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19 let mut config = uarte::Config::default();
20 config.parity = uarte::Parity::EXCLUDED;
21 config.baudrate = uarte::Baudrate::BAUD1M;
22
23 let mut tx_buffer = [0u8; 1024];
24 let mut rx_buffer = [0u8; 1024];
25
26 let mut u = BufferedUarte::new(
27 p.UARTE0,
28 p.TIMER0,
29 p.PPI_CH0,
30 p.PPI_CH1,
31 p.PPI_GROUP0,
32 Irqs,
33 p.P1_03,
34 p.P1_02,
35 config.clone(),
36 &mut rx_buffer,
37 &mut tx_buffer,
38 );
39
40 info!("uarte initialized!");
41
42 let (mut rx, mut tx) = u.split();
43
44 const COUNT: usize = 40_000;
45
46 let tx_fut = async {
47 let mut tx_buf = [0; 215];
48 let mut i = 0;
49 while i < COUNT {
50 let n = tx_buf.len().min(COUNT - i);
51 let tx_buf = &mut tx_buf[..n];
52 for (j, b) in tx_buf.iter_mut().enumerate() {
53 *b = (i + j) as u8;
54 }
55 let n = unwrap!(tx.write(tx_buf).await);
56 i += n;
57 }
58 };
59 let rx_fut = async {
60 let mut i = 0;
61 while i < COUNT {
62 let buf = unwrap!(rx.fill_buf().await);
63
64 for &b in buf {
65 assert_eq!(b, i as u8);
66 i = i + 1;
67 }
68
69 let n = buf.len();
70 rx.consume(n);
71 }
72 };
73
74 join(rx_fut, tx_fut).await;
75
76 info!("Test OK");
77 cortex_m::asm::bkpt();
78}
diff --git a/tests/nrf51422/.cargo/config.toml b/tests/nrf51422/.cargo/config.toml
new file mode 100644
index 000000000..634805633
--- /dev/null
+++ b/tests/nrf51422/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "teleprobe local run --chip nRF51422_xxAA --elf"
3runner = "teleprobe client run"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace,embassy_hal_internal=debug"
diff --git a/tests/nrf51422/Cargo.toml b/tests/nrf51422/Cargo.toml
new file mode 100644
index 000000000..07236987b
--- /dev/null
+++ b/tests/nrf51422/Cargo.toml
@@ -0,0 +1,23 @@
1[package]
2edition = "2021"
3name = "embassy-nrf51-tests"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8teleprobe-meta = "1"
9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt", ] }
12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-128", "integrated-timers"] }
13embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
14embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "gpiote"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
16embedded-hal-async = { version = "1.0" }
17
18defmt = "0.3"
19defmt-rtt = "0.4"
20
21cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/tests/nrf51422/build.rs b/tests/nrf51422/build.rs
new file mode 100644
index 000000000..13ebbe4ee
--- /dev/null
+++ b/tests/nrf51422/build.rs
@@ -0,0 +1,17 @@
1use std::error::Error;
2use std::path::PathBuf;
3use std::{env, fs};
4
5fn main() -> Result<(), Box<dyn Error>> {
6 let out = PathBuf::from(env::var("OUT_DIR").unwrap());
7 fs::write(out.join("memory.x"), include_bytes!("memory.x")).unwrap();
8 println!("cargo:rustc-link-search={}", out.display());
9 println!("cargo:rerun-if-changed=memory.x");
10
11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
15
16 Ok(())
17}
diff --git a/tests/nrf51422/memory.x b/tests/nrf51422/memory.x
new file mode 100644
index 000000000..a5881e66f
--- /dev/null
+++ b/tests/nrf51422/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 128K
4 RAM : ORIGIN = 0x20000000, LENGTH = 16K
5}
diff --git a/tests/nrf51422/src/bin/gpio.rs b/tests/nrf51422/src/bin/gpio.rs
new file mode 100644
index 000000000..6d5a87d0a
--- /dev/null
+++ b/tests/nrf51422/src/bin/gpio.rs
@@ -0,0 +1,28 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf51-dk");
4
5use defmt::{assert, info};
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14
15 let input = Input::new(p.P0_13, Pull::Up);
16 let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard);
17
18 output.set_low();
19 Timer::after_millis(10).await;
20 assert!(input.is_low());
21
22 output.set_high();
23 Timer::after_millis(10).await;
24 assert!(input.is_high());
25
26 info!("Test OK");
27 cortex_m::asm::bkpt();
28}
diff --git a/tests/nrf51422/src/bin/gpiote.rs b/tests/nrf51422/src/bin/gpiote.rs
new file mode 100644
index 000000000..330fe993e
--- /dev/null
+++ b/tests/nrf51422/src/bin/gpiote.rs
@@ -0,0 +1,47 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf51-dk");
4
5use defmt::{assert, info};
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
9use embassy_time::{Duration, Instant, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default());
15
16 let mut input = Input::new(p.P0_13, Pull::Up);
17 let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard);
18
19 let fut1 = async {
20 Timer::after_millis(100).await;
21 output.set_high();
22 };
23 let fut2 = async {
24 let start = Instant::now();
25 input.wait_for_high().await;
26 let dur = Instant::now() - start;
27 assert!((Duration::from_millis(90)..Duration::from_millis(110)).contains(&dur));
28 };
29
30 join(fut1, fut2).await;
31
32 let fut1 = async {
33 Timer::after_millis(100).await;
34 output.set_low();
35 };
36 let fut2 = async {
37 let start = Instant::now();
38 input.wait_for_low().await;
39 let dur = Instant::now() - start;
40 assert!((Duration::from_millis(90)..Duration::from_millis(110)).contains(&dur));
41 };
42
43 join(fut1, fut2).await;
44
45 info!("Test OK");
46 cortex_m::asm::bkpt();
47}
diff --git a/tests/nrf51422/src/bin/timer.rs b/tests/nrf51422/src/bin/timer.rs
new file mode 100644
index 000000000..cf9ea41a8
--- /dev/null
+++ b/tests/nrf51422/src/bin/timer.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf51-dk");
4
5use defmt::{assert, info};
6use embassy_executor::Spawner;
7use embassy_time::{Instant, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let _p = embassy_nrf::init(Default::default());
13 info!("Hello World!");
14
15 let start = Instant::now();
16 Timer::after_millis(100).await;
17 let end = Instant::now();
18 let ms = (end - start).as_millis();
19 info!("slept for {} ms", ms);
20 assert!(ms >= 99);
21
22 info!("Test OK");
23 cortex_m::asm::bkpt();
24}
diff --git a/tests/nrf/.cargo/config.toml b/tests/nrf52840/.cargo/config.toml
index 9d6b0313a..9d6b0313a 100644
--- a/tests/nrf/.cargo/config.toml
+++ b/tests/nrf52840/.cargo/config.toml
diff --git a/tests/nrf/Cargo.toml b/tests/nrf52840/Cargo.toml
index 84ca99f1f..84ca99f1f 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf52840/Cargo.toml
diff --git a/tests/nrf/build.rs b/tests/nrf52840/build.rs
index 71c82a70f..71c82a70f 100644
--- a/tests/nrf/build.rs
+++ b/tests/nrf52840/build.rs
diff --git a/tests/nrf/memory.x b/tests/nrf52840/memory.x
index 58900a7bd..58900a7bd 100644
--- a/tests/nrf/memory.x
+++ b/tests/nrf52840/memory.x
diff --git a/tests/nrf52840/src/bin/buffered_uart.rs b/tests/nrf52840/src/bin/buffered_uart.rs
new file mode 100644
index 000000000..a01d66d85
--- /dev/null
+++ b/tests/nrf52840/src/bin/buffered_uart.rs
@@ -0,0 +1,81 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf52840-dk");
4
5use defmt::{assert_eq, *};
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_nrf::buffered_uarte::{self, BufferedUarte};
9use embassy_nrf::{bind_interrupts, peripherals, uarte};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut p = embassy_nrf::init(Default::default());
19 let mut config = uarte::Config::default();
20 config.parity = uarte::Parity::EXCLUDED;
21 config.baudrate = uarte::Baudrate::BAUD1M;
22
23 let mut tx_buffer = [0u8; 1024];
24 let mut rx_buffer = [0u8; 1024];
25
26 // test teardown + recreate of the buffereduarte works fine.
27 for _ in 0..2 {
28 let u = BufferedUarte::new(
29 &mut p.UARTE0,
30 &mut p.TIMER0,
31 &mut p.PPI_CH0,
32 &mut p.PPI_CH1,
33 &mut p.PPI_GROUP0,
34 Irqs,
35 &mut p.P1_03,
36 &mut p.P1_02,
37 config.clone(),
38 &mut rx_buffer,
39 &mut tx_buffer,
40 );
41
42 info!("uarte initialized!");
43
44 let (mut rx, mut tx) = u.split();
45
46 const COUNT: usize = 40_000;
47
48 let tx_fut = async {
49 let mut tx_buf = [0; 215];
50 let mut i = 0;
51 while i < COUNT {
52 let n = tx_buf.len().min(COUNT - i);
53 let tx_buf = &mut tx_buf[..n];
54 for (j, b) in tx_buf.iter_mut().enumerate() {
55 *b = (i + j) as u8;
56 }
57 let n = unwrap!(tx.write(tx_buf).await);
58 i += n;
59 }
60 };
61 let rx_fut = async {
62 let mut i = 0;
63 while i < COUNT {
64 let buf = unwrap!(rx.fill_buf().await);
65
66 for &b in buf {
67 assert_eq!(b, i as u8);
68 i = i + 1;
69 }
70
71 let n = buf.len();
72 rx.consume(n);
73 }
74 };
75
76 join(rx_fut, tx_fut).await;
77 }
78
79 info!("Test OK");
80 cortex_m::asm::bkpt();
81}
diff --git a/tests/nrf/src/bin/buffered_uart_full.rs b/tests/nrf52840/src/bin/buffered_uart_full.rs
index e59c75ba9..62edaed25 100644
--- a/tests/nrf/src/bin/buffered_uart_full.rs
+++ b/tests/nrf52840/src/bin/buffered_uart_full.rs
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 let mut tx_buffer = [0u8; 1024]; 23 let mut tx_buffer = [0u8; 1024];
24 let mut rx_buffer = [0u8; 1024]; 24 let mut rx_buffer = [0u8; 1024];
25 25
26 let mut u = BufferedUarte::new( 26 let u = BufferedUarte::new(
27 p.UARTE0, 27 p.UARTE0,
28 p.TIMER0, 28 p.TIMER0,
29 p.PPI_CH0, 29 p.PPI_CH0,
diff --git a/tests/nrf52840/src/bin/buffered_uart_halves.rs b/tests/nrf52840/src/bin/buffered_uart_halves.rs
new file mode 100644
index 000000000..54a9fef5b
--- /dev/null
+++ b/tests/nrf52840/src/bin/buffered_uart_halves.rs
@@ -0,0 +1,82 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"nrf52840-dk");
4
5use defmt::{assert_eq, *};
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_nrf::buffered_uarte::{self, BufferedUarteRx, BufferedUarteTx};
9use embassy_nrf::{bind_interrupts, peripherals, uarte};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
14 UARTE1 => buffered_uarte::InterruptHandler<peripherals::UARTE1>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let mut p = embassy_nrf::init(Default::default());
20 let mut config = uarte::Config::default();
21 config.parity = uarte::Parity::EXCLUDED;
22 config.baudrate = uarte::Baudrate::BAUD1M;
23
24 let mut tx_buffer = [0u8; 1024];
25 let mut rx_buffer = [0u8; 1024];
26
27 // test teardown + recreate of the buffereduarte works fine.
28 for _ in 0..2 {
29 const COUNT: usize = 40_000;
30
31 let mut tx = BufferedUarteTx::new(&mut p.UARTE1, Irqs, &mut p.P1_02, config.clone(), &mut tx_buffer);
32
33 let mut rx = BufferedUarteRx::new(
34 &mut p.UARTE0,
35 &mut p.TIMER0,
36 &mut p.PPI_CH0,
37 &mut p.PPI_CH1,
38 &mut p.PPI_GROUP0,
39 Irqs,
40 &mut p.P1_03,
41 config.clone(),
42 &mut rx_buffer,
43 );
44
45 let tx_fut = async {
46 info!("tx initialized!");
47
48 let mut tx_buf = [0; 215];
49 let mut i = 0;
50 while i < COUNT {
51 let n = tx_buf.len().min(COUNT - i);
52 let tx_buf = &mut tx_buf[..n];
53 for (j, b) in tx_buf.iter_mut().enumerate() {
54 *b = (i + j) as u8;
55 }
56 let n = unwrap!(tx.write(tx_buf).await);
57 i += n;
58 }
59 };
60 let rx_fut = async {
61 info!("rx initialized!");
62
63 let mut i = 0;
64 while i < COUNT {
65 let buf = unwrap!(rx.fill_buf().await);
66
67 for &b in buf {
68 assert_eq!(b, i as u8);
69 i = i + 1;
70 }
71
72 let n = buf.len();
73 rx.consume(n);
74 }
75 };
76
77 join(rx_fut, tx_fut).await;
78 }
79
80 info!("Test OK");
81 cortex_m::asm::bkpt();
82}
diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf52840/src/bin/buffered_uart_spam.rs
index 400c0df99..400c0df99 100644
--- a/tests/nrf/src/bin/buffered_uart_spam.rs
+++ b/tests/nrf52840/src/bin/buffered_uart_spam.rs
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs
index 7dc1941d7..33c2f4235 100644
--- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
+++ b/tests/nrf52840/src/bin/ethernet_enc28j60_perf.rs
@@ -21,10 +21,7 @@ bind_interrupts!(struct Irqs {
21 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; 21 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
22}); 22});
23 23
24type MyDriver = Enc28j60< 24type MyDriver = Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>;
25 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>,
26 Output<'static, peripherals::P0_13>,
27>;
28 25
29#[embassy_executor::task] 26#[embassy_executor::task]
30async fn net_task(stack: &'static Stack<MyDriver>) -> ! { 27async fn net_task(stack: &'static Stack<MyDriver>) -> ! {
diff --git a/tests/nrf/src/bin/timer.rs b/tests/nrf52840/src/bin/timer.rs
index 2a147e7ba..117947a94 100644
--- a/tests/nrf/src/bin/timer.rs
+++ b/tests/nrf52840/src/bin/timer.rs
@@ -18,7 +18,6 @@ async fn main(_spawner: Spawner) {
18 let ms = (end - start).as_millis(); 18 let ms = (end - start).as_millis();
19 info!("slept for {} ms", ms); 19 info!("slept for {} ms", ms);
20 assert!(ms >= 99); 20 assert!(ms >= 99);
21 assert!(ms < 110);
22 21
23 info!("Test OK"); 22 info!("Test OK");
24 cortex_m::asm::bkpt(); 23 cortex_m::asm::bkpt();
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs
index c96064f84..b83edddc4 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf52840/src/bin/wifi_esp_hosted_perf.rs
@@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120);
6use defmt::{info, unwrap}; 6use defmt::{info, unwrap};
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_net::{Config, Stack, StackResources}; 8use embassy_net::{Config, Stack, StackResources};
9use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; 9use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
10use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
11use embassy_nrf::spim::{self, Spim}; 11use embassy_nrf::spim::{self, Spim};
12use embassy_nrf::{bind_interrupts, peripherals}; 12use embassy_nrf::{bind_interrupts, peripherals};
@@ -28,9 +28,9 @@ const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
28async fn wifi_task( 28async fn wifi_task(
29 runner: hosted::Runner< 29 runner: hosted::Runner<
30 'static, 30 'static,
31 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>, Delay>, 31 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>,
32 Input<'static, AnyPin>, 32 Input<'static>,
33 Output<'static, peripherals::P1_05>, 33 Output<'static>,
34 >, 34 >,
35) -> ! { 35) -> ! {
36 runner.run().await 36 runner.run().await
@@ -53,8 +53,8 @@ async fn main(spawner: Spawner) {
53 let sck = p.P0_29; 53 let sck = p.P0_29;
54 let mosi = p.P0_30; 54 let mosi = p.P0_30;
55 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); 55 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
56 let handshake = Input::new(p.P1_01.degrade(), Pull::Up); 56 let handshake = Input::new(p.P1_01, Pull::Up);
57 let ready = Input::new(p.P1_04.degrade(), Pull::None); 57 let ready = Input::new(p.P1_04, Pull::None);
58 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); 58 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
59 59
60 let mut config = spim::Config::default(); 60 let mut config = spim::Config::default();
diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml
index 40b5d7000..de7bb0e56 100644
--- a/tests/rp/.cargo/config.toml
+++ b/tests/rp/.cargo/config.toml
@@ -10,7 +10,7 @@ runner = "teleprobe client run"
10 10
11rustflags = [ 11rustflags = [
12 # Code-size optimizations. 12 # Code-size optimizations.
13 "-Z", "trap-unreachable=no", 13 #"-Z", "trap-unreachable=no",
14 "-C", "inline-threshold=5", 14 "-C", "inline-threshold=5",
15 "-C", "no-vectorize-loops", 15 "-C", "no-vectorize-loops",
16] 16]
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 46e1e9a5f..e67f2117d 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -14,6 +14,7 @@ embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal/"}
17cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } 18cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
18cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } 19cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
19perf-client = { path = "../perf-client" } 20perf-client = { path = "../perf-client" }
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index a1b2946e6..b46ae670a 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -7,7 +7,7 @@ use defmt::{panic, *};
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_net::{Config, Stack, StackResources}; 8use embassy_net::{Config, Stack, StackResources};
9use embassy_rp::gpio::{Level, Output}; 9use embassy_rp::gpio::{Level, Output};
10use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; 10use embassy_rp::peripherals::{DMA_CH0, PIO0};
11use embassy_rp::pio::{InterruptHandler, Pio}; 11use embassy_rp::pio::{InterruptHandler, Pio};
12use embassy_rp::{bind_interrupts, rom_data}; 12use embassy_rp::{bind_interrupts, rom_data};
13use static_cell::StaticCell; 13use static_cell::StaticCell;
@@ -24,9 +24,7 @@ const WIFI_NETWORK: &str = "EmbassyTest";
24const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; 24const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
25 25
26#[embassy_executor::task] 26#[embassy_executor::task]
27async fn wifi_task( 27async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
28 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
29) -> ! {
30 runner.run().await 28 runner.run().await
31} 29}
32 30
diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs
index 8c9089d0e..5d5547773 100644
--- a/tests/rp/src/bin/ethernet_w5100s_perf.rs
+++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs
@@ -10,7 +10,7 @@ use embassy_net_wiznet::chip::W5100S;
10use embassy_net_wiznet::*; 10use embassy_net_wiznet::*;
11use embassy_rp::clocks::RoscRng; 11use embassy_rp::clocks::RoscRng;
12use embassy_rp::gpio::{Input, Level, Output, Pull}; 12use embassy_rp::gpio::{Input, Level, Output, Pull};
13use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 13use embassy_rp::peripherals::SPI0;
14use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 14use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
15use embassy_time::Delay; 15use embassy_time::Delay;
16use embedded_hal_bus::spi::ExclusiveDevice; 16use embedded_hal_bus::spi::ExclusiveDevice;
@@ -23,9 +23,9 @@ async fn ethernet_task(
23 runner: Runner< 23 runner: Runner<
24 'static, 24 'static,
25 W5100S, 25 W5100S,
26 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 26 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static>, Delay>,
27 Input<'static, PIN_21>, 27 Input<'static>,
28 Output<'static, PIN_20>, 28 Output<'static>,
29 >, 29 >,
30) -> ! { 30) -> ! {
31 runner.run().await 31 runner.run().await
diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs
index 77d628cf6..153b37999 100644
--- a/tests/rp/src/bin/i2c.rs
+++ b/tests/rp/src/bin/i2c.rs
@@ -3,7 +3,10 @@
3teleprobe_meta::target!(b"rpi-pico"); 3teleprobe_meta::target!(b"rpi-pico");
4 4
5use defmt::{assert_eq, info, panic, unwrap}; 5use defmt::{assert_eq, info, panic, unwrap};
6use embassy_executor::Executor; 6use embassy_embedded_hal::SetConfig;
7use embassy_executor::{Executor, Spawner};
8use embassy_rp::clocks::{PllConfig, XoscConfig};
9use embassy_rp::config::Config as rpConfig;
7use embassy_rp::multicore::{spawn_core1, Stack}; 10use embassy_rp::multicore::{spawn_core1, Stack};
8use embassy_rp::peripherals::{I2C0, I2C1}; 11use embassy_rp::peripherals::{I2C0, I2C1};
9use embassy_rp::{bind_interrupts, i2c, i2c_slave}; 12use embassy_rp::{bind_interrupts, i2c, i2c_slave};
@@ -13,7 +16,6 @@ use static_cell::StaticCell;
13use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _};
14 17
15static mut CORE1_STACK: Stack<1024> = Stack::new(); 18static mut CORE1_STACK: Stack<1024> = Stack::new();
16static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
17static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); 19static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
18 20
19use crate::i2c::AbortReason; 21use crate::i2c::AbortReason;
@@ -44,10 +46,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
44 Ok(x) => match x { 46 Ok(x) => match x {
45 i2c_slave::ReadStatus::Done => break, 47 i2c_slave::ReadStatus::Done => break,
46 i2c_slave::ReadStatus::NeedMoreBytes => count += 1, 48 i2c_slave::ReadStatus::NeedMoreBytes => count += 1,
47 i2c_slave::ReadStatus::LeftoverBytes(x) => { 49 i2c_slave::ReadStatus::LeftoverBytes(x) => panic!("tried to write {} extra bytes", x),
48 info!("tried to write {} extra bytes", x);
49 break;
50 }
51 }, 50 },
52 Err(e) => match e { 51 Err(e) => match e {
53 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), 52 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
@@ -80,7 +79,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
80 _ => panic!("Invalid write length {}", len), 79 _ => panic!("Invalid write length {}", len),
81 }, 80 },
82 Ok(i2c_slave::Command::WriteRead(len)) => { 81 Ok(i2c_slave::Command::WriteRead(len)) => {
83 info!("device recieved write read: {:x}", buf[..len]); 82 info!("device received write read: {:x}", buf[..len]);
84 match buf[0] { 83 match buf[0] {
85 0xC2 => { 84 0xC2 => {
86 let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4]; 85 let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4];
@@ -92,6 +91,8 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
92 resp_buff[i] = i as u8; 91 resp_buff[i] = i as u8;
93 } 92 }
94 dev.respond_to_read(&resp_buff).await.unwrap(); 93 dev.respond_to_read(&resp_buff).await.unwrap();
94 // reset count for next round of tests
95 count = 0xD0;
95 } 96 }
96 x => panic!("Invalid Write Read {:x}", x), 97 x => panic!("Invalid Write Read {:x}", x),
97 } 98 }
@@ -104,8 +105,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
104 } 105 }
105} 106}
106 107
107#[embassy_executor::task] 108async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) {
108async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
109 info!("Device start"); 109 info!("Device start");
110 110
111 { 111 {
@@ -179,33 +179,55 @@ async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
179 info!("large write_read - OK") 179 info!("large write_read - OK")
180 } 180 }
181 181
182 info!("Test OK"); 182 #[embassy_executor::main]
183 cortex_m::asm::bkpt(); 183 async fn main(_core0_spawner: Spawner) {
184} 184 let mut config = rpConfig::default();
185 185 // Configure clk_sys to 48MHz to support 1kHz scl.
186#[cortex_m_rt::entry] 186 // In theory it can go lower, but we won't bother to test below 1kHz.
187fn main() -> ! { 187 config.clocks.xosc = Some(XoscConfig {
188 let p = embassy_rp::init(Default::default()); 188 hz: 12_000_000,
189 info!("Hello World!"); 189 delay_multiplier: 128,
190 190 sys_pll: Some(PllConfig {
191 let d_sda = p.PIN_19; 191 refdiv: 1,
192 let d_scl = p.PIN_18; 192 fbdiv: 120,
193 let mut config = i2c_slave::Config::default(); 193 post_div1: 6,
194 config.addr = DEV_ADDR as u16; 194 post_div2: 5,
195 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); 195 }),
196 196 usb_pll: Some(PllConfig {
197 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { 197 refdiv: 1,
198 let executor1 = EXECUTOR1.init(Executor::new()); 198 fbdiv: 120,
199 executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); 199 post_div1: 6,
200 }); 200 post_div2: 5,
201 201 }),
202 let executor0 = EXECUTOR0.init(Executor::new()); 202 });
203 203
204 let c_sda = p.PIN_21; 204 let p = embassy_rp::init(config);
205 let c_scl = p.PIN_20; 205 info!("Hello World!");
206 let mut config = i2c::Config::default(); 206
207 config.frequency = 5_000; 207 let d_sda = p.PIN_19;
208 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); 208 let d_scl = p.PIN_18;
209 let mut config = i2c_slave::Config::default();
210 config.addr = DEV_ADDR as u16;
211 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config);
212
213 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
214 let executor1 = EXECUTOR1.init(Executor::new());
215 executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device))));
216 });
217
218 let c_sda = p.PIN_21;
219 let c_scl = p.PIN_20;
220 let mut controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, Default::default());
221
222 for freq in [1000, 100_000, 400_000, 1_000_000] {
223 info!("testing at {}hz", freq);
224 let mut config = i2c::Config::default();
225 config.frequency = freq;
226 controller.set_config(&config).unwrap();
227 controller_task(&mut controller).await;
228 }
209 229
210 executor0.run(|spawner| unwrap!(spawner.spawn(controller_task(controller)))); 230 info!("Test OK");
231 cortex_m::asm::bkpt();
232 }
211} 233}
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs
index f4d641175..6e6e5517b 100644
--- a/tests/rp/src/bin/uart.rs
+++ b/tests/rp/src/bin/uart.rs
@@ -21,7 +21,7 @@ fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Resu
21 Ok(buf) 21 Ok(buf)
22} 22}
23 23
24async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option<bool>) { 24async fn send(pin: &mut Output<'_>, v: u8, parity: Option<bool>) {
25 pin.set_low(); 25 pin.set_low();
26 Timer::after_millis(1).await; 26 Timer::after_millis(1).await;
27 for i in 0..8 { 27 for i in 0..8 {
@@ -116,7 +116,7 @@ async fn main(_spawner: Spawner) {
116 config.parity = Parity::ParityEven; 116 config.parity = Parity::ParityEven;
117 let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); 117 let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config);
118 118
119 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u8) { 119 async fn chr(pin: &mut Output<'_>, v: u8, parity: u8) {
120 send(pin, v, Some(parity != 0)).await; 120 send(pin, v, Some(parity != 0)).await;
121 } 121 }
122 122
@@ -142,7 +142,7 @@ async fn main(_spawner: Spawner) {
142 config.baudrate = 1000; 142 config.baudrate = 1000;
143 let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); 143 let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config);
144 144
145 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { 145 async fn chr(pin: &mut Output<'_>, v: u8, good: bool) {
146 if good { 146 if good {
147 send(pin, v, None).await; 147 send(pin, v, None).await;
148 } else { 148 } else {
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
index 14647e44a..d68c23cbd 100644
--- a/tests/rp/src/bin/uart_buffered.rs
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -36,7 +36,7 @@ async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) ->
36 } 36 }
37} 37}
38 38
39async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option<bool>) { 39async fn send(pin: &mut Output<'_>, v: u8, parity: Option<bool>) {
40 pin.set_low(); 40 pin.set_low();
41 Timer::after_millis(1).await; 41 Timer::after_millis(1).await;
42 for i in 0..8 { 42 for i in 0..8 {
@@ -161,7 +161,7 @@ async fn main(_spawner: Spawner) {
161 let rx_buf = &mut [0u8; 16]; 161 let rx_buf = &mut [0u8; 16];
162 let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); 162 let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config);
163 163
164 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) { 164 async fn chr(pin: &mut Output<'_>, v: u8, parity: u32) {
165 send(pin, v, Some(parity != 0)).await; 165 send(pin, v, Some(parity != 0)).await;
166 } 166 }
167 167
@@ -208,7 +208,7 @@ async fn main(_spawner: Spawner) {
208 let rx_buf = &mut [0u8; 16]; 208 let rx_buf = &mut [0u8; 16];
209 let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); 209 let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config);
210 210
211 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { 211 async fn chr(pin: &mut Output<'_>, v: u8, good: bool) {
212 if good { 212 if good {
213 send(pin, v, None).await; 213 send(pin, v, None).await;
214 } else { 214 } else {
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs
index 130d8599e..edc87175a 100644
--- a/tests/rp/src/bin/uart_dma.rs
+++ b/tests/rp/src/bin/uart_dma.rs
@@ -27,7 +27,7 @@ async fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Async>) -> R
27 Ok(buf) 27 Ok(buf)
28} 28}
29 29
30async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option<bool>) { 30async fn send(pin: &mut Output<'_>, v: u8, parity: Option<bool>) {
31 pin.set_low(); 31 pin.set_low();
32 Timer::after_millis(1).await; 32 Timer::after_millis(1).await;
33 for i in 0..8 { 33 for i in 0..8 {
@@ -160,7 +160,7 @@ async fn main(_spawner: Spawner) {
160 config.parity = Parity::ParityEven; 160 config.parity = Parity::ParityEven;
161 let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); 161 let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config);
162 162
163 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) { 163 async fn chr(pin: &mut Output<'_>, v: u8, parity: u32) {
164 send(pin, v, Some(parity != 0)).await; 164 send(pin, v, Some(parity != 0)).await;
165 } 165 }
166 166
@@ -205,7 +205,7 @@ async fn main(_spawner: Spawner) {
205 config.baudrate = 1000; 205 config.baudrate = 1000;
206 let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); 206 let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config);
207 207
208 async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { 208 async fn chr(pin: &mut Output<'_>, v: u8, good: bool) {
209 if good { 209 if good {
210 send(pin, v, None).await; 210 send(pin, v, None).await;
211 } else { 211 } else {
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml
index 2e3f055d4..528bd3451 100644
--- a/tests/stm32/.cargo/config.toml
+++ b/tests/stm32/.cargo/config.toml
@@ -1,6 +1,6 @@
1[unstable] 1[unstable]
2build-std = ["core"] 2#build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3#build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "teleprobe client run" 6runner = "teleprobe client run"
@@ -8,16 +8,16 @@ runner = "teleprobe client run"
8 8
9rustflags = [ 9rustflags = [
10 # Code-size optimizations. 10 # Code-size optimizations.
11 "-Z", "trap-unreachable=no", 11 #"-Z", "trap-unreachable=no",
12 "-C", "inline-threshold=5", 12 "-C", "inline-threshold=5",
13 "-C", "no-vectorize-loops", 13 "-C", "no-vectorize-loops",
14] 14]
15 15
16[build] 16[build]
17target = "thumbv6m-none-eabi" 17#target = "thumbv6m-none-eabi"
18#target = "thumbv7m-none-eabi" 18#target = "thumbv7m-none-eabi"
19#target = "thumbv7em-none-eabi" 19target = "thumbv7em-none-eabi"
20#target = "thumbv8m.main-none-eabihf" 20#target = "thumbv8m.main-none-eabihf"
21 21
22[env] 22[env]
23DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info" \ No newline at end of file 23DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info"
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index bf85f05d2..bfe003a11 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -14,29 +14,34 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not
14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] 14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] 15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"]
19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"] 20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"] 21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] 22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
23stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] 23stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] 24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng"] 25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"]
26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] 26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"]
27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng"] 27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"]
28stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng"] 28stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"]
29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] 29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"]
30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] 30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"]
31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng"] 31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"]
32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] 32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"]
33stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"]
34stm32h503rb = ["embassy-stm32/stm32h503rb", "rng"]
33 35
36cryp = []
37hash = []
34eth = ["embassy-executor/task-arena-size-16384"] 38eth = ["embassy-executor/task-arena-size-16384"]
35rng = [] 39rng = []
36sdmmc = [] 40sdmmc = []
37stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] 41stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"]
38chrono = ["embassy-stm32/chrono", "dep:chrono"] 42chrono = ["embassy-stm32/chrono", "dep:chrono"]
39can = [] 43can = []
44fdcan = []
40ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] 45ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
41mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] 46mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
42embassy-stm32-wpan = [] 47embassy-stm32-wpan = []
@@ -65,6 +70,7 @@ cortex-m-rt = "0.7.0"
65embedded-hal = "0.2.6" 70embedded-hal = "0.2.6"
66embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 71embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
67embedded-hal-async = { version = "1.0" } 72embedded-hal-async = { version = "1.0" }
73embedded-can = { version = "0.4" }
68micromath = "2.0.0" 74micromath = "2.0.0"
69panic-probe = { version = "0.3.0", features = ["print-defmt"] } 75panic-probe = { version = "0.3.0", features = ["print-defmt"] }
70rand_core = { version = "0.6", default-features = false } 76rand_core = { version = "0.6", default-features = false }
@@ -73,6 +79,9 @@ static_cell = "2"
73portable-atomic = { version = "1.5", features = [] } 79portable-atomic = { version = "1.5", features = [] }
74 80
75chrono = { version = "^0.4", default-features = false, optional = true} 81chrono = { version = "^0.4", default-features = false, optional = true}
82sha2 = { version = "0.10.8", default-features = false }
83hmac = "0.12.1"
84aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
76 85
77# BEGIN TESTS 86# BEGIN TESTS
78# Generated by gen_test.py. DO NOT EDIT. 87# Generated by gen_test.py. DO NOT EDIT.
@@ -82,6 +91,11 @@ path = "src/bin/can.rs"
82required-features = [ "can",] 91required-features = [ "can",]
83 92
84[[bin]] 93[[bin]]
94name = "cryp"
95path = "src/bin/cryp.rs"
96required-features = [ "cryp",]
97
98[[bin]]
85name = "dac" 99name = "dac"
86path = "src/bin/dac.rs" 100path = "src/bin/dac.rs"
87required-features = [ "dac",] 101required-features = [ "dac",]
@@ -97,11 +111,21 @@ path = "src/bin/eth.rs"
97required-features = [ "eth",] 111required-features = [ "eth",]
98 112
99[[bin]] 113[[bin]]
114name = "fdcan"
115path = "src/bin/fdcan.rs"
116required-features = [ "fdcan",]
117
118[[bin]]
100name = "gpio" 119name = "gpio"
101path = "src/bin/gpio.rs" 120path = "src/bin/gpio.rs"
102required-features = [] 121required-features = []
103 122
104[[bin]] 123[[bin]]
124name = "hash"
125path = "src/bin/hash.rs"
126required-features = [ "hash",]
127
128[[bin]]
105name = "rng" 129name = "rng"
106path = "src/bin/rng.rs" 130path = "src/bin/rng.rs"
107required-features = [ "rng",] 131required-features = [ "rng",]
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index f32a7b2f8..176adff62 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -16,6 +16,9 @@ fn main() -> Result<(), Box<dyn Error>> {
16 feature = "stm32l073rz", 16 feature = "stm32l073rz",
17 // wrong ram size in stm32-data 17 // wrong ram size in stm32-data
18 feature = "stm32wl55jc", 18 feature = "stm32wl55jc",
19 feature = "stm32u5a5zj",
20 // no VTOR, so interrupts can't work when running from RAM
21 feature = "stm32f091rc",
19 )) { 22 )) {
20 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 23 println!("cargo:rustc-link-arg-bins=-Tlink.x");
21 println!("cargo:rerun-if-changed=link.x"); 24 println!("cargo:rerun-if-changed=link.x");
diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs
new file mode 100644
index 000000000..f105abf26
--- /dev/null
+++ b/tests/stm32/src/bin/cryp.rs
@@ -0,0 +1,69 @@
1// required-features: cryp
2#![no_std]
3#![no_main]
4
5#[path = "../common.rs"]
6mod common;
7
8use aes_gcm::aead::heapless::Vec;
9use aes_gcm::aead::{AeadInPlace, KeyInit};
10use aes_gcm::Aes128Gcm;
11use common::*;
12use embassy_executor::Spawner;
13use embassy_stm32::cryp::*;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
19
20 const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567";
21 const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh";
22 const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1";
23 const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg";
24
25 let hw_cryp = Cryp::new(p.CRYP);
26 let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
27 let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
28 let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
29 let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
30
31 // Encrypt in hardware using AES-GCM 128-bit
32 let aes_gcm = AesGcm::new(&key, &iv);
33 let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt);
34 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false);
35 hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true);
36 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false);
37 hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true);
38 let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt);
39
40 // Decrypt in hardware using AES-GCM 128-bit
41 let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt);
42 hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false);
43 hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true);
44 hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true);
45 let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt);
46
47 info!("AES-GCM Ciphertext: {:?}", ciphertext);
48 info!("AES-GCM Plaintext: {:?}", plaintext);
49 defmt::assert!(PAYLOAD1 == &plaintext[..PAYLOAD1.len()]);
50 defmt::assert!(PAYLOAD2 == &plaintext[PAYLOAD1.len()..]);
51 defmt::assert!(encrypt_tag == decrypt_tag);
52
53 // Encrypt in software using AES-GCM 128-bit
54 let mut payload_vec: Vec<u8, { PAYLOAD1.len() + PAYLOAD2.len() + 16 }> = Vec::from_slice(&PAYLOAD1).unwrap();
55 payload_vec.extend_from_slice(&PAYLOAD2).unwrap();
56 let cipher = Aes128Gcm::new(&key.into());
57 let mut aad: Vec<u8, { AAD1.len() + AAD2.len() }> = Vec::from_slice(&AAD1).unwrap();
58 aad.extend_from_slice(&AAD2).unwrap();
59 let _ = cipher.encrypt_in_place(&iv.into(), &aad, &mut payload_vec);
60
61 defmt::assert!(ciphertext == payload_vec[0..ciphertext.len()]);
62 defmt::assert!(encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]);
63
64 // Decrypt in software using AES-GCM 128-bit
65 let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec);
66
67 info!("Test OK");
68 cortex_m::asm::bkpt();
69}
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
new file mode 100644
index 000000000..dd78d7fb3
--- /dev/null
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -0,0 +1,190 @@
1#![no_std]
2#![no_main]
3
4// required-features: fdcan
5
6#[path = "../common.rs"]
7mod common;
8use common::*;
9use defmt::assert;
10use embassy_executor::Spawner;
11use embassy_stm32::peripherals::*;
12use embassy_stm32::{bind_interrupts, can, Config};
13use embassy_time::{Duration, Instant};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
18 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
19});
20
21struct TestOptions {
22 config: Config,
23 max_latency: Duration,
24 second_fifo_working: bool,
25}
26
27#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
28fn options() -> TestOptions {
29 use embassy_stm32::rcc;
30 info!("H75 config");
31 let mut c = config();
32 c.rcc.hse = Some(rcc::Hse {
33 freq: embassy_stm32::time::Hertz(25_000_000),
34 mode: rcc::HseMode::Oscillator,
35 });
36 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
37 TestOptions {
38 config: c,
39 max_latency: Duration::from_micros(1200),
40 second_fifo_working: false,
41 }
42}
43
44#[cfg(any(feature = "stm32h7a3zi"))]
45fn options() -> TestOptions {
46 use embassy_stm32::rcc;
47 info!("H7a config");
48 let mut c = config();
49 c.rcc.hse = Some(rcc::Hse {
50 freq: embassy_stm32::time::Hertz(25_000_000),
51 mode: rcc::HseMode::Oscillator,
52 });
53 c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
54 TestOptions {
55 config: c,
56 max_latency: Duration::from_micros(1200),
57 second_fifo_working: false,
58 }
59}
60
61#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
62fn options() -> TestOptions {
63 info!("G4 config");
64 TestOptions {
65 config: config(),
66 max_latency: Duration::from_micros(500),
67 second_fifo_working: true,
68 }
69}
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 //let peripherals = embassy_stm32::init(config());
74
75 let options = options();
76 let peripherals = embassy_stm32::init(options.config);
77
78 let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
79
80 // 250k bps
81 can.set_bitrate(250_000);
82
83 can.set_extended_filter(
84 can::filter::ExtendedFilterSlot::_0,
85 can::filter::ExtendedFilter::accept_all_into_fifo1(),
86 );
87
88 let mut can = can.into_internal_loopback_mode();
89
90 info!("CAN Configured");
91
92 let mut i: u8 = 0;
93 loop {
94 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
95
96 info!("Transmitting frame...");
97 let tx_ts = Instant::now();
98 can.write(&tx_frame).await;
99
100 let (frame, timestamp) = can.read().await.unwrap();
101 info!("Frame received!");
102
103 // Check data.
104 assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
105
106 info!("loopback time {}", timestamp);
107 info!("loopback frame {=u8}", frame.data()[0]);
108 let latency = timestamp.saturating_duration_since(tx_ts);
109 info!("loopback latency {} us", latency.as_micros());
110
111 // Theoretical minimum latency is 55us, actual is usually ~80us
112 const MIN_LATENCY: Duration = Duration::from_micros(50);
113 // Was failing at 150 but we are not getting a real time stamp. I'm not
114 // sure if there are other delays
115 assert!(
116 MIN_LATENCY <= latency && latency <= options.max_latency,
117 "{} <= {} <= {}",
118 MIN_LATENCY,
119 latency,
120 options.max_latency
121 );
122
123 i += 1;
124 if i > 10 {
125 break;
126 }
127 }
128
129 let max_buffered = if options.second_fifo_working { 6 } else { 3 };
130
131 // Below here, check that we can receive from both FIFO0 and FIFO0
132 // Above we configured FIFO1 for extended ID packets. There are only 3 slots
133 // in each FIFO so make sure we write enough to fill them both up before reading.
134 for i in 0..3 {
135 // Try filling up the RX FIFO0 buffers with standard packets
136 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
137 info!("Transmitting frame {}", i);
138 can.write(&tx_frame).await;
139 }
140 for i in 3..max_buffered {
141 // Try filling up the RX FIFO0 buffers with extended packets
142 let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
143 info!("Transmitting frame {}", i);
144 can.write(&tx_frame).await;
145 }
146
147 // Try and receive all 6 packets
148 for i in 0..max_buffered {
149 let (frame, _ts) = can.read().await.unwrap();
150 match frame.id() {
151 embedded_can::Id::Extended(id) => {
152 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
153 }
154 embedded_can::Id::Standard(id) => {
155 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
156 }
157 }
158 }
159
160 // Test again with a split
161 let (mut tx, mut rx) = can.split();
162 for i in 0..3 {
163 // Try filling up the RX FIFO0 buffers with standard packets
164 let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
165 info!("Transmitting frame {}", i);
166 tx.write(&tx_frame).await;
167 }
168 for i in 3..max_buffered {
169 // Try filling up the RX FIFO0 buffers with extended packets
170 let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
171 info!("Transmitting frame {}", i);
172 tx.write(&tx_frame).await;
173 }
174
175 // Try and receive all 6 packets
176 for i in 0..max_buffered {
177 let (frame, _ts) = rx.read().await.unwrap();
178 match frame.id() {
179 embedded_can::Id::Extended(id) => {
180 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
181 }
182 embedded_can::Id::Standard(id) => {
183 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
184 }
185 }
186 }
187
188 info!("Test OK");
189 cortex_m::asm::bkpt();
190}
diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs
new file mode 100644
index 000000000..8cc5d593f
--- /dev/null
+++ b/tests/stm32/src/bin/hash.rs
@@ -0,0 +1,101 @@
1// required-features: hash
2#![no_std]
3#![no_main]
4
5#[path = "../common.rs"]
6mod common;
7use common::*;
8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::hash::*;
11use embassy_stm32::{bind_interrupts, hash, peripherals};
12use hmac::{Hmac, Mac};
13use sha2::{Digest, Sha224, Sha256};
14use {defmt_rtt as _, panic_probe as _};
15
16type HmacSha256 = Hmac<Sha256>;
17
18#[cfg(any(feature = "stm32l4a6zg", feature = "stm32h755zi", feature = "stm32h753zi"))]
19bind_interrupts!(struct Irqs {
20 HASH_RNG => hash::InterruptHandler<peripherals::HASH>;
21});
22
23#[cfg(any(
24 feature = "stm32wba52cg",
25 feature = "stm32l552ze",
26 feature = "stm32h563zi",
27 feature = "stm32h503rb",
28 feature = "stm32u5a5zj",
29 feature = "stm32u585ai"
30))]
31bind_interrupts!(struct Irqs {
32 HASH => hash::InterruptHandler<peripherals::HASH>;
33});
34
35#[embassy_executor::main]
36async fn main(_spawner: Spawner) {
37 let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
38 let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs);
39
40 let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh";
41 let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr";
42 let test_3: &[u8] = b"a.ewtkluGWEBR.KAJRBTA,RMNRBG,FDMGB.kger.tkasjrbt.akrjtba.krjtba.ktmyna,nmbvtyliasd;gdrtba,sfvs.kgjzshd.gkbsr.tksejb.SDkfBSE.gkfgb>ESkfbSE>gkJSBESE>kbSE>fk";
43
44 // Start an SHA-256 digest.
45 let mut sha256context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None);
46 hw_hasher.update_blocking(&mut sha256context, test_1);
47
48 // Interrupt the SHA-256 digest to compute an SHA-224 digest.
49 let mut sha224context = hw_hasher.start(Algorithm::SHA224, DataType::Width8, None);
50 hw_hasher.update_blocking(&mut sha224context, test_3);
51 let mut sha224_digest_buffer: [u8; 28] = [0; 28];
52 let _ = hw_hasher.finish_blocking(sha224context, &mut sha224_digest_buffer);
53
54 // Finish the SHA-256 digest.
55 hw_hasher.update_blocking(&mut sha256context, test_2);
56 let mut sha256_digest_buffer: [u8; 32] = [0; 32];
57 let _ = hw_hasher.finish_blocking(sha256context, &mut sha256_digest_buffer);
58
59 // Compute the SHA-256 digest in software.
60 let mut sw_sha256_hasher = Sha256::new();
61 sw_sha256_hasher.update(test_1);
62 sw_sha256_hasher.update(test_2);
63 let sw_sha256_digest = sw_sha256_hasher.finalize();
64
65 //Compute the SHA-224 digest in software.
66 let mut sw_sha224_hasher = Sha224::new();
67 sw_sha224_hasher.update(test_3);
68 let sw_sha224_digest = sw_sha224_hasher.finalize();
69
70 // Compare the SHA-256 digests.
71 info!("Hardware SHA-256 Digest: {:?}", sha256_digest_buffer);
72 info!("Software SHA-256 Digest: {:?}", sw_sha256_digest[..]);
73 defmt::assert!(sha256_digest_buffer == sw_sha256_digest[..]);
74
75 // Compare the SHA-224 digests.
76 info!("Hardware SHA-256 Digest: {:?}", sha224_digest_buffer);
77 info!("Software SHA-256 Digest: {:?}", sw_sha224_digest[..]);
78 defmt::assert!(sha224_digest_buffer == sw_sha224_digest[..]);
79
80 let hmac_key: [u8; 64] = [0x55; 64];
81
82 // Compute HMAC in hardware.
83 let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key));
84 hw_hasher.update_blocking(&mut sha256hmac_context, test_1);
85 hw_hasher.update_blocking(&mut sha256hmac_context, test_2);
86 let mut hw_hmac: [u8; 32] = [0; 32];
87 hw_hasher.finish_blocking(sha256hmac_context, &mut hw_hmac);
88
89 // Compute HMAC in software.
90 let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap();
91 sw_mac.update(test_1);
92 sw_mac.update(test_2);
93 let sw_hmac = sw_mac.finalize().into_bytes();
94
95 info!("Hardware HMAC: {:?}", hw_hmac);
96 info!("Software HMAC: {:?}", sw_hmac[..]);
97 defmt::assert!(hw_hmac == sw_hmac[..]);
98
99 info!("Test OK");
100 cortex_m::asm::bkpt();
101}
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
index f5d618db4..0c110421d 100644
--- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs
+++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
@@ -74,7 +74,7 @@ async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>)
74} 74}
75 75
76#[embassy_executor::task] 76#[embassy_executor::task]
77async fn receive_task(mut rx: RingBufferedUartRx<'static, peris::UART, peris::UART_RX_DMA>) { 77async fn receive_task(mut rx: RingBufferedUartRx<'static, peris::UART>) {
78 info!("Ready to receive..."); 78 info!("Ready to receive...");
79 79
80 let mut rng = ChaCha8Rng::seed_from_u64(1337); 80 let mut rng = ChaCha8Rng::seed_from_u64(1337);
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 313380b35..3297ea7e2 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -2,6 +2,8 @@
2 2
3pub use defmt::*; 3pub use defmt::*;
4#[allow(unused)] 4#[allow(unused)]
5use embassy_stm32::rcc::*;
6#[allow(unused)]
5use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
6use embassy_stm32::Config; 8use embassy_stm32::Config;
7use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
@@ -54,6 +56,10 @@ teleprobe_meta::target!(b"nucleo-stm32l496zg");
54teleprobe_meta::target!(b"nucleo-stm32wl55jc"); 56teleprobe_meta::target!(b"nucleo-stm32wl55jc");
55#[cfg(feature = "stm32wba52cg")] 57#[cfg(feature = "stm32wba52cg")]
56teleprobe_meta::target!(b"nucleo-stm32wba52cg"); 58teleprobe_meta::target!(b"nucleo-stm32wba52cg");
59#[cfg(feature = "stm32f091rc")]
60teleprobe_meta::target!(b"nucleo-stm32f091rc");
61#[cfg(feature = "stm32h503rb")]
62teleprobe_meta::target!(b"nucleo-stm32h503rb");
57 63
58macro_rules! define_peris { 64macro_rules! define_peris {
59 ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => { 65 ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => {
@@ -85,6 +91,12 @@ macro_rules! define_peris {
85 }; 91 };
86} 92}
87 93
94#[cfg(feature = "stm32f091rc")]
95define_peris!(
96 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5,
97 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
98 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
99);
88#[cfg(feature = "stm32f103c8")] 100#[cfg(feature = "stm32f103c8")]
89define_peris!( 101define_peris!(
90 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, 102 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5,
@@ -157,6 +169,12 @@ define_peris!(
157 SPI = SPI4, SPI_SCK = PE12, SPI_MOSI = PE14, SPI_MISO = PE13, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, 169 SPI = SPI4, SPI_SCK = PE12, SPI_MOSI = PE14, SPI_MISO = PE13, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1,
158 @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::LPUART1>;}, 170 @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::LPUART1>;},
159); 171);
172#[cfg(feature = "stm32h503rb")]
173define_peris!(
174 UART = USART1, UART_TX = PB14, UART_RX = PB15, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1,
175 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1,
176 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
177);
160#[cfg(feature = "stm32c031c6")] 178#[cfg(feature = "stm32c031c6")]
161define_peris!( 179define_peris!(
162 UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, 180 UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
@@ -242,14 +260,68 @@ pub fn config() -> Config {
242 #[allow(unused_mut)] 260 #[allow(unused_mut)]
243 let mut config = Config::default(); 261 let mut config = Config::default();
244 262
263 #[cfg(feature = "stm32c031c6")]
264 {
265 config.rcc.hsi = Some(Hsi {
266 sys_div: HsiSysDiv::DIV1, // 48Mhz
267 ker_div: HsiKerDiv::DIV3, // 16Mhz
268 });
269 config.rcc.sys = Sysclk::HSISYS;
270 config.rcc.ahb_pre = AHBPrescaler::DIV1;
271 config.rcc.apb1_pre = APBPrescaler::DIV1;
272 }
273
274 #[cfg(feature = "stm32g071rb")]
275 {
276 config.rcc.hsi = true;
277 config.rcc.pll = Some(Pll {
278 source: PllSource::HSI,
279 prediv: PllPreDiv::DIV1,
280 mul: PllMul::MUL16,
281 divp: None,
282 divq: None,
283 divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz
284 });
285 config.rcc.sys = Sysclk::PLL1_R;
286 }
245 #[cfg(feature = "stm32wb55rg")] 287 #[cfg(feature = "stm32wb55rg")]
246 { 288 {
247 config.rcc = embassy_stm32::rcc::WPAN_DEFAULT; 289 config.rcc = embassy_stm32::rcc::WPAN_DEFAULT;
248 } 290 }
249 291
292 #[cfg(feature = "stm32f091rc")]
293 {
294 config.rcc.hse = Some(Hse {
295 freq: Hertz(8_000_000),
296 mode: HseMode::Bypass,
297 });
298 config.rcc.pll = Some(Pll {
299 src: PllSource::HSE,
300 prediv: PllPreDiv::DIV1,
301 mul: PllMul::MUL6,
302 });
303 config.rcc.sys = Sysclk::PLL1_P;
304 config.rcc.ahb_pre = AHBPrescaler::DIV1;
305 config.rcc.apb1_pre = APBPrescaler::DIV1;
306 }
307 #[cfg(feature = "stm32f103c8")]
308 {
309 config.rcc.hse = Some(Hse {
310 freq: Hertz(8_000_000),
311 mode: HseMode::Oscillator,
312 });
313 config.rcc.pll = Some(Pll {
314 src: PllSource::HSE,
315 prediv: PllPreDiv::DIV1,
316 mul: PllMul::MUL9,
317 });
318 config.rcc.sys = Sysclk::PLL1_P;
319 config.rcc.ahb_pre = AHBPrescaler::DIV1;
320 config.rcc.apb1_pre = APBPrescaler::DIV2;
321 config.rcc.apb2_pre = APBPrescaler::DIV1;
322 }
250 #[cfg(feature = "stm32f207zg")] 323 #[cfg(feature = "stm32f207zg")]
251 { 324 {
252 use embassy_stm32::rcc::*;
253 // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) 325 // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
254 config.rcc.hse = Some(Hse { 326 config.rcc.hse = Some(Hse {
255 freq: Hertz(8_000_000), 327 freq: Hertz(8_000_000),
@@ -276,9 +348,25 @@ pub fn config() -> Config {
276 config.rcc.apb2_pre = APBPrescaler::DIV2; 348 config.rcc.apb2_pre = APBPrescaler::DIV2;
277 } 349 }
278 350
351 #[cfg(feature = "stm32f303ze")]
352 {
353 config.rcc.hse = Some(Hse {
354 freq: Hertz(8_000_000),
355 mode: HseMode::Bypass,
356 });
357 config.rcc.pll = Some(Pll {
358 src: PllSource::HSE,
359 prediv: PllPreDiv::DIV1,
360 mul: PllMul::MUL9,
361 });
362 config.rcc.sys = Sysclk::PLL1_P;
363 config.rcc.ahb_pre = AHBPrescaler::DIV1;
364 config.rcc.apb1_pre = APBPrescaler::DIV2;
365 config.rcc.apb2_pre = APBPrescaler::DIV1;
366 }
367
279 #[cfg(feature = "stm32f429zi")] 368 #[cfg(feature = "stm32f429zi")]
280 { 369 {
281 use embassy_stm32::rcc::*;
282 config.rcc.hse = Some(Hse { 370 config.rcc.hse = Some(Hse {
283 freq: Hertz(8_000_000), 371 freq: Hertz(8_000_000),
284 mode: HseMode::Bypass, 372 mode: HseMode::Bypass,
@@ -299,7 +387,6 @@ pub fn config() -> Config {
299 387
300 #[cfg(feature = "stm32f446re")] 388 #[cfg(feature = "stm32f446re")]
301 { 389 {
302 use embassy_stm32::rcc::*;
303 config.rcc.hse = Some(Hse { 390 config.rcc.hse = Some(Hse {
304 freq: Hertz(8_000_000), 391 freq: Hertz(8_000_000),
305 mode: HseMode::Oscillator, 392 mode: HseMode::Oscillator,
@@ -320,7 +407,6 @@ pub fn config() -> Config {
320 407
321 #[cfg(feature = "stm32f767zi")] 408 #[cfg(feature = "stm32f767zi")]
322 { 409 {
323 use embassy_stm32::rcc::*;
324 config.rcc.hse = Some(Hse { 410 config.rcc.hse = Some(Hse {
325 freq: Hertz(8_000_000), 411 freq: Hertz(8_000_000),
326 mode: HseMode::Bypass, 412 mode: HseMode::Bypass,
@@ -341,7 +427,6 @@ pub fn config() -> Config {
341 427
342 #[cfg(feature = "stm32h563zi")] 428 #[cfg(feature = "stm32h563zi")]
343 { 429 {
344 use embassy_stm32::rcc::*;
345 config.rcc.hsi = None; 430 config.rcc.hsi = None;
346 config.rcc.hsi48 = Some(Default::default()); // needed for RNG 431 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
347 config.rcc.hse = Some(Hse { 432 config.rcc.hse = Some(Hse {
@@ -364,9 +449,50 @@ pub fn config() -> Config {
364 config.rcc.voltage_scale = VoltageScale::Scale0; 449 config.rcc.voltage_scale = VoltageScale::Scale0;
365 } 450 }
366 451
452 #[cfg(feature = "stm32h503rb")]
453 {
454 config.rcc.hsi = None;
455 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
456 config.rcc.hse = Some(Hse {
457 freq: Hertz(24_000_000),
458 mode: HseMode::Oscillator,
459 });
460 config.rcc.pll1 = Some(Pll {
461 source: PllSource::HSE,
462 prediv: PllPreDiv::DIV6,
463 mul: PllMul::MUL125,
464 divp: Some(PllDiv::DIV2),
465 divq: Some(PllDiv::DIV2),
466 divr: None,
467 });
468 config.rcc.ahb_pre = AHBPrescaler::DIV1;
469 config.rcc.apb1_pre = APBPrescaler::DIV1;
470 config.rcc.apb2_pre = APBPrescaler::DIV1;
471 config.rcc.apb3_pre = APBPrescaler::DIV1;
472 config.rcc.sys = Sysclk::PLL1_P;
473 config.rcc.voltage_scale = VoltageScale::Scale0;
474 }
475
476 #[cfg(feature = "stm32g491re")]
477 {
478 config.rcc.hse = Some(Hse {
479 freq: Hertz(24_000_000),
480 mode: HseMode::Oscillator,
481 });
482 config.rcc.pll = Some(Pll {
483 source: PllSource::HSE,
484 prediv: PllPreDiv::DIV6,
485 mul: PllMul::MUL85,
486 divp: None,
487 divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
488 divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
489 });
490 config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
491 config.rcc.sys = Sysclk::PLL1_R;
492 }
493
367 #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] 494 #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
368 { 495 {
369 use embassy_stm32::rcc::*;
370 config.rcc.hsi = Some(HSIPrescaler::DIV1); 496 config.rcc.hsi = Some(HSIPrescaler::DIV1);
371 config.rcc.csi = true; 497 config.rcc.csi = true;
372 config.rcc.hsi48 = Some(Default::default()); // needed for RNG 498 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -393,12 +519,15 @@ pub fn config() -> Config {
393 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz 519 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
394 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz 520 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
395 config.rcc.voltage_scale = VoltageScale::Scale1; 521 config.rcc.voltage_scale = VoltageScale::Scale1;
396 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 522 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
523 #[cfg(any(feature = "stm32h755zi"))]
524 {
525 config.rcc.supply_config = SupplyConfig::DirectSMPS;
526 }
397 } 527 }
398 528
399 #[cfg(any(feature = "stm32h7a3zi"))] 529 #[cfg(any(feature = "stm32h7a3zi"))]
400 { 530 {
401 use embassy_stm32::rcc::*;
402 config.rcc.hsi = Some(HSIPrescaler::DIV1); 531 config.rcc.hsi = Some(HSIPrescaler::DIV1);
403 config.rcc.csi = true; 532 config.rcc.csi = true;
404 config.rcc.hsi48 = Some(Default::default()); // needed for RNG 533 config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -425,13 +554,12 @@ pub fn config() -> Config {
425 config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz 554 config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz
426 config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz 555 config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz
427 config.rcc.voltage_scale = VoltageScale::Scale0; 556 config.rcc.voltage_scale = VoltageScale::Scale0;
428 config.rcc.adc_clock_source = AdcClockSource::PLL2_P; 557 config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
429 } 558 }
430 559
431 #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] 560 #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))]
432 { 561 {
433 use embassy_stm32::rcc::*; 562 config.rcc.sys = Sysclk::PLL1_R;
434 config.rcc.mux = ClockSrc::PLL1_R;
435 config.rcc.hsi = true; 563 config.rcc.hsi = true;
436 config.rcc.pll = Some(Pll { 564 config.rcc.pll = Some(Pll {
437 source: PllSource::HSI, 565 source: PllSource::HSI,
@@ -445,13 +573,12 @@ pub fn config() -> Config {
445 573
446 #[cfg(feature = "stm32wl55jc")] 574 #[cfg(feature = "stm32wl55jc")]
447 { 575 {
448 use embassy_stm32::rcc::*;
449 config.rcc.hse = Some(Hse { 576 config.rcc.hse = Some(Hse {
450 freq: Hertz(32_000_000), 577 freq: Hertz(32_000_000),
451 mode: HseMode::Bypass, 578 mode: HseMode::Bypass,
452 prescaler: HsePrescaler::DIV1, 579 prescaler: HsePrescaler::DIV1,
453 }); 580 });
454 config.rcc.mux = ClockSrc::PLL1_R; 581 config.rcc.sys = Sysclk::PLL1_R;
455 config.rcc.pll = Some(Pll { 582 config.rcc.pll = Some(Pll {
456 source: PllSource::HSE, 583 source: PllSource::HSE,
457 prediv: PllPreDiv::DIV2, 584 prediv: PllPreDiv::DIV2,
@@ -464,9 +591,8 @@ pub fn config() -> Config {
464 591
465 #[cfg(any(feature = "stm32l552ze"))] 592 #[cfg(any(feature = "stm32l552ze"))]
466 { 593 {
467 use embassy_stm32::rcc::*;
468 config.rcc.hsi = true; 594 config.rcc.hsi = true;
469 config.rcc.mux = ClockSrc::PLL1_R; 595 config.rcc.sys = Sysclk::PLL1_R;
470 config.rcc.pll = Some(Pll { 596 config.rcc.pll = Some(Pll {
471 // 110Mhz clock (16 / 4 * 55 / 2) 597 // 110Mhz clock (16 / 4 * 55 / 2)
472 source: PllSource::HSI, 598 source: PllSource::HSI,
@@ -480,42 +606,46 @@ pub fn config() -> Config {
480 606
481 #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] 607 #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))]
482 { 608 {
483 use embassy_stm32::rcc::*; 609 config.rcc.hsi = true;
484 config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_48MHZ); 610 config.rcc.pll1 = Some(Pll {
611 source: PllSource::HSI, // 16 MHz
612 prediv: PllPreDiv::DIV1,
613 mul: PllMul::MUL10,
614 divp: None,
615 divq: None,
616 divr: Some(PllDiv::DIV1), // 160 MHz
617 });
618 config.rcc.sys = Sysclk::PLL1_R;
619 config.rcc.voltage_range = VoltageScale::RANGE1;
620 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
485 } 621 }
486 622
487 #[cfg(feature = "stm32wba52cg")] 623 #[cfg(feature = "stm32wba52cg")]
488 { 624 {
489 use embassy_stm32::rcc::*; 625 config.rcc.sys = Sysclk::HSI;
490 config.rcc.mux = ClockSrc::HSI; 626 config.rcc.mux.rngsel = mux::Rngsel::HSI;
491
492 embassy_stm32::pac::RCC.ccipr2().write(|w| {
493 w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI);
494 });
495 } 627 }
496 628
497 #[cfg(feature = "stm32l073rz")] 629 #[cfg(feature = "stm32l073rz")]
498 { 630 {
499 use embassy_stm32::rcc::*;
500 config.rcc.hsi = true; 631 config.rcc.hsi = true;
501 config.rcc.pll = Some(Pll { 632 config.rcc.pll = Some(Pll {
502 source: PllSource::HSI, 633 source: PllSource::HSI,
503 mul: PllMul::MUL4, 634 mul: PllMul::MUL4,
504 div: PllDiv::DIV2, // 32Mhz clock (16 * 4 / 2) 635 div: PllDiv::DIV2, // 32Mhz clock (16 * 4 / 2)
505 }); 636 });
506 config.rcc.mux = ClockSrc::PLL1_R; 637 config.rcc.sys = Sysclk::PLL1_R;
507 } 638 }
508 639
509 #[cfg(any(feature = "stm32l152re"))] 640 #[cfg(any(feature = "stm32l152re"))]
510 { 641 {
511 use embassy_stm32::rcc::*;
512 config.rcc.hsi = true; 642 config.rcc.hsi = true;
513 config.rcc.pll = Some(Pll { 643 config.rcc.pll = Some(Pll {
514 source: PllSource::HSI, 644 source: PllSource::HSI,
515 mul: PllMul::MUL4, 645 mul: PllMul::MUL4,
516 div: PllDiv::DIV2, // 32Mhz clock (16 * 4 / 2) 646 div: PllDiv::DIV2, // 32Mhz clock (16 * 4 / 2)
517 }); 647 });
518 config.rcc.mux = ClockSrc::PLL1_R; 648 config.rcc.sys = Sysclk::PLL1_R;
519 } 649 }
520 650
521 config 651 config
diff --git a/tests/stm32/teleprobe.sh b/tests/stm32/teleprobe.sh
deleted file mode 100755
index 6eec6ca93..000000000
--- a/tests/stm32/teleprobe.sh
+++ /dev/null
@@ -1,12 +0,0 @@
1echo Running target=$1 elf=$2
2STATUSCODE=$(
3 curl \
4 -sS \
5 --output /dev/stderr \
6 --write-out "%{http_code}" \
7 -H "Authorization: Bearer $TELEPROBE_TOKEN" \
8 https://teleprobe.embassy.dev/targets/$1/run --data-binary @$2
9)
10echo
11echo HTTP Status code: $STATUSCODE
12test "$STATUSCODE" -eq 200