aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorjrmoulton <[email protected]>2025-06-10 15:47:54 -0600
committerjrmoulton <[email protected]>2025-06-10 15:48:36 -0600
commitcfad9798ff99d4de0571a512d156b5fe1ef1d427 (patch)
treefc3bf670f82d139de19466cddad1e909db7f3d2e /embassy-stm32
parentfc342915e6155dec7bafa3e135da7f37a9a07f5c (diff)
parent6186d111a5c150946ee5b7e9e68d987a38c1a463 (diff)
merge new embassy changes
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/CHANGELOG.md279
-rw-r--r--embassy-stm32/Cargo.toml199
-rw-r--r--embassy-stm32/build.rs693
-rw-r--r--embassy-stm32/src/adc/c0.rs467
-rw-r--r--embassy-stm32/src/adc/f1.rs19
-rw-r--r--embassy-stm32/src/adc/f3.rs10
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs9
-rw-r--r--embassy-stm32/src/adc/g4.rs260
-rw-r--r--embassy-stm32/src/adc/mod.rs90
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs41
-rw-r--r--embassy-stm32/src/adc/u5_adc4.rs478
-rw-r--r--embassy-stm32/src/adc/v1.rs8
-rw-r--r--embassy-stm32/src/adc/v2.rs7
-rw-r--r--embassy-stm32/src/adc/v3.rs39
-rw-r--r--embassy-stm32/src/adc/v4.rs42
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs121
-rw-r--r--embassy-stm32/src/can/bxcan/registers.rs17
-rw-r--r--embassy-stm32/src/can/common.rs96
-rw-r--r--embassy-stm32/src/can/enums.rs14
-rw-r--r--embassy-stm32/src/can/fd/config.rs12
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs25
-rw-r--r--embassy-stm32/src/can/fdcan.rs416
-rw-r--r--embassy-stm32/src/can/frame.rs39
-rw-r--r--embassy-stm32/src/cordic/mod.rs30
-rw-r--r--embassy-stm32/src/crc/v1.rs27
-rw-r--r--embassy-stm32/src/crc/v2v3.rs50
-rw-r--r--embassy-stm32/src/cryp/mod.rs893
-rw-r--r--embassy-stm32/src/dac/mod.rs405
-rw-r--r--embassy-stm32/src/dcmi.rs267
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs215
-rw-r--r--embassy-stm32/src/dma/gpdma.rs89
-rw-r--r--embassy-stm32/src/dma/mod.rs31
-rw-r--r--embassy-stm32/src/dma/ringbuffer.rs668
-rw-r--r--embassy-stm32/src/dma/ringbuffer/mod.rs333
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/mod.rs90
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs50
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs123
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs122
-rw-r--r--embassy-stm32/src/dma/util.rs28
-rw-r--r--embassy-stm32/src/dsihost.rs14
-rw-r--r--embassy-stm32/src/dts/mod.rs238
-rw-r--r--embassy-stm32/src/dts/tsel.rs51
-rw-r--r--embassy-stm32/src/eth/generic_phy.rs (renamed from embassy-stm32/src/eth/generic_smi.rs)56
-rw-r--r--embassy-stm32/src/eth/mod.rs57
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs182
-rw-r--r--embassy-stm32/src/eth/v1/rx_desc.rs6
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs123
-rw-r--r--embassy-stm32/src/exti.rs53
-rw-r--r--embassy-stm32/src/flash/asynch.rs14
-rw-r--r--embassy-stm32/src/flash/common.rs20
-rw-r--r--embassy-stm32/src/flash/eeprom.rs236
-rw-r--r--embassy-stm32/src/flash/f0.rs10
-rw-r--r--embassy-stm32/src/flash/f1f3.rs14
-rw-r--r--embassy-stm32/src/flash/f2.rs134
-rw-r--r--embassy-stm32/src/flash/f4.rs339
-rw-r--r--embassy-stm32/src/flash/f7.rs77
-rw-r--r--embassy-stm32/src/flash/g.rs49
-rw-r--r--embassy-stm32/src/flash/h5.rs166
-rw-r--r--embassy-stm32/src/flash/h50.rs12
-rw-r--r--embassy-stm32/src/flash/h7.rs10
-rw-r--r--embassy-stm32/src/flash/l.rs160
-rw-r--r--embassy-stm32/src/flash/mod.rs36
-rw-r--r--embassy-stm32/src/flash/other.rs10
-rw-r--r--embassy-stm32/src/flash/u0.rs10
-rw-r--r--embassy-stm32/src/flash/u5.rs26
-rw-r--r--embassy-stm32/src/fmc.rs23
-rw-r--r--embassy-stm32/src/fmt.rs22
-rw-r--r--embassy-stm32/src/gpio.rs101
-rw-r--r--embassy-stm32/src/hash/mod.rs292
-rw-r--r--embassy-stm32/src/hrtim/mod.rs48
-rw-r--r--embassy-stm32/src/hrtim/traits.rs4
-rw-r--r--embassy-stm32/src/hsem/mod.rs16
-rw-r--r--embassy-stm32/src/hspi/enums.rs422
-rw-r--r--embassy-stm32/src/hspi/mod.rs1007
-rw-r--r--embassy-stm32/src/i2c/mod.rs46
-rw-r--r--embassy-stm32/src/i2c/v2.rs110
-rw-r--r--embassy-stm32/src/i2s.rs423
-rw-r--r--embassy-stm32/src/ipcc.rs6
-rw-r--r--embassy-stm32/src/lib.rs151
-rw-r--r--embassy-stm32/src/low_power.rs30
-rw-r--r--embassy-stm32/src/lptim/channel.rs18
-rw-r--r--embassy-stm32/src/lptim/mod.rs49
-rw-r--r--embassy-stm32/src/lptim/pwm.rs198
-rw-r--r--embassy-stm32/src/lptim/timer/channel_direction.rs18
-rw-r--r--embassy-stm32/src/lptim/timer/mod.rs131
-rw-r--r--embassy-stm32/src/lptim/timer/prescaler.rs90
-rw-r--r--embassy-stm32/src/ltdc.rs87
-rw-r--r--embassy-stm32/src/macros.rs33
-rw-r--r--embassy-stm32/src/opamp.rs396
-rw-r--r--embassy-stm32/src/ospi/mod.rs433
-rw-r--r--embassy-stm32/src/qspi/enums.rs48
-rw-r--r--embassy-stm32/src/qspi/mod.rs169
-rw-r--r--embassy-stm32/src/rcc/bd.rs54
-rw-r--r--embassy-stm32/src/rcc/c0.rs39
-rw-r--r--embassy-stm32/src/rcc/f013.rs148
-rw-r--r--embassy-stm32/src/rcc/f247.rs57
-rw-r--r--embassy-stm32/src/rcc/g0.rs87
-rw-r--r--embassy-stm32/src/rcc/g4.rs43
-rw-r--r--embassy-stm32/src/rcc/h.rs68
-rw-r--r--embassy-stm32/src/rcc/hsi48.rs8
-rw-r--r--embassy-stm32/src/rcc/l.rs28
-rw-r--r--embassy-stm32/src/rcc/mco.rs15
-rw-r--r--embassy-stm32/src/rcc/mod.rs50
-rw-r--r--embassy-stm32/src/rcc/u5.rs102
-rw-r--r--embassy-stm32/src/rcc/wba.rs16
-rw-r--r--embassy-stm32/src/rng.rs74
-rw-r--r--embassy-stm32/src/rtc/datetime.rs24
-rw-r--r--embassy-stm32/src/rtc/low_power.rs31
-rw-r--r--embassy-stm32/src/rtc/mod.rs22
-rw-r--r--embassy-stm32/src/rtc/v2.rs12
-rw-r--r--embassy-stm32/src/rtc/v3.rs24
-rw-r--r--embassy-stm32/src/sai/mod.rs208
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs1536
-rw-r--r--embassy-stm32/src/spdifrx/mod.rs333
-rw-r--r--embassy-stm32/src/spi/mod.rs255
-rw-r--r--embassy-stm32/src/time.rs15
-rw-r--r--embassy-stm32/src/time_driver.rs238
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs24
-rw-r--r--embassy-stm32/src/timer/input_capture.rs27
-rw-r--r--embassy-stm32/src/timer/low_level.rs114
-rw-r--r--embassy-stm32/src/timer/mod.rs18
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs383
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs24
-rw-r--r--embassy-stm32/src/timer/qei.rs20
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs480
-rw-r--r--embassy-stm32/src/tsc/acquisition_banks.rs209
-rw-r--r--embassy-stm32/src/tsc/config.rs175
-rw-r--r--embassy-stm32/src/tsc/enums.rs238
-rw-r--r--embassy-stm32/src/tsc/errors.rs21
-rw-r--r--embassy-stm32/src/tsc/io_pin.rs200
-rw-r--r--embassy-stm32/src/tsc/mod.rs1016
-rw-r--r--embassy-stm32/src/tsc/pin_groups.rs663
-rw-r--r--embassy-stm32/src/tsc/tsc.rs446
-rw-r--r--embassy-stm32/src/tsc/types.rs93
-rw-r--r--embassy-stm32/src/ucpd.rs160
-rw-r--r--embassy-stm32/src/usart/buffered.rs353
-rw-r--r--embassy-stm32/src/usart/mod.rs735
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs295
-rw-r--r--embassy-stm32/src/usb/mod.rs40
-rw-r--r--embassy-stm32/src/usb/otg.rs175
-rw-r--r--embassy-stm32/src/usb/usb.rs330
-rw-r--r--embassy-stm32/src/wdg/mod.rs9
-rw-r--r--embassy-stm32/src/xspi/enums.rs364
-rw-r--r--embassy-stm32/src/xspi/mod.rs1425
144 files changed, 18198 insertions, 6602 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
new file mode 100644
index 000000000..b6781905e
--- /dev/null
+++ b/embassy-stm32/CHANGELOG.md
@@ -0,0 +1,279 @@
1# Changelog for embassy-stm32
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9- Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983))
10- Added a 'single-bank' and a 'dual-bank' feature so chips with configurable flash bank setups are be supported in embassy ([#4125](https://github.com/embassy-rs/embassy/pull/4125))
11
12## 0.2.0 - 2025-01-10
13
14Starting 2025 strong with a release packed with new, exciting good stuff! 🚀
15
16### New chips
17
18This release adds support for many newly-released STM32 chips.
19
20- STM32H7[RS] "bootflash line" ([#2898](https://github.com/embassy-rs/embassy/pull/2898))
21- STM32U0 ([#2809](https://github.com/embassy-rs/embassy/pull/2809) [#2813](https://github.com/embassy-rs/embassy/pull/2813))
22- STM32H5[23] ([#2892](https://github.com/embassy-rs/embassy/pull/2892))
23- STM32U5[FG] ([#2892](https://github.com/embassy-rs/embassy/pull/2892))
24- STM32WBA5[045] ([#2892](https://github.com/embassy-rs/embassy/pull/2892))
25
26### Simpler APIs with less generics
27
28Many HAL APIs have been simplified thanks to reducing the amount of generic parameters. This helps with creating arrays of pins or peripherals, and for calling the same code with different pins/peripherals without incurring in code size penalties d
29
30For GPIO, the pins have been eliminated. `Output<'_, PA4>` is now `Output<'_>`.
31
32For peripherals, both pins and DMA channels have been eliminated. Peripherals now have a "mode" generic param that specifies whether it's capable of async operation. For example, `I2c<'_, I2C2, NoDma, NoDma>` is now `I2c<'_, Blocking>` and `I2c<'_, I2C2, DMA2_CH1, DMA2_CH2>` is now `I2c<'_, Async>`.
33
34- Removed DMA channel generic params for UART ([#2821](https://github.com/embassy-rs/embassy/pull/2821)), I2C ([#2820](https://github.com/embassy-rs/embassy/pull/2820)), SPI ([#2819](https://github.com/embassy-rs/embassy/pull/2819)), QSPI ([#2982](https://github.com/embassy-rs/embassy/pull/2982)), OSPI ([#2941](https://github.com/embassy-rs/embassy/pull/2941)).
35- Removed peripheral generic params for GPIO ([#2471](https://github.com/embassy-rs/embassy/pull/2471)), UART ([#2836](https://github.com/embassy-rs/embassy/pull/2836)), I2C ([#2974](https://github.com/embassy-rs/embassy/pull/2974)), SPI ([#2835](https://github.com/embassy-rs/embassy/pull/2835))
36- Remove generics in CAN ([#3012](https://github.com/embassy-rs/embassy/pull/3012), [#3020](https://github.com/embassy-rs/embassy/pull/3020), [#3032](https://github.com/embassy-rs/embassy/pull/3032), [#3033](https://github.com/embassy-rs/embassy/pull/3033))
37
38### More complete and consistent RCC
39
40RCC support has been vastly expanded and improved.
41- The API is now consistent across all STM32 families. Previously in some families you'd configure the desired target frequencies for `sysclk` and the buses and `embassy-stm32` would try to calculate dividers and muxes to hit them as close as possible. This has proved to be intractable in the general case and hard to extend to more exotic RCC configurations. So, we have standardized on an API where the user specifies the settings for dividers and muxes directly. It's lower level but gices more control to the user, supports all edge case exotic configurations, and makes it easier to translate a configuration from the STM32CubeMX tool. ([Tracking issue](https://github.com/embassy-rs/embassy/issues/2515). [#2624](https://github.com/embassy-rs/embassy/pull/2624). F0, F1 [#2564](https://github.com/embassy-rs/embassy/pull/2564), F3 [#2560](https://github.com/embassy-rs/embassy/pull/2560), U5 [#2617](https://github.com/embassy-rs/embassy/pull/2617), [#3514](https://github.com/embassy-rs/embassy/pull/3514), [#3513](https://github.com/embassy-rs/embassy/pull/3513), G4 [#2579](https://github.com/embassy-rs/embassy/pull/2579), [#2618](https://github.com/embassy-rs/embassy/pull/2618), WBA [#2520](https://github.com/embassy-rs/embassy/pull/2520), G0, C0 ([#2656](https://github.com/embassy-rs/embassy/pull/2656)).
42- Added support for configuring all per-peripheral clock muxes (CCIPRx, DCKCFGRx registers) in `config.rcc.mux`. This was previously handled in an ad-hoc way in some drivers (e.g. USB) and not at all in others (causing e.g. wrong SPI frequency) ([#2521](https://github.com/embassy-rs/embassy/pull/2521), [#2583](https://github.com/embassy-rs/embassy/pull/2583), [#2634](https://github.com/embassy-rs/embassy/pull/2634), [#2626](https://github.com/embassy-rs/embassy/pull/2626), [#2815](https://github.com/embassy-rs/embassy/pull/2815), [#2517](https://github.com/embassy-rs/embassy/pull/2517)).
43- Switch to a safe configuration before configuring RCC. This helps avoid crashes when RCC has been already configured previously (for example by a bootloader). (F2, F4, F7 [#2829](https://github.com/embassy-rs/embassy/pull/2829), C0, F0, F1, F3, G0, G4, H5, H7[#3008](https://github.com/embassy-rs/embassy/pull/3008))
44- Some new nice features:
45 - Expose RCC enable and disable in public API. ([#2807](https://github.com/embassy-rs/embassy/pull/2807))
46 - Add `unchecked-overclocking` feature that disables all asserts, allowing running RCC out of spec. ([#3574](https://github.com/embassy-rs/embassy/pull/3574))
47- Many fixes:
48 - Workaround H5 errata that accidentally clears RAM on backup domain reset. ([#2616](https://github.com/embassy-rs/embassy/pull/2616))
49 - Reset RTC on L0 ([#2597](https://github.com/embassy-rs/embassy/pull/2597))
50 - Fix H7 to use correct unit in vco clock check ([#2537](https://github.com/embassy-rs/embassy/pull/2537))
51 - Fix incorrect D1CPRE max for STM32H7 RM0468 ([#2518](https://github.com/embassy-rs/embassy/pull/2518))
52 - WBA's high speed external clock has to run at 32 MHz ([#2511](https://github.com/embassy-rs/embassy/pull/2511))
53 - Take into account clock propagation delay to peripherals after enabling a clock. ([#2677](https://github.com/embassy-rs/embassy/pull/2677))
54 - Fix crash caused by using higher MSI range as sysclk on STM32WL ([#2786](https://github.com/embassy-rs/embassy/pull/2786))
55 - fix using HSI48 as SYSCLK on F0 devices with CRS ([#3652](https://github.com/embassy-rs/embassy/pull/3652))
56 - compute LSE and LSI frequency for STM32L and STM32U0 series ([#3554](https://github.com/embassy-rs/embassy/pull/3554))
57 - Add support for LSESYS, used to pass LSE clock to peripherals ([#3518](https://github.com/embassy-rs/embassy/pull/3518))
58 - H5: LSE low drive mode is not functional ([#2738](https://github.com/embassy-rs/embassy/pull/2738))
59
60### New peripheral drivers
61
62- Dual-core support. First core initializes RCC and writes a struct into shared memory that the second core uses, ensuring no conflicts. ([#3158](https://github.com/embassy-rs/embassy/pull/3158), [#3263](https://github.com/embassy-rs/embassy/pull/3263), [#3687](https://github.com/embassy-rs/embassy/pull/3687))
63- USB Type-C/USB Power Delivery Interface (UCPD) ([#2652](https://github.com/embassy-rs/embassy/pull/2652), [#2683](https://github.com/embassy-rs/embassy/pull/2683), [#2701](https://github.com/embassy-rs/embassy/pull/2701), [#2925](https://github.com/embassy-rs/embassy/pull/2925), [#3084](https://github.com/embassy-rs/embassy/pull/3084), [#3271](https://github.com/embassy-rs/embassy/pull/3271), [#3678](https://github.com/embassy-rs/embassy/pull/3678), [#3714](https://github.com/embassy-rs/embassy/pull/3714))
64- Touch sensing controller (TSC) ([#2853](https://github.com/embassy-rs/embassy/pull/2853), [#3111](https://github.com/embassy-rs/embassy/pull/3111), [#3163](https://github.com/embassy-rs/embassy/pull/3163), [#3274](https://github.com/embassy-rs/embassy/pull/3274))
65- Display Serial Interface (DSI) [#2903](https://github.com/embassy-rs/embassy/pull/2903), ([#3082](https://github.com/embassy-rs/embassy/pull/3082))
66- LCD/TFT Display Controller (LTDC) ([#3126](https://github.com/embassy-rs/embassy/pull/3126), [#3458](https://github.com/embassy-rs/embassy/pull/3458))
67- SPDIF receiver (SPDIFRX) ([#3280](https://github.com/embassy-rs/embassy/pull/3280))
68- CORDIC math accelerator ([#2697](https://github.com/embassy-rs/embassy/pull/2697))
69- Digital Temperature Sensor (DTS) ([#3717](https://github.com/embassy-rs/embassy/pull/3717))
70- HMAC accelerator ([#2565](https://github.com/embassy-rs/embassy/pull/2565))
71- Hash accelerator ([#2528](https://github.com/embassy-rs/embassy/pull/2528))
72- Crypto accelerator ([#2619](https://github.com/embassy-rs/embassy/pull/2619), [#2691](https://github.com/embassy-rs/embassy/pull/2691))
73- Semaphore (HSEM) ([#2777](https://github.com/embassy-rs/embassy/pull/2777), [#3161](https://github.com/embassy-rs/embassy/pull/3161))
74
75### Improvements to existing drivers
76
77GPIO:
78- Generate singletons only for pins that actually exist. ([#3738](https://github.com/embassy-rs/embassy/pull/3738))
79- Add `set_as_analog` to Flex ([#3017](https://github.com/embassy-rs/embassy/pull/3017))
80- Add `embedded-hal` v0.2 `InputPin` impls for `OutputOpenDrain`. ([#2716](https://github.com/embassy-rs/embassy/pull/2716))
81- Add a config option to make the VDDIO2 supply line valid ([#2737](https://github.com/embassy-rs/embassy/pull/2737))
82- Refactor AfType ([#3031](https://github.com/embassy-rs/embassy/pull/3031))
83- Gpiov1: Do not call set_speed for AFType::Input ([#2996](https://github.com/embassy-rs/embassy/pull/2996))
84
85UART:
86- Add embedded-io impls ([#2739](https://github.com/embassy-rs/embassy/pull/2739))
87- Add support for changing baud rate ([#3512](https://github.com/embassy-rs/embassy/pull/3512))
88- Add split_ref ([#3500](https://github.com/embassy-rs/embassy/pull/3500))
89- Add data bit selection ([#3595](https://github.com/embassy-rs/embassy/pull/3595))
90- Add RX Pull configuration option ([#3415](https://github.com/embassy-rs/embassy/pull/3415))
91- Add async flush ([#3379](https://github.com/embassy-rs/embassy/pull/3379))
92- Add support for sending breaks ([#3286](https://github.com/embassy-rs/embassy/pull/3286))
93- Disconnect pins on drop ([#3006](https://github.com/embassy-rs/embassy/pull/3006))
94- Half-duplex improvements
95 - Add half-duplex for all USART versions ([#2833](https://github.com/embassy-rs/embassy/pull/2833))
96 - configurable readback for half-duplex. ([#3679](https://github.com/embassy-rs/embassy/pull/3679))
97 - Convert uart half_duplex to use user configurable IO ([#3233](https://github.com/embassy-rs/embassy/pull/3233))
98 - Fix uart::flush with FIFO at Half-Duplex mode ([#2895](https://github.com/embassy-rs/embassy/pull/2895))
99 - Fix Half-Duplex sequential reads and writes ([#3089](https://github.com/embassy-rs/embassy/pull/3089))
100 - disable transmitter during during half-duplex flush ([#3299](https://github.com/embassy-rs/embassy/pull/3299))
101- Buffered UART improvements
102 - Add embedded-io ReadReady impls ([#3179](https://github.com/embassy-rs/embassy/pull/3179), [#3451](https://github.com/embassy-rs/embassy/pull/3451))
103 - Add constructors for RS485 ([#3441](https://github.com/embassy-rs/embassy/pull/3441))
104 - Fix RingBufferedUartRx hard-resetting DMA after initial error ([#3356](https://github.com/embassy-rs/embassy/pull/3356))
105 - Don't teardown during reconfigure ([#2989](https://github.com/embassy-rs/embassy/pull/2989))
106 - Wake receive task for each received byte ([#2722](https://github.com/embassy-rs/embassy/pull/2722))
107 - Fix dma and idle line detection in ringbuffereduartrx ([#3319](https://github.com/embassy-rs/embassy/pull/3319))
108
109SPI:
110- Add MISO pullup configuration option ([#2943](https://github.com/embassy-rs/embassy/pull/2943))
111- Add slew rate configuration options ([#3669](https://github.com/embassy-rs/embassy/pull/3669))
112- Fix blocking_write on nosck spi. ([#3035](https://github.com/embassy-rs/embassy/pull/3035))
113- Restrict txonly_nosck to SPIv1, it hangs in other versions. ([#3028](https://github.com/embassy-rs/embassy/pull/3028))
114- Fix non-u8 word sizes. ([#3363](https://github.com/embassy-rs/embassy/pull/3363))
115- Issue correct DMA word length when reading to prevent hang. ([#3362](https://github.com/embassy-rs/embassy/pull/3362))
116- Add proper rxonly support for spi_v3 and force tx dma stream requirements. ([#3007](https://github.com/embassy-rs/embassy/pull/3007))
117
118I2C:
119- Implement asynchronous transactions ([#2742](https://github.com/embassy-rs/embassy/pull/2742))
120- Implement blocking transactions ([#2713](https://github.com/embassy-rs/embassy/pull/2713))
121- Disconnect pins on drop ([#3006](https://github.com/embassy-rs/embassy/pull/3006))
122- Ensure bus is free before master-write operation ([#3104](https://github.com/embassy-rs/embassy/pull/3104))
123- Add workaround for STM32 i2cv1 errata ([#2887](https://github.com/embassy-rs/embassy/pull/2887))
124- Fix disabling pullup accidentally enabling pulldown ([#3410](https://github.com/embassy-rs/embassy/pull/3410))
125
126Flash:
127- Add L5 support ([#3423](https://github.com/embassy-rs/embassy/pull/3423))
128- Add H5 support ([#3305](https://github.com/embassy-rs/embassy/pull/3305))
129- add F2 support ([#3303](https://github.com/embassy-rs/embassy/pull/3303))
130- Add U5 support ([#2591](https://github.com/embassy-rs/embassy/pull/2591), [#2792](https://github.com/embassy-rs/embassy/pull/2792))
131- Add H50x support ([#2600](https://github.com/embassy-rs/embassy/pull/2600), [#2808](https://github.com/embassy-rs/embassy/pull/2808))
132- Fix flash erase on F3 ([#3744](https://github.com/embassy-rs/embassy/pull/3744))
133- Support G0 second flash bank ([#3711](https://github.com/embassy-rs/embassy/pull/3711))
134- F1, F3: wait for BSY flag to clear before flashing ([#3217](https://github.com/embassy-rs/embassy/pull/3217))
135- H7: enhance resilience to program sequence errors (pgserr) ([#2539](https://github.com/embassy-rs/embassy/pull/2539))
136
137ADC:
138- Add `AnyAdcChannel` type. You can obtain it from a pin with `.degrade_adc()`. Useful for making arrays of ADC pins. ([#2985](https://github.com/embassy-rs/embassy/pull/2985))
139- Add L0 support ([#2544](https://github.com/embassy-rs/embassy/pull/2544))
140- Add U5 support ([#3688](https://github.com/embassy-rs/embassy/pull/3688))
141- Add H5 support ([#2613](https://github.com/embassy-rs/embassy/pull/2613), [#3557](https://github.com/embassy-rs/embassy/pull/3557))
142- Add G4 async support ([#3566](https://github.com/embassy-rs/embassy/pull/3566))
143- Add G4 support for calibrating differential inputs ([#3735](https://github.com/embassy-rs/embassy/pull/3735))
144- Add oversampling and differential support for G4 ([#3169](https://github.com/embassy-rs/embassy/pull/3169))
145- Add DMA support for ADC v2 ([#3116](https://github.com/embassy-rs/embassy/pull/3116))
146- Add DMA support for ADC v3 and v4 ([#3128](https://github.com/embassy-rs/embassy/pull/3128))
147- Unify naming `blocking_read` for blocking, `read` for async. ([#3148](https://github.com/embassy-rs/embassy/pull/3148))
148- Fix channel count for the STM32G4 ADCs. ([#2828](https://github.com/embassy-rs/embassy/pull/2828))
149- Fix blocking_delay_us() overflowing when sys freq is high ([#2825](https://github.com/embassy-rs/embassy/pull/2825))
150- Remove need for taking a `Delay` impl. ([#2797](https://github.com/embassy-rs/embassy/pull/2797))
151- H5: set OR.OP0 to 1 when ADCx_INP0 is selected, per RM ([#2776](https://github.com/embassy-rs/embassy/pull/2776))
152- Add oversampling support ([#3124](https://github.com/embassy-rs/embassy/pull/3124))
153- Adc averaging support for ADC v4. ([#3110](https://github.com/embassy-rs/embassy/pull/3110))
154- F2 ADC fixes ([#2513](https://github.com/embassy-rs/embassy/pull/2513))
155
156DAC:
157- Fix new_internal not setting mode as documented ([#2886](https://github.com/embassy-rs/embassy/pull/2886))
158
159OPAMP:
160- Add missing opamp external outputs for STM32G4 ([#3636](https://github.com/embassy-rs/embassy/pull/3636))
161- Add extra lifetime to opamp-using structs ([#3207](https://github.com/embassy-rs/embassy/pull/3207))
162- Make OpAmp usable in follower configuration for internal DAC channel ([#3021](https://github.com/embassy-rs/embassy/pull/3021))
163
164CAN:
165- Add FDCAN support. ([#2475](https://github.com/embassy-rs/embassy/pull/2475), [#2571](https://github.com/embassy-rs/embassy/pull/2571), [#2623](https://github.com/embassy-rs/embassy/pull/2623), [#2631](https://github.com/embassy-rs/embassy/pull/2631), [#2635](https://github.com/embassy-rs/embassy/pull/2635), [#2637](https://github.com/embassy-rs/embassy/pull/2637), [#2645](https://github.com/embassy-rs/embassy/pull/2645), [#2647](https://github.com/embassy-rs/embassy/pull/2647), [#2658](https://github.com/embassy-rs/embassy/pull/2658), [#2703](https://github.com/embassy-rs/embassy/pull/2703), [#3364](https://github.com/embassy-rs/embassy/pull/3364))
166- Simplify BXCAN API, make BXCAN and FDCAN APIs consistent. ([#2760](https://github.com/embassy-rs/embassy/pull/2760), [#2693](https://github.com/embassy-rs/embassy/pull/2693), [#2744](https://github.com/embassy-rs/embassy/pull/2744))
167- Add buffered mode support ([#2588](https://github.com/embassy-rs/embassy/pull/2588))
168- Add support for modifying the receiver filters from `BufferedCan`, `CanRx`, and `BufferedCanRx` ([#3733](https://github.com/embassy-rs/embassy/pull/3733))
169- Add support for optional FIFO scheduling for outgoing frames ([#2988](https://github.com/embassy-rs/embassy/pull/2988))
170- fdcan: Properties for common runtime get/set operations ([#2840](https://github.com/embassy-rs/embassy/pull/2840))
171- fdcan: implement bus-off recovery ([#2832](https://github.com/embassy-rs/embassy/pull/2832))
172- Add BXCAN sleep/wakeup functionality ([#2854](https://github.com/embassy-rs/embassy/pull/2854))
173- Fix BXCAN hangs ([#3468](https://github.com/embassy-rs/embassy/pull/3468))
174- add RTR flag if it is remote frame ([#3421](https://github.com/embassy-rs/embassy/pull/3421))
175- Fix log storm when no CAN is connected ([#3284](https://github.com/embassy-rs/embassy/pull/3284))
176- Fix error handling ([#2850](https://github.com/embassy-rs/embassy/pull/2850))
177- Give CAN a kick when writing into TX buffer via sender. ([#2646](https://github.com/embassy-rs/embassy/pull/2646))
178- Preseve the RTR flag in messages. ([#2745](https://github.com/embassy-rs/embassy/pull/2745))
179
180FMC:
181- Add 13bit address sdram constructors ([#3189](https://github.com/embassy-rs/embassy/pull/3189))
182
183xSPI:
184- Add OCTOSPI support ([#2672](https://github.com/embassy-rs/embassy/pull/2672))
185- Add OCTOSPIM support ([#3102](https://github.com/embassy-rs/embassy/pull/3102))
186- Add HEXADECASPI support ([#3667](https://github.com/embassy-rs/embassy/pull/3667))
187- Add memory mapping support for QSPI ([#3725](https://github.com/embassy-rs/embassy/pull/3725))
188- Add memory mapping support for OCTOSPI ([#3456](https://github.com/embassy-rs/embassy/pull/3456))
189- Add async support for QSPI ([#3475](https://github.com/embassy-rs/embassy/pull/3475))
190- Fix QSPI synchronous read operation hangs when FIFO is not full ([#3724](https://github.com/embassy-rs/embassy/pull/3724))
191- Stick to `blocking_*` naming convention for QSPI, OSPI ([#3661](https://github.com/embassy-rs/embassy/pull/3661))
192
193SDMMC:
194- Add `block-device-driver` impl for use with `embedded-fatfs` ([#2607](https://github.com/embassy-rs/embassy/pull/2607))
195- Allow cmd block to be passed in for sdmmc dma transfers ([#3188](https://github.com/embassy-rs/embassy/pull/3188))
196
197ETH:
198- Fix reception of multicast packets ([#3488](https://github.com/embassy-rs/embassy/pull/3488), [#3707](https://github.com/embassy-rs/embassy/pull/3707))
199- Add support for executing custom SMI commands ([#3355](https://github.com/embassy-rs/embassy/pull/3355))
200- Add support for MII interface ([#2465](https://github.com/embassy-rs/embassy/pull/2465))
201
202USB:
203- Assert correct clock on init. ([#2711](https://github.com/embassy-rs/embassy/pull/2711))
204- Set PWR_CR2 USV on STM32L4 ([#2605](https://github.com/embassy-rs/embassy/pull/2605))
205- USBD driver improvements:
206 - Add ISO endpoint support ([#3314](https://github.com/embassy-rs/embassy/pull/3314))
207 - Add support for L1. ([#2452](https://github.com/embassy-rs/embassy/pull/2452))
208 - set USB initialization delay to 1µs ([#3700](https://github.com/embassy-rs/embassy/pull/3700))
209- OTG driver improvements:
210 - Add ISO endpoint support ([#3314](https://github.com/embassy-rs/embassy/pull/3314))
211 - Add support for U595, U5A5 ([#3613](https://github.com/embassy-rs/embassy/pull/3613))
212 - Add support for STM32H7R/S ([#3337](https://github.com/embassy-rs/embassy/pull/3337))
213 - Add support for full-speed ULPI mode ([#3281](https://github.com/embassy-rs/embassy/pull/3281))
214 - Make max EP count configurable ([#2881](https://github.com/embassy-rs/embassy/pull/2881))
215 - fix corruption in CONTROL OUT transfers in stm32f4. ([#3565](https://github.com/embassy-rs/embassy/pull/3565))
216 - Extract Synopsys USB OTG driver to a separate crate ([#2871](https://github.com/embassy-rs/embassy/pull/2871))
217 - Add critical sections to avoid USB OTG corruption Errata ([#2823](https://github.com/embassy-rs/embassy/pull/2823))
218 - Fix support for OTG_HS in FS mode. ([#2805](https://github.com/embassy-rs/embassy/pull/2805))
219
220I2S:
221- Add SPIv3 support. ([#2992](https://github.com/embassy-rs/embassy/pull/2992))
222- Add full-duplex support. ([#2992](https://github.com/embassy-rs/embassy/pull/2992))
223- Add I2S ringbuffered DMA support ([#3023](https://github.com/embassy-rs/embassy/pull/3023))
224- Fix STM32F4 I2S clock calculations ([#3716](https://github.com/embassy-rs/embassy/pull/3716))
225
226SAI:
227- Add a function that waits for any SAI/ringbuffer write error ([#3545](https://github.com/embassy-rs/embassy/pull/3545))
228- Disallow start without an initial write ([#3541](https://github.com/embassy-rs/embassy/pull/3541))
229- Flush FIFO on init and disable ([#3538](https://github.com/embassy-rs/embassy/pull/3538))
230- Fix MCKDIV for SAI v3/v4 ([#2710](https://github.com/embassy-rs/embassy/pull/2710))
231- Pull down clock and data lines in receive mode ([#3326](https://github.com/embassy-rs/embassy/pull/3326))
232- Add function to check if SAI is muted ([#3282](https://github.com/embassy-rs/embassy/pull/3282))
233
234Low-power support:
235- Update `embassy-executor` to v0.7.
236- Add support for U0 ([#3556](https://github.com/embassy-rs/embassy/pull/3556))
237- Add support for U5 ([#3496](https://github.com/embassy-rs/embassy/pull/3496))
238- Add support for H5 ([#2877](https://github.com/embassy-rs/embassy/pull/2877))
239- Add support for L4 ([#3213](https://github.com/embassy-rs/embassy/pull/3213))
240- Fix low-power EXTI IRQ handler dropped edges ([#3404](https://github.com/embassy-rs/embassy/pull/3404))
241- Fix alarms not triggering in some cases ([#3592](https://github.com/embassy-rs/embassy/pull/3592))
242
243Timer:
244- Add Input Capture high-level driver ([#2912](https://github.com/embassy-rs/embassy/pull/2912))
245- Add PWM Input high-level driver ([#3014](https://github.com/embassy-rs/embassy/pull/3014))
246- Add support for splitting `SimplePwm` into channels ([#3317](https://github.com/embassy-rs/embassy/pull/3317))
247- Fix `SimplePwm` not enabling output pin in some stm32 families ([#2670](https://github.com/embassy-rs/embassy/pull/2670))
248- Add LPTIM low-level driver. ([#3310](https://github.com/embassy-rs/embassy/pull/3310))
249- Low-level TIM driver improvements:
250 - Simplify traits, convert from trait methods to struct. ([#2728](https://github.com/embassy-rs/embassy/pull/2728))
251 - Add `low_level::Timer::get_clock_frequency()` ([#2908](https://github.com/embassy-rs/embassy/pull/2908))
252 - Fix 32bit timer off by one ARR error ([#2876](https://github.com/embassy-rs/embassy/pull/2876))
253 - Avoid max_compare_value >= u16::MAX ([#3549](https://github.com/embassy-rs/embassy/pull/3549))
254
255DMA:
256- Add `AnyChannel` type. Similar to `AnyPin`, it allows representing any DMA channel at runtime without needing generics. ([#2606](https://github.com/embassy-rs/embassy/pull/2606))
257, Add support for BDMA on H7 ([#2606](https://github.com/embassy-rs/embassy/pull/2606))
258- Add async `stop()` function to BDMA, DMA ([#2757](https://github.com/embassy-rs/embassy/pull/2757))
259- Add configuration option for DMA Request Priority ([#2680](https://github.com/embassy-rs/embassy/pull/2680))
260- Rewrite DMA ringbuffers ([#3336](https://github.com/embassy-rs/embassy/pull/3336))
261- Enable half transfer IRQ when constructing a ReadableDmaRingBuffer ([#3093](https://github.com/embassy-rs/embassy/pull/3093))
262- Right-align `write_immediate()` in ring buffers ([#3588](https://github.com/embassy-rs/embassy/pull/3588))
263
264`embassy-time` driver:
265- Update to `embassy-time` v0.4, `embassy-time-driver` v0.2. ([#3593](https://github.com/embassy-rs/embassy/pull/3593))
266- Change preference order of `time-driver-any` to pick less-featureful timers first. ([#2570](https://github.com/embassy-rs/embassy/pull/2570))
267- Allow using more TIMx timers for the time driver of TIM1 ([#2570](https://github.com/embassy-rs/embassy/pull/2570), [#2614](https://github.com/embassy-rs/embassy/pull/2614))
268- Correctly gate `time` feature of embassy-embedded-hal in embassy-stm32 ([#3359](https://github.com/embassy-rs/embassy/pull/3359))
269- adds timer-driver for tim21 and tim22 (on L0) ([#2450](https://github.com/embassy-rs/embassy/pull/2450))
270
271WDG:
272- Allow higher PSC value for iwdg_v3 ... ([#2628](https://github.com/embassy-rs/embassy/pull/2628))
273
274Misc:
275- Allow `bind_interrupts!` to accept conditional compilation attrs ([#3444](https://github.com/embassy-rs/embassy/pull/3444))
276
277## 0.1.0 - 2024-01-12
278
279First release.
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index ac9e9644c..034f51df9 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-stm32" 2name = "embassy-stm32"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers" 6description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers"
@@ -19,16 +19,22 @@ flavors = [
19 { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, 19 { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" },
20 { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" }, 20 { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" },
21 { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" }, 21 { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" },
22 { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi", features = ["low-power"] }, 22 { regex_feature = "stm32f4[2367]..[ig]", target = "thumbv7em-none-eabi", features = ["low-power", "dual-bank"] },
23 { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi", features = ["low-power", "single-bank"] },
24 { regex_feature = "stm32f7[67]..[ig]", target = "thumbv7em-none-eabi", features = ["dual-bank"] },
23 { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" }, 25 { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" },
24 { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, 26 { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" },
27 { regex_feature = "stm32g0...c", target = "thumbv6m-none-eabi", features = ["dual-bank"] },
25 { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, 28 { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" },
29 { regex_feature = "stm32g4[78].*", target = "thumbv7em-none-eabi", features = ["low-power", "dual-bank"] },
26 { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi", features = ["low-power"] }, 30 { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi", features = ["low-power"] },
27 { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] }, 31 { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] },
28 { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, 32 { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" },
29 { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] }, 33 { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] },
30 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, 34 { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
35 { regex_feature = "stm32l4[pqrs].*", target = "thumbv7em-none-eabi", features = ["dual-bank"] },
31 { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, 36 { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" },
37 { regex_feature = "stm32l5...e", target = "thumbv8m.main-none-eabihf", features = ["low-power", "dual-bank"] },
32 { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] }, 38 { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] },
33 { regex_feature = "stm32u0.*", target = "thumbv6m-none-eabi" }, 39 { regex_feature = "stm32u0.*", target = "thumbv6m-none-eabi" },
34 { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, 40 { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
@@ -38,20 +44,21 @@ flavors = [
38] 44]
39 45
40[package.metadata.docs.rs] 46[package.metadata.docs.rs]
41features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h755zi-cm7"] 47features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h755zi-cm7", "single-bank"]
42rustdoc-args = ["--cfg", "docsrs"] 48rustdoc-args = ["--cfg", "docsrs"]
43 49
44[dependencies] 50[dependencies]
45embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 51embassy-sync = { version = "0.7.0", path = "../embassy-sync" }
46embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } 52embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
47embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 53embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true }
54embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true }
48embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 55embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
49embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } 56embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
50embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } 57embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false }
51embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 58embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
52embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } 59embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
53embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } 60embassy-usb-synopsys-otg = { version = "0.2.0", path = "../embassy-usb-synopsys-otg" }
54embassy-executor = { version = "0.6.0", path = "../embassy-executor", optional = true } 61embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true }
55 62
56embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 63embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
57embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 64embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
@@ -62,17 +69,19 @@ embedded-can = "0.4"
62embedded-storage = "0.3.1" 69embedded-storage = "0.3.1"
63embedded-storage-async = { version = "0.4.1" } 70embedded-storage-async = { version = "0.4.1" }
64 71
72rand-core-06 = { package = "rand_core", version = "0.6" }
73rand-core-09 = { package = "rand_core", version = "0.9" }
65 74
66defmt = { version = "0.3", optional = true } 75
76defmt = { version = "1.0.1", optional = true }
67log = { version = "0.4.14", optional = true } 77log = { version = "0.4.14", optional = true }
68cortex-m-rt = ">=0.6.15,<0.8" 78cortex-m-rt = ">=0.6.15,<0.8"
69cortex-m = "0.7.6" 79cortex-m = "0.7.6"
70futures-util = { version = "0.3.30", default-features = false } 80futures-util = { version = "0.3.30", default-features = false }
71rand_core = "0.6.3" 81sdio-host = "0.9.0"
72sdio-host = "0.5.0"
73critical-section = "1.1" 82critical-section = "1.1"
74#stm32-metapac = { version = "15" } 83#stm32-metapac = { version = "16" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645" } 84stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec" }
76 85
77vcell = "0.1.3" 86vcell = "0.1.3"
78nb = "1.0.0" 87nb = "1.0.0"
@@ -88,16 +97,20 @@ static_assertions = { version = "1.1" }
88volatile-register = { version = "0.2.1" } 97volatile-register = { version = "0.2.1" }
89bitflags = "2.4.2" 98bitflags = "2.4.2"
90 99
100block-device-driver = { version = "0.2" }
101aligned = "0.4.1"
91 102
92[dev-dependencies] 103[dev-dependencies]
93critical-section = { version = "1.1", features = ["std"] } 104critical-section = { version = "1.1", features = ["std"] }
105proptest = "1.5.0"
106proptest-state-machine = "0.3.0"
94 107
95[build-dependencies] 108[build-dependencies]
96proc-macro2 = "1.0.36" 109proc-macro2 = "1.0.36"
97quote = "1.0.15" 110quote = "1.0.15"
98 111
99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 112#stm32-metapac = { version = "16", default-features = false, features = ["metadata"]}
100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645", default-features = false, features = ["metadata"] } 113stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec", default-features = false, features = ["metadata"] }
101 114
102[features] 115[features]
103default = ["rt"] 116default = ["rt"]
@@ -106,14 +119,24 @@ default = ["rt"]
106rt = ["stm32-metapac/rt"] 119rt = ["stm32-metapac/rt"]
107 120
108## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging 121## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging
109defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] 122defmt = [
123 "dep:defmt",
124 "embassy-sync/defmt",
125 "embassy-embedded-hal/defmt",
126 "embassy-hal-internal/defmt",
127 "embedded-io-async/defmt-03",
128 "embassy-usb-driver/defmt",
129 "embassy-net-driver/defmt",
130 "embassy-time?/defmt",
131 "embassy-usb-synopsys-otg/defmt",
132]
110 133
111exti = [] 134exti = []
112low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] 135low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ]
113low-power-debug-with-sleep = [] 136low-power-debug-with-sleep = []
114 137
115## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) 138## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/)
116memory-x = ["stm32-metapac/memory-x"] 139memory-x = []
117 140
118## Use secure registers when TrustZone is enabled 141## Use secure registers when TrustZone is enabled
119trustzone-secure = [] 142trustzone-secure = []
@@ -124,14 +147,18 @@ trustzone-secure = []
124## There are no plans to make this stable. 147## There are no plans to make this stable.
125unstable-pac = [] 148unstable-pac = []
126 149
150## Enable this feature to disable the overclocking check.
151## DO NOT ENABLE THIS FEATURE UNLESS YOU KNOW WHAT YOU'RE DOING.
152unchecked-overclocking = []
153
127#! ## Time 154#! ## Time
128 155
129## Enables additional driver features that depend on embassy-time 156## Enables additional driver features that depend on embassy-time
130time = ["dep:embassy-time"] 157time = ["dep:embassy-time", "embassy-embedded-hal/time"]
131 158
132# Features starting with `_` are for internal use only. They're not intended 159# Features starting with `_` are for internal use only. They're not intended
133# to be enabled by other crates, and are not covered by semver guarantees. 160# to be enabled by other crates, and are not covered by semver guarantees.
134_time-driver = ["dep:embassy-time-driver", "time"] 161_time-driver = ["dep:embassy-time-driver", "time", "dep:embassy-time-queue-utils"]
135 162
136## Use any time driver 163## Use any time driver
137time-driver-any = ["_time-driver"] 164time-driver-any = ["_time-driver"]
@@ -178,11 +205,17 @@ split-pc2 = ["_split-pins-enabled"]
178## Split PC3 205## Split PC3
179split-pc3 = ["_split-pins-enabled"] 206split-pc3 = ["_split-pins-enabled"]
180 207
208dual-bank = []
209single-bank = []
210
181## internal use only 211## internal use only
182_split-pins-enabled = [] 212_split-pins-enabled = []
183 213
184## internal use only 214## internal use only
185_dual-core = [] 215_dual-core = []
216_core-cm0p = []
217_core-cm4 = []
218_core-cm7 = []
186 219
187#! ## Chip-selection features 220#! ## Chip-selection features
188#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`. 221#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`.
@@ -1007,40 +1040,40 @@ stm32h743xg = [ "stm32-metapac/stm32h743xg" ]
1007stm32h743xi = [ "stm32-metapac/stm32h743xi" ] 1040stm32h743xi = [ "stm32-metapac/stm32h743xi" ]
1008stm32h743zg = [ "stm32-metapac/stm32h743zg" ] 1041stm32h743zg = [ "stm32-metapac/stm32h743zg" ]
1009stm32h743zi = [ "stm32-metapac/stm32h743zi" ] 1042stm32h743zi = [ "stm32-metapac/stm32h743zi" ]
1010stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "_dual-core" ] 1043stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "_dual-core", "_core-cm7" ]
1011stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "_dual-core" ] 1044stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "_dual-core", "_core-cm4" ]
1012stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "_dual-core" ] 1045stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "_dual-core", "_core-cm7" ]
1013stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "_dual-core" ] 1046stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "_dual-core", "_core-cm4" ]
1014stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "_dual-core" ] 1047stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "_dual-core", "_core-cm7" ]
1015stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "_dual-core" ] 1048stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "_dual-core", "_core-cm4" ]
1016stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "_dual-core" ] 1049stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "_dual-core", "_core-cm7" ]
1017stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "_dual-core" ] 1050stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "_dual-core", "_core-cm4" ]
1018stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "_dual-core" ] 1051stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "_dual-core", "_core-cm7" ]
1019stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "_dual-core" ] 1052stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "_dual-core", "_core-cm4" ]
1020stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "_dual-core" ] 1053stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "_dual-core", "_core-cm7" ]
1021stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "_dual-core" ] 1054stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "_dual-core", "_core-cm4" ]
1022stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "_dual-core" ] 1055stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "_dual-core", "_core-cm7" ]
1023stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "_dual-core" ] 1056stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "_dual-core", "_core-cm4" ]
1024stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "_dual-core" ] 1057stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "_dual-core", "_core-cm7" ]
1025stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "_dual-core" ] 1058stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "_dual-core", "_core-cm4" ]
1026stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "_dual-core" ] 1059stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "_dual-core", "_core-cm7" ]
1027stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "_dual-core" ] 1060stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "_dual-core", "_core-cm4" ]
1028stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "_dual-core" ] 1061stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "_dual-core", "_core-cm7" ]
1029stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "_dual-core" ] 1062stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "_dual-core", "_core-cm4" ]
1030stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "_dual-core" ] 1063stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "_dual-core", "_core-cm7" ]
1031stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "_dual-core" ] 1064stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "_dual-core", "_core-cm4" ]
1032stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "_dual-core" ] 1065stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "_dual-core", "_core-cm7" ]
1033stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "_dual-core" ] 1066stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "_dual-core", "_core-cm4" ]
1034stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "_dual-core" ] 1067stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "_dual-core", "_core-cm7" ]
1035stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "_dual-core" ] 1068stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "_dual-core", "_core-cm4" ]
1036stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "_dual-core" ] 1069stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "_dual-core", "_core-cm7" ]
1037stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "_dual-core" ] 1070stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "_dual-core", "_core-cm4" ]
1038stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "_dual-core" ] 1071stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "_dual-core", "_core-cm7" ]
1039stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "_dual-core" ] 1072stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "_dual-core", "_core-cm4" ]
1040stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "_dual-core" ] 1073stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "_dual-core", "_core-cm7" ]
1041stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "_dual-core" ] 1074stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "_dual-core", "_core-cm4" ]
1042stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "_dual-core" ] 1075stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "_dual-core", "_core-cm7" ]
1043stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "_dual-core" ] 1076stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "_dual-core", "_core-cm4" ]
1044stm32h750ib = [ "stm32-metapac/stm32h750ib" ] 1077stm32h750ib = [ "stm32-metapac/stm32h750ib" ]
1045stm32h750vb = [ "stm32-metapac/stm32h750vb" ] 1078stm32h750vb = [ "stm32-metapac/stm32h750vb" ]
1046stm32h750xb = [ "stm32-metapac/stm32h750xb" ] 1079stm32h750xb = [ "stm32-metapac/stm32h750xb" ]
@@ -1051,24 +1084,24 @@ stm32h753ii = [ "stm32-metapac/stm32h753ii" ]
1051stm32h753vi = [ "stm32-metapac/stm32h753vi" ] 1084stm32h753vi = [ "stm32-metapac/stm32h753vi" ]
1052stm32h753xi = [ "stm32-metapac/stm32h753xi" ] 1085stm32h753xi = [ "stm32-metapac/stm32h753xi" ]
1053stm32h753zi = [ "stm32-metapac/stm32h753zi" ] 1086stm32h753zi = [ "stm32-metapac/stm32h753zi" ]
1054stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "_dual-core" ] 1087stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "_dual-core", "_core-cm7" ]
1055stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "_dual-core" ] 1088stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "_dual-core", "_core-cm4" ]
1056stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "_dual-core" ] 1089stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "_dual-core", "_core-cm7" ]
1057stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "_dual-core" ] 1090stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "_dual-core", "_core-cm4" ]
1058stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "_dual-core" ] 1091stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "_dual-core", "_core-cm7" ]
1059stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "_dual-core" ] 1092stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "_dual-core", "_core-cm4" ]
1060stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "_dual-core" ] 1093stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "_dual-core", "_core-cm7" ]
1061stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "_dual-core" ] 1094stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "_dual-core", "_core-cm4" ]
1062stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "_dual-core" ] 1095stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "_dual-core", "_core-cm7" ]
1063stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "_dual-core" ] 1096stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "_dual-core", "_core-cm4" ]
1064stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "_dual-core" ] 1097stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "_dual-core", "_core-cm7" ]
1065stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "_dual-core" ] 1098stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "_dual-core", "_core-cm4" ]
1066stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "_dual-core" ] 1099stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "_dual-core", "_core-cm7" ]
1067stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "_dual-core" ] 1100stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "_dual-core", "_core-cm4" ]
1068stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "_dual-core" ] 1101stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "_dual-core", "_core-cm7" ]
1069stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "_dual-core" ] 1102stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "_dual-core", "_core-cm4" ]
1070stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "_dual-core" ] 1103stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "_dual-core", "_core-cm7" ]
1071stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "_dual-core" ] 1104stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "_dual-core", "_core-cm4" ]
1072stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] 1105stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ]
1073stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] 1106stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ]
1074stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] 1107stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ]
@@ -1601,14 +1634,14 @@ stm32wba55he = [ "stm32-metapac/stm32wba55he" ]
1601stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ] 1634stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ]
1602stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ] 1635stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ]
1603stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ] 1636stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ]
1604stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core" ] 1637stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core", "_core-cm4" ]
1605stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core" ] 1638stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core", "_core-cm0p" ]
1606stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core" ] 1639stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core", "_core-cm4" ]
1607stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p", "_dual-core" ] 1640stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p", "_dual-core", "_core-cm0p" ]
1608stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4", "_dual-core" ] 1641stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4", "_dual-core", "_core-cm4" ]
1609stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p", "_dual-core" ] 1642stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p", "_dual-core", "_core-cm0p" ]
1610stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4", "_dual-core" ] 1643stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4", "_dual-core", "_core-cm4" ]
1611stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p", "_dual-core" ] 1644stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p", "_dual-core", "_core-cm0p" ]
1612stm32wle4c8 = [ "stm32-metapac/stm32wle4c8" ] 1645stm32wle4c8 = [ "stm32-metapac/stm32wle4c8" ]
1613stm32wle4cb = [ "stm32-metapac/stm32wle4cb" ] 1646stm32wle4cb = [ "stm32-metapac/stm32wle4cb" ]
1614stm32wle4cc = [ "stm32-metapac/stm32wle4cc" ] 1647stm32wle4cc = [ "stm32-metapac/stm32wle4cc" ]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index d8a7ea0e6..bb5ef53d7 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -9,8 +9,8 @@ use proc_macro2::{Ident, TokenStream};
9use quote::{format_ident, quote}; 9use quote::{format_ident, quote};
10use stm32_metapac::metadata::ir::BitOffset; 10use stm32_metapac::metadata::ir::BitOffset;
11use stm32_metapac::metadata::{ 11use stm32_metapac::metadata::{
12 MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, ALL_CHIPS, 12 MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode,
13 ALL_PERIPHERAL_VERSIONS, METADATA, 13 ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA,
14}; 14};
15 15
16#[path = "./build_common.rs"] 16#[path = "./build_common.rs"]
@@ -50,12 +50,63 @@ fn main() {
50 } 50 }
51 51
52 // ======== 52 // ========
53 // Select the memory variant to use
54 let memory = {
55 let single_bank_selected = env::var("CARGO_FEATURE_SINGLE_BANK").is_ok();
56 let dual_bank_selected = env::var("CARGO_FEATURE_DUAL_BANK").is_ok();
57
58 let single_bank_memory = METADATA.memory.iter().find(|mem| {
59 mem.iter().any(|region| region.name.contains("BANK_1"))
60 && !mem.iter().any(|region| region.name.contains("BANK_2"))
61 });
62
63 let dual_bank_memory = METADATA.memory.iter().find(|mem| {
64 mem.iter().any(|region| region.name.contains("BANK_1"))
65 && mem.iter().any(|region| region.name.contains("BANK_2"))
66 });
67
68 cfgs.set(
69 "bank_setup_configurable",
70 single_bank_memory.is_some() && dual_bank_memory.is_some(),
71 );
72
73 match (single_bank_selected, dual_bank_selected) {
74 (true, true) => panic!("Both 'single-bank' and 'dual-bank' features enabled"),
75 (true, false) => {
76 single_bank_memory.expect("The 'single-bank' feature is not supported on this dual bank chip")
77 }
78 (false, true) => {
79 dual_bank_memory.expect("The 'dual-bank' feature is not supported on this single bank chip")
80 }
81 (false, false) => {
82 if METADATA.memory.len() != 1 {
83 panic!("Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection")
84 }
85 METADATA.memory[0]
86 }
87 }
88 };
89
90 // ========
53 // Generate singletons 91 // Generate singletons
54 92
55 let mut singletons: Vec<String> = Vec::new(); 93 let mut singletons: Vec<String> = Vec::new();
94
95 // Generate one singleton per pin
96 for p in METADATA.pins {
97 singletons.push(p.name.to_string());
98 }
99
100 // generate one singleton per peripheral (with many exceptions...)
56 for p in METADATA.peripherals { 101 for p in METADATA.peripherals {
57 if let Some(r) = &p.registers { 102 if let Some(r) = &p.registers {
58 if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" { 103 if r.kind == "adccommon"
104 || r.kind == "sai"
105 || r.kind == "ucpd"
106 || r.kind == "otg"
107 || r.kind == "octospi"
108 || r.kind == "xspi"
109 {
59 // TODO: should we emit this for all peripherals? if so, we will need a list of all 110 // TODO: should we emit this for all peripherals? if so, we will need a list of all
60 // possible peripherals across all chips, so that we can declare the configs 111 // possible peripherals across all chips, so that we can declare the configs
61 // (replacing the hard-coded list of `peri_*` cfgs below) 112 // (replacing the hard-coded list of `peri_*` cfgs below)
@@ -63,13 +114,8 @@ fn main() {
63 } 114 }
64 115
65 match r.kind { 116 match r.kind {
66 // Generate singletons per pin, not per port 117 // handled above
67 "gpio" => { 118 "gpio" => {}
68 let port_letter = p.name.strip_prefix("GPIO").unwrap();
69 for pin_num in 0..16 {
70 singletons.push(format!("P{}{}", port_letter, pin_num));
71 }
72 }
73 119
74 // No singleton for these, the HAL handles them specially. 120 // No singleton for these, the HAL handles them specially.
75 "exti" => {} 121 "exti" => {}
@@ -111,6 +157,10 @@ fn main() {
111 "peri_sai4", 157 "peri_sai4",
112 "peri_ucpd1", 158 "peri_ucpd1",
113 "peri_ucpd2", 159 "peri_ucpd2",
160 "peri_usb_otg_fs",
161 "peri_usb_otg_hs",
162 "peri_octospi2",
163 "peri_xspi2",
114 ]); 164 ]);
115 cfgs.declare_all(&["mco", "mco1", "mco2"]); 165 cfgs.declare_all(&["mco", "mco1", "mco2"]);
116 166
@@ -192,7 +242,7 @@ fn main() {
192 .to_ascii_lowercase(), 242 .to_ascii_lowercase(),
193 ), 243 ),
194 Err(GetOneError::None) => None, 244 Err(GetOneError::None) => None,
195 Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"), 245 Err(GetOneError::Multiple) => panic!("Multiple time-driver-xxx Cargo features enabled"),
196 }; 246 };
197 247
198 let time_driver_singleton = match time_driver.as_ref().map(|x| x.as_ref()) { 248 let time_driver_singleton = match time_driver.as_ref().map(|x| x.as_ref()) {
@@ -278,8 +328,7 @@ fn main() {
278 // ======== 328 // ========
279 // Generate FLASH regions 329 // Generate FLASH regions
280 let mut flash_regions = TokenStream::new(); 330 let mut flash_regions = TokenStream::new();
281 let flash_memory_regions: Vec<_> = METADATA 331 let flash_memory_regions: Vec<_> = memory
282 .memory
283 .iter() 332 .iter()
284 .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) 333 .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some())
285 .collect(); 334 .collect();
@@ -291,6 +340,8 @@ fn main() {
291 "Bank1" 340 "Bank1"
292 } else if region.name.starts_with("BANK_2") { 341 } else if region.name.starts_with("BANK_2") {
293 "Bank2" 342 "Bank2"
343 } else if region.name == "OTP" {
344 "Otp"
294 } else { 345 } else {
295 continue; 346 continue;
296 } 347 }
@@ -317,7 +368,7 @@ fn main() {
317 let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); 368 let region_type = format_ident!("{}", get_flash_region_type_name(region.name));
318 flash_regions.extend(quote! { 369 flash_regions.extend(quote! {
319 #[cfg(flash)] 370 #[cfg(flash)]
320 pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_internal::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>); 371 pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>);
321 }); 372 });
322 } 373 }
323 374
@@ -349,7 +400,7 @@ fn main() {
349 400
350 #[cfg(flash)] 401 #[cfg(flash)]
351 impl<'d, MODE> FlashLayout<'d, MODE> { 402 impl<'d, MODE> FlashLayout<'d, MODE> {
352 pub(crate) fn new(p: embassy_hal_internal::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { 403 pub(crate) fn new(p: embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>) -> Self {
353 Self { 404 Self {
354 #(#inits),*, 405 #(#inits),*,
355 _mode: core::marker::PhantomData, 406 _mode: core::marker::PhantomData,
@@ -475,9 +526,39 @@ fn main() {
475 } 526 }
476 527
477 impl<'a> ClockGen<'a> { 528 impl<'a> ClockGen<'a> {
529 fn parse_mul_div(name: &str) -> (&str, Frac) {
530 if name == "hse_div_rtcpre" {
531 return (name, Frac { num: 1, denom: 1 });
532 }
533
534 if let Some(i) = name.find("_div_") {
535 let n = &name[..i];
536 let val: u32 = name[i + 5..].parse().unwrap();
537 (n, Frac { num: 1, denom: val })
538 } else if let Some(i) = name.find("_mul_") {
539 let n = &name[..i];
540 let val: u32 = name[i + 5..].parse().unwrap();
541 (n, Frac { num: val, denom: 1 })
542 } else {
543 (name, Frac { num: 1, denom: 1 })
544 }
545 }
546
478 fn gen_clock(&mut self, peripheral: &str, name: &str) -> TokenStream { 547 fn gen_clock(&mut self, peripheral: &str, name: &str) -> TokenStream {
479 let clock_name = format_ident!("{}", name.to_ascii_lowercase()); 548 let name = name.to_ascii_lowercase();
480 self.clock_names.insert(name.to_ascii_lowercase()); 549 let (name, frac) = Self::parse_mul_div(&name);
550 let clock_name = format_ident!("{}", name);
551 self.clock_names.insert(name.to_string());
552
553 let mut muldiv = quote!();
554 if frac.num != 1 {
555 let val = frac.num;
556 muldiv.extend(quote!(* #val));
557 }
558 if frac.denom != 1 {
559 let val = frac.denom;
560 muldiv.extend(quote!(/ #val));
561 }
481 quote!(unsafe { 562 quote!(unsafe {
482 unwrap!( 563 unwrap!(
483 crate::rcc::get_freqs().#clock_name.to_hertz(), 564 crate::rcc::get_freqs().#clock_name.to_hertz(),
@@ -486,6 +567,7 @@ fn main() {
486 #peripheral, 567 #peripheral,
487 #name 568 #name
488 ) 569 )
570 #muldiv
489 }) 571 })
490 } 572 }
491 573
@@ -527,7 +609,11 @@ fn main() {
527 match crate::pac::RCC.#fieldset_name().read().#field_name() { 609 match crate::pac::RCC.#fieldset_name().read().#field_name() {
528 #match_arms 610 #match_arms
529 #[allow(unreachable_patterns)] 611 #[allow(unreachable_patterns)]
530 _ => unreachable!(), 612 _ => panic!(
613 "attempted to use peripheral '{}' but its clock mux is not set to a valid \
614 clock. Change 'config.rcc.mux' to another clock.",
615 #peripheral
616 )
531 } 617 }
532 } 618 }
533 } 619 }
@@ -598,6 +684,8 @@ fn main() {
598 PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(p.name, clock), 684 PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(p.name, clock),
599 }; 685 };
600 686
687 let bus_clock_frequency = clock_gen.gen_clock(p.name, &rcc.bus_clock);
688
601 // A refcount leak can result if the same field is shared by peripherals with different stop modes 689 // A refcount leak can result if the same field is shared by peripherals with different stop modes
602 // This condition should be checked in stm32-data 690 // This condition should be checked in stm32-data
603 let stop_mode = match rcc.stop_mode { 691 let stop_mode = match rcc.stop_mode {
@@ -611,6 +699,9 @@ fn main() {
611 fn frequency() -> crate::time::Hertz { 699 fn frequency() -> crate::time::Hertz {
612 #clock_frequency 700 #clock_frequency
613 } 701 }
702 fn bus_frequency() -> crate::time::Hertz {
703 #bus_clock_frequency
704 }
614 705
615 const RCC_INFO: crate::rcc::RccInfo = unsafe { 706 const RCC_INFO: crate::rcc::RccInfo = unsafe {
616 crate::rcc::RccInfo::new( 707 crate::rcc::RccInfo::new(
@@ -709,6 +800,16 @@ fn main() {
709 // Generate RCC 800 // Generate RCC
710 clock_gen.clock_names.insert("sys".to_string()); 801 clock_gen.clock_names.insert("sys".to_string());
711 clock_gen.clock_names.insert("rtc".to_string()); 802 clock_gen.clock_names.insert("rtc".to_string());
803
804 // STM32F4 SPI in I2S mode receives a clock input from the dedicated I2S PLL.
805 // For this, there is an additional clock MUX, which is not present in other
806 // peripherals and does not fit the current RCC structure of stm32-data.
807 if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") {
808 clock_gen.clock_names.insert("plli2s1_p".to_string());
809 clock_gen.clock_names.insert("plli2s1_q".to_string());
810 clock_gen.clock_names.insert("plli2s1_r".to_string());
811 }
812
712 let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect(); 813 let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect();
713 g.extend(quote! { 814 g.extend(quote! {
714 #[derive(Clone, Copy, Debug)] 815 #[derive(Clone, Copy, Debug)]
@@ -857,6 +958,7 @@ fn main() {
857 (("ltdc", "B7"), quote!(crate::ltdc::B7Pin)), 958 (("ltdc", "B7"), quote!(crate::ltdc::B7Pin)),
858 (("usb", "DP"), quote!(crate::usb::DpPin)), 959 (("usb", "DP"), quote!(crate::usb::DpPin)),
859 (("usb", "DM"), quote!(crate::usb::DmPin)), 960 (("usb", "DM"), quote!(crate::usb::DmPin)),
961 (("usb", "SOF"), quote!(crate::usb::SofPin)),
860 (("otg", "DP"), quote!(crate::usb::DpPin)), 962 (("otg", "DP"), quote!(crate::usb::DpPin)),
861 (("otg", "DM"), quote!(crate::usb::DmPin)), 963 (("otg", "DM"), quote!(crate::usb::DmPin)),
862 (("otg", "ULPI_CK"), quote!(crate::usb::UlpiClkPin)), 964 (("otg", "ULPI_CK"), quote!(crate::usb::UlpiClkPin)),
@@ -1015,6 +1117,9 @@ fn main() {
1015 (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)), 1117 (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)),
1016 (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)), 1118 (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)),
1017 (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), 1119 (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)),
1120 (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)),
1121 (("lptim", "CH2"), quote!(crate::lptim::Channel2Pin)),
1122 (("lptim", "OUT"), quote!(crate::lptim::OutputPin)),
1018 (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), 1123 (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)),
1019 (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), 1124 (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)),
1020 (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), 1125 (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)),
@@ -1024,7 +1129,7 @@ fn main() {
1024 (("sdmmc", "D4"), quote!(crate::sdmmc::D4Pin)), 1129 (("sdmmc", "D4"), quote!(crate::sdmmc::D4Pin)),
1025 (("sdmmc", "D5"), quote!(crate::sdmmc::D5Pin)), 1130 (("sdmmc", "D5"), quote!(crate::sdmmc::D5Pin)),
1026 (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), 1131 (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
1027 (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), 1132 (("sdmmc", "D7"), quote!(crate::sdmmc::D7Pin)),
1028 (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), 1133 (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
1029 (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)), 1134 (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)),
1030 (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)), 1135 (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)),
@@ -1049,6 +1154,117 @@ fn main() {
1049 (("octospi", "NCS"), quote!(crate::ospi::NSSPin)), 1154 (("octospi", "NCS"), quote!(crate::ospi::NSSPin)),
1050 (("octospi", "CLK"), quote!(crate::ospi::SckPin)), 1155 (("octospi", "CLK"), quote!(crate::ospi::SckPin)),
1051 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)), 1156 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)),
1157 (("octospim", "P1_IO0"), quote!(crate::ospi::D0Pin)),
1158 (("octospim", "P1_IO1"), quote!(crate::ospi::D1Pin)),
1159 (("octospim", "P1_IO2"), quote!(crate::ospi::D2Pin)),
1160 (("octospim", "P1_IO3"), quote!(crate::ospi::D3Pin)),
1161 (("octospim", "P1_IO4"), quote!(crate::ospi::D4Pin)),
1162 (("octospim", "P1_IO5"), quote!(crate::ospi::D5Pin)),
1163 (("octospim", "P1_IO6"), quote!(crate::ospi::D6Pin)),
1164 (("octospim", "P1_IO7"), quote!(crate::ospi::D7Pin)),
1165 (("octospim", "P1_DQS"), quote!(crate::ospi::DQSPin)),
1166 (("octospim", "P1_NCS"), quote!(crate::ospi::NSSPin)),
1167 (("octospim", "P1_CLK"), quote!(crate::ospi::SckPin)),
1168 (("octospim", "P1_NCLK"), quote!(crate::ospi::NckPin)),
1169 (("octospim", "P2_IO0"), quote!(crate::ospi::D0Pin)),
1170 (("octospim", "P2_IO1"), quote!(crate::ospi::D1Pin)),
1171 (("octospim", "P2_IO2"), quote!(crate::ospi::D2Pin)),
1172 (("octospim", "P2_IO3"), quote!(crate::ospi::D3Pin)),
1173 (("octospim", "P2_IO4"), quote!(crate::ospi::D4Pin)),
1174 (("octospim", "P2_IO5"), quote!(crate::ospi::D5Pin)),
1175 (("octospim", "P2_IO6"), quote!(crate::ospi::D6Pin)),
1176 (("octospim", "P2_IO7"), quote!(crate::ospi::D7Pin)),
1177 (("octospim", "P2_DQS"), quote!(crate::ospi::DQSPin)),
1178 (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)),
1179 (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)),
1180 (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)),
1181 (("xspi", "IO0"), quote!(crate::xspi::D0Pin)),
1182 (("xspi", "IO1"), quote!(crate::xspi::D1Pin)),
1183 (("xspi", "IO2"), quote!(crate::xspi::D2Pin)),
1184 (("xspi", "IO3"), quote!(crate::xspi::D3Pin)),
1185 (("xspi", "IO4"), quote!(crate::xspi::D4Pin)),
1186 (("xspi", "IO5"), quote!(crate::xspi::D5Pin)),
1187 (("xspi", "IO6"), quote!(crate::xspi::D6Pin)),
1188 (("xspi", "IO7"), quote!(crate::xspi::D7Pin)),
1189 (("xspi", "IO8"), quote!(crate::xspi::D8Pin)),
1190 (("xspi", "IO9"), quote!(crate::xspi::D9Pin)),
1191 (("xspi", "IO10"), quote!(crate::xspi::D10Pin)),
1192 (("xspi", "IO11"), quote!(crate::xspi::D11Pin)),
1193 (("xspi", "IO12"), quote!(crate::xspi::D12Pin)),
1194 (("xspi", "IO13"), quote!(crate::xspi::D13Pin)),
1195 (("xspi", "IO14"), quote!(crate::xspi::D14Pin)),
1196 (("xspi", "IO15"), quote!(crate::xspi::D15Pin)),
1197 (("xspi", "DQS0"), quote!(crate::xspi::DQS0Pin)),
1198 (("xspi", "DQS1"), quote!(crate::xspi::DQS1Pin)),
1199 (("xspi", "NCS1"), quote!(crate::xspi::NCSPin)),
1200 (("xspi", "NCS2"), quote!(crate::xspi::NCSPin)),
1201 (("xspi", "CLK"), quote!(crate::xspi::CLKPin)),
1202 (("xspi", "NCLK"), quote!(crate::xspi::NCLKPin)),
1203 (("xspim", "P1_IO0"), quote!(crate::xspi::D0Pin)),
1204 (("xspim", "P1_IO1"), quote!(crate::xspi::D1Pin)),
1205 (("xspim", "P1_IO2"), quote!(crate::xspi::D2Pin)),
1206 (("xspim", "P1_IO3"), quote!(crate::xspi::D3Pin)),
1207 (("xspim", "P1_IO4"), quote!(crate::xspi::D4Pin)),
1208 (("xspim", "P1_IO5"), quote!(crate::xspi::D5Pin)),
1209 (("xspim", "P1_IO6"), quote!(crate::xspi::D6Pin)),
1210 (("xspim", "P1_IO7"), quote!(crate::xspi::D7Pin)),
1211 (("xspim", "P1_IO8"), quote!(crate::xspi::D8Pin)),
1212 (("xspim", "P1_IO9"), quote!(crate::xspi::D9Pin)),
1213 (("xspim", "P1_IO10"), quote!(crate::xspi::D10Pin)),
1214 (("xspim", "P1_IO11"), quote!(crate::xspi::D11Pin)),
1215 (("xspim", "P1_IO12"), quote!(crate::xspi::D12Pin)),
1216 (("xspim", "P1_IO13"), quote!(crate::xspi::D13Pin)),
1217 (("xspim", "P1_IO14"), quote!(crate::xspi::D14Pin)),
1218 (("xspim", "P1_IO15"), quote!(crate::xspi::D15Pin)),
1219 (("xspim", "P1_DQS0"), quote!(crate::xspi::DQS0Pin)),
1220 (("xspim", "P1_DQS1"), quote!(crate::xspi::DQS1Pin)),
1221 (("xspim", "P1_NCS1"), quote!(crate::xspi::NCSPin)),
1222 (("xspim", "P1_NCS2"), quote!(crate::xspi::NCSPin)),
1223 (("xspim", "P1_CLK"), quote!(crate::xspi::CLKPin)),
1224 (("xspim", "P1_NCLK"), quote!(crate::xspi::NCLKPin)),
1225 (("xspim", "P2_IO0"), quote!(crate::xspi::D0Pin)),
1226 (("xspim", "P2_IO1"), quote!(crate::xspi::D1Pin)),
1227 (("xspim", "P2_IO2"), quote!(crate::xspi::D2Pin)),
1228 (("xspim", "P2_IO3"), quote!(crate::xspi::D3Pin)),
1229 (("xspim", "P2_IO4"), quote!(crate::xspi::D4Pin)),
1230 (("xspim", "P2_IO5"), quote!(crate::xspi::D5Pin)),
1231 (("xspim", "P2_IO6"), quote!(crate::xspi::D6Pin)),
1232 (("xspim", "P2_IO7"), quote!(crate::xspi::D7Pin)),
1233 (("xspim", "P2_IO8"), quote!(crate::xspi::D8Pin)),
1234 (("xspim", "P2_IO9"), quote!(crate::xspi::D9Pin)),
1235 (("xspim", "P2_IO10"), quote!(crate::xspi::D10Pin)),
1236 (("xspim", "P2_IO11"), quote!(crate::xspi::D11Pin)),
1237 (("xspim", "P2_IO12"), quote!(crate::xspi::D12Pin)),
1238 (("xspim", "P2_IO13"), quote!(crate::xspi::D13Pin)),
1239 (("xspim", "P2_IO14"), quote!(crate::xspi::D14Pin)),
1240 (("xspim", "P2_IO15"), quote!(crate::xspi::D15Pin)),
1241 (("xspim", "P2_DQS0"), quote!(crate::xspi::DQS0Pin)),
1242 (("xspim", "P2_DQS1"), quote!(crate::xspi::DQS1Pin)),
1243 (("xspim", "P2_NCS1"), quote!(crate::xspi::NCSPin)),
1244 (("xspim", "P2_NCS2"), quote!(crate::xspi::NCSPin)),
1245 (("xspim", "P2_CLK"), quote!(crate::xspi::CLKPin)),
1246 (("xspim", "P2_NCLK"), quote!(crate::xspi::NCLKPin)),
1247 (("hspi", "IO0"), quote!(crate::hspi::D0Pin)),
1248 (("hspi", "IO1"), quote!(crate::hspi::D1Pin)),
1249 (("hspi", "IO2"), quote!(crate::hspi::D2Pin)),
1250 (("hspi", "IO3"), quote!(crate::hspi::D3Pin)),
1251 (("hspi", "IO4"), quote!(crate::hspi::D4Pin)),
1252 (("hspi", "IO5"), quote!(crate::hspi::D5Pin)),
1253 (("hspi", "IO6"), quote!(crate::hspi::D6Pin)),
1254 (("hspi", "IO7"), quote!(crate::hspi::D7Pin)),
1255 (("hspi", "IO8"), quote!(crate::hspi::D8Pin)),
1256 (("hspi", "IO9"), quote!(crate::hspi::D9Pin)),
1257 (("hspi", "IO10"), quote!(crate::hspi::D10Pin)),
1258 (("hspi", "IO11"), quote!(crate::hspi::D11Pin)),
1259 (("hspi", "IO12"), quote!(crate::hspi::D12Pin)),
1260 (("hspi", "IO13"), quote!(crate::hspi::D13Pin)),
1261 (("hspi", "IO14"), quote!(crate::hspi::D14Pin)),
1262 (("hspi", "IO15"), quote!(crate::hspi::D15Pin)),
1263 (("hspi", "DQS0"), quote!(crate::hspi::DQS0Pin)),
1264 (("hspi", "DQS1"), quote!(crate::hspi::DQS1Pin)),
1265 (("hspi", "NCS"), quote!(crate::hspi::NSSPin)),
1266 (("hspi", "CLK"), quote!(crate::hspi::SckPin)),
1267 (("hspi", "NCLK"), quote!(crate::hspi::NckPin)),
1052 (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)), 1268 (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)),
1053 (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)), 1269 (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)),
1054 (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)), 1270 (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)),
@@ -1081,6 +1297,8 @@ fn main() {
1081 (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)), 1297 (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)),
1082 (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)), 1298 (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)),
1083 (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)), 1299 (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)),
1300 (("dac", "OUT1"), quote!(crate::dac::DacPin<Ch1>)),
1301 (("dac", "OUT2"), quote!(crate::dac::DacPin<Ch2>)),
1084 ].into(); 1302 ].into();
1085 1303
1086 for p in METADATA.peripherals { 1304 for p in METADATA.peripherals {
@@ -1106,6 +1324,41 @@ fn main() {
1106 peri = format_ident!("{}", pin.signal.replace('_', "")); 1324 peri = format_ident!("{}", pin.signal.replace('_', ""));
1107 } 1325 }
1108 1326
1327 // OCTOSPIM is special
1328 if p.name == "OCTOSPIM" {
1329 // Some chips have OCTOSPIM but not OCTOSPI2.
1330 if METADATA.peripherals.iter().any(|p| p.name == "OCTOSPI2") {
1331 peri = format_ident!("{}", "OCTOSPI2");
1332 g.extend(quote! {
1333 pin_trait_impl!(#tr, #peri, #pin_name, #af);
1334 });
1335 }
1336 peri = format_ident!("{}", "OCTOSPI1");
1337 }
1338
1339 // XSPIM is special
1340 if p.name == "XSPIM" {
1341 if pin.signal.starts_with("P1") {
1342 peri = format_ident!("{}", "XSPI1");
1343 } else if pin.signal.starts_with("P2") {
1344 peri = format_ident!("{}", "XSPI2");
1345 } else {
1346 panic! {"malformed XSPIM pin: {:?}", pin}
1347 }
1348 }
1349
1350 // XSPI NCS pin to CSSEL mapping
1351 if pin.signal.ends_with("NCS1") {
1352 g.extend(quote! {
1353 sel_trait_impl!(crate::xspi::NCSEither, #peri, #pin_name, 0);
1354 })
1355 }
1356 if pin.signal.ends_with("NCS2") {
1357 g.extend(quote! {
1358 sel_trait_impl!(crate::xspi::NCSEither, #peri, #pin_name, 1);
1359 })
1360 }
1361
1109 g.extend(quote! { 1362 g.extend(quote! {
1110 pin_trait_impl!(#tr, #peri, #pin_name, #af); 1363 pin_trait_impl!(#tr, #peri, #pin_name, #af);
1111 }) 1364 })
@@ -1158,6 +1411,18 @@ fn main() {
1158 g.extend(quote! { 1411 g.extend(quote! {
1159 impl_opamp_vp_pin!( #peri, #pin_name, #ch); 1412 impl_opamp_vp_pin!( #peri, #pin_name, #ch);
1160 }) 1413 })
1414 } else if pin.signal.starts_with("VINM") {
1415 // Impl NonInvertingPin for the VINM* signals ( VINM0, VINM1, etc)
1416 // STM32G4
1417 let peri = format_ident!("{}", p.name);
1418 let pin_name = format_ident!("{}", pin.pin);
1419 let ch: Result<u8, _> = pin.signal.strip_prefix("VINM").unwrap().parse();
1420
1421 if let Ok(ch) = ch {
1422 g.extend(quote! {
1423 impl_opamp_vn_pin!( #peri, #pin_name, #ch);
1424 })
1425 }
1161 } else if pin.signal == "VOUT" { 1426 } else if pin.signal == "VOUT" {
1162 // Impl OutputPin for the VOUT pin 1427 // Impl OutputPin for the VOUT pin
1163 let peri = format_ident!("{}", p.name); 1428 let peri = format_ident!("{}", p.name);
@@ -1168,14 +1433,14 @@ fn main() {
1168 } 1433 }
1169 } 1434 }
1170 1435
1171 // DAC is special 1436 if regs.kind == "spdifrx" {
1172 if regs.kind == "dac" {
1173 let peri = format_ident!("{}", p.name); 1437 let peri = format_ident!("{}", p.name);
1174 let pin_name = format_ident!("{}", pin.pin); 1438 let pin_name = format_ident!("{}", pin.pin);
1175 let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap(); 1439 let af = pin.af.unwrap_or(0);
1440 let sel: u8 = pin.signal.strip_prefix("IN").unwrap().parse().unwrap();
1176 1441
1177 g.extend(quote! { 1442 g.extend(quote! {
1178 impl_dac_pin!( #peri, #pin_name, #ch); 1443 impl_spdifrx_pin!( #peri, #pin_name, #af, #sel);
1179 }) 1444 })
1180 } 1445 }
1181 } 1446 }
@@ -1185,13 +1450,12 @@ fn main() {
1185 // ======== 1450 // ========
1186 // Generate dma_trait_impl! 1451 // Generate dma_trait_impl!
1187 1452
1188 let signals: HashMap<_, _> = [ 1453 let mut signals: HashMap<_, _> = [
1189 // (kind, signal) => trait 1454 // (kind, signal) => trait
1190 (("adc", "ADC"), quote!(crate::adc::RxDma)), 1455 (("adc", "ADC"), quote!(crate::adc::RxDma)),
1191 (("adc", "ADC1"), quote!(crate::adc::RxDma)), 1456 (("adc", "ADC1"), quote!(crate::adc::RxDma)),
1192 (("adc", "ADC2"), quote!(crate::adc::RxDma)), 1457 (("adc", "ADC2"), quote!(crate::adc::RxDma)),
1193 (("adc", "ADC3"), quote!(crate::adc::RxDma)), 1458 (("adc", "ADC3"), quote!(crate::adc::RxDma)),
1194 (("adc", "ADC4"), quote!(crate::adc::RxDma)),
1195 (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), 1459 (("ucpd", "RX"), quote!(crate::ucpd::RxDma)),
1196 (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), 1460 (("ucpd", "TX"), quote!(crate::ucpd::TxDma)),
1197 (("usart", "RX"), quote!(crate::usart::RxDma)), 1461 (("usart", "RX"), quote!(crate::usart::RxDma)),
@@ -1202,6 +1466,7 @@ fn main() {
1202 (("sai", "B"), quote!(crate::sai::Dma<B>)), 1466 (("sai", "B"), quote!(crate::sai::Dma<B>)),
1203 (("spi", "RX"), quote!(crate::spi::RxDma)), 1467 (("spi", "RX"), quote!(crate::spi::RxDma)),
1204 (("spi", "TX"), quote!(crate::spi::TxDma)), 1468 (("spi", "TX"), quote!(crate::spi::TxDma)),
1469 (("spdifrx", "RX"), quote!(crate::spdifrx::Dma)),
1205 (("i2c", "RX"), quote!(crate::i2c::RxDma)), 1470 (("i2c", "RX"), quote!(crate::i2c::RxDma)),
1206 (("i2c", "TX"), quote!(crate::i2c::TxDma)), 1471 (("i2c", "TX"), quote!(crate::i2c::TxDma)),
1207 (("dcmi", "DCMI"), quote!(crate::dcmi::FrameDma)), 1472 (("dcmi", "DCMI"), quote!(crate::dcmi::FrameDma)),
@@ -1210,8 +1475,9 @@ fn main() {
1210 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 1475 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
1211 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), 1476 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
1212 (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)), 1477 (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)),
1213 (("dac", "CH1"), quote!(crate::dac::DacDma1)), 1478 (("hspi", "HSPI1"), quote!(crate::hspi::HspiDma)),
1214 (("dac", "CH2"), quote!(crate::dac::DacDma2)), 1479 (("dac", "CH1"), quote!(crate::dac::Dma<Ch1>)),
1480 (("dac", "CH2"), quote!(crate::dac::Dma<Ch2>)),
1215 (("timer", "UP"), quote!(crate::timer::UpDma)), 1481 (("timer", "UP"), quote!(crate::timer::UpDma)),
1216 (("hash", "IN"), quote!(crate::hash::Dma)), 1482 (("hash", "IN"), quote!(crate::hash::Dma)),
1217 (("cryp", "IN"), quote!(crate::cryp::DmaIn)), 1483 (("cryp", "IN"), quote!(crate::cryp::DmaIn)),
@@ -1225,6 +1491,19 @@ fn main() {
1225 ] 1491 ]
1226 .into(); 1492 .into();
1227 1493
1494 if chip_name.starts_with("stm32u5") {
1495 signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4));
1496 } else {
1497 signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma));
1498 }
1499
1500 if chip_name.starts_with("stm32g4") {
1501 let line_number = chip_name.chars().skip(8).next().unwrap();
1502 if line_number == '3' || line_number == '4' {
1503 signals.insert(("adc", "ADC5"), quote!(crate::adc::RxDma));
1504 }
1505 }
1506
1228 for p in METADATA.peripherals { 1507 for p in METADATA.peripherals {
1229 if let Some(regs) = &p.registers { 1508 if let Some(regs) = &p.registers {
1230 // FIXME: stm32u5a crash on Cordic driver 1509 // FIXME: stm32u5a crash on Cordic driver
@@ -1290,36 +1569,13 @@ fn main() {
1290 for e in rcc_registers.ir.enums { 1569 for e in rcc_registers.ir.enums {
1291 fn is_rcc_name(e: &str) -> bool { 1570 fn is_rcc_name(e: &str) -> bool {
1292 match e { 1571 match e {
1293 "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true, 1572 "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" => true,
1294 "Timpre" | "Pllrclkpre" => false, 1573 "Timpre" | "Pllrclkpre" => false,
1295 e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, 1574 e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
1296 _ => false, 1575 _ => false,
1297 } 1576 }
1298 } 1577 }
1299 1578
1300 #[derive(Copy, Clone, Debug)]
1301 struct Frac {
1302 num: u32,
1303 denom: u32,
1304 }
1305
1306 impl Frac {
1307 fn simplify(self) -> Self {
1308 let d = gcd(self.num, self.denom);
1309 Self {
1310 num: self.num / d,
1311 denom: self.denom / d,
1312 }
1313 }
1314 }
1315
1316 fn gcd(a: u32, b: u32) -> u32 {
1317 if b == 0 {
1318 return a;
1319 }
1320 gcd(b, a % b)
1321 }
1322
1323 fn parse_num(n: &str) -> Result<Frac, ()> { 1579 fn parse_num(n: &str) -> Result<Frac, ()> {
1324 for prefix in ["DIV", "MUL"] { 1580 for prefix in ["DIV", "MUL"] {
1325 if let Some(n) = n.strip_prefix(prefix) { 1581 if let Some(n) = n.strip_prefix(prefix) {
@@ -1402,8 +1658,7 @@ fn main() {
1402 let mut pins_table: Vec<Vec<String>> = Vec::new(); 1658 let mut pins_table: Vec<Vec<String>> = Vec::new();
1403 let mut adc_table: Vec<Vec<String>> = Vec::new(); 1659 let mut adc_table: Vec<Vec<String>> = Vec::new();
1404 1660
1405 for m in METADATA 1661 for m in memory
1406 .memory
1407 .iter() 1662 .iter()
1408 .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some()) 1663 .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some())
1409 { 1664 {
@@ -1419,43 +1674,42 @@ fn main() {
1419 let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32; 1674 let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32;
1420 let gpio_stride = 0x400; 1675 let gpio_stride = 0x400;
1421 1676
1422 for p in METADATA.peripherals { 1677 for pin in METADATA.pins {
1423 if let Some(regs) = &p.registers { 1678 let port_letter = pin.name.chars().nth(1).unwrap();
1424 if regs.kind == "gpio" { 1679 let pname = format!("GPIO{}", port_letter);
1425 let port_letter = p.name.chars().nth(4).unwrap(); 1680 let p = METADATA.peripherals.iter().find(|p| p.name == pname).unwrap();
1426 assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride); 1681 assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride);
1427 let port_num = (p.address as u32 - gpio_base) / gpio_stride; 1682 let port_num = (p.address as u32 - gpio_base) / gpio_stride;
1428 1683 let pin_num: u32 = pin.name[2..].parse().unwrap();
1429 for pin_num in 0u32..16 { 1684
1430 let pin_name = format!("P{}{}", port_letter, pin_num); 1685 pins_table.push(vec![
1431 1686 pin.name.to_string(),
1432 pins_table.push(vec![ 1687 p.name.to_string(),
1433 pin_name.clone(), 1688 port_num.to_string(),
1434 p.name.to_string(), 1689 pin_num.to_string(),
1435 port_num.to_string(), 1690 format!("EXTI{}", pin_num),
1436 pin_num.to_string(), 1691 ]);
1437 format!("EXTI{}", pin_num), 1692
1438 ]); 1693 // If we have the split pins, we need to do a little extra work:
1439 1694 // Add the "_C" variant to the table. The solution is not optimal, though.
1440 // If we have the split pins, we need to do a little extra work: 1695 // Adding them only when the corresponding GPIOx also appears.
1441 // Add the "_C" variant to the table. The solution is not optimal, though. 1696 // This should avoid unintended side-effects as much as possible.
1442 // Adding them only when the corresponding GPIOx also appears. 1697 #[cfg(feature = "_split-pins-enabled")]
1443 // This should avoid unintended side-effects as much as possible. 1698 for split_feature in &split_features {
1444 #[cfg(feature = "_split-pins-enabled")] 1699 if split_feature.pin_name_without_c == pin.name {
1445 for split_feature in &split_features { 1700 pins_table.push(vec![
1446 if split_feature.pin_name_without_c == pin_name { 1701 split_feature.pin_name_with_c.to_string(),
1447 pins_table.push(vec![ 1702 p.name.to_string(),
1448 split_feature.pin_name_with_c.to_string(), 1703 port_num.to_string(),
1449 p.name.to_string(), 1704 pin_num.to_string(),
1450 port_num.to_string(), 1705 format!("EXTI{}", pin_num),
1451 pin_num.to_string(), 1706 ]);
1452 format!("EXTI{}", pin_num),
1453 ]);
1454 }
1455 }
1456 }
1457 } 1707 }
1708 }
1709 }
1458 1710
1711 for p in METADATA.peripherals {
1712 if let Some(regs) = &p.registers {
1459 if regs.kind == "adc" { 1713 if regs.kind == "adc" {
1460 let adc_num = p.name.strip_prefix("ADC").unwrap(); 1714 let adc_num = p.name.strip_prefix("ADC").unwrap();
1461 let mut adc_common = None; 1715 let mut adc_common = None;
@@ -1494,6 +1748,36 @@ fn main() {
1494 .flat_map(|p| &p.registers) 1748 .flat_map(|p| &p.registers)
1495 .any(|p| p.kind == "dmamux"); 1749 .any(|p| p.kind == "dmamux");
1496 1750
1751 let mut dma_irqs: BTreeMap<&str, Vec<String>> = BTreeMap::new();
1752
1753 for p in METADATA.peripherals {
1754 if let Some(r) = &p.registers {
1755 if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" {
1756 for irq in p.interrupts {
1757 let ch_name = format!("{}_{}", p.name, irq.signal);
1758 let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap();
1759
1760 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1761 if has_dmamux && ch.dmamux.is_none() {
1762 continue;
1763 }
1764
1765 dma_irqs.entry(irq.interrupt).or_default().push(ch_name);
1766 }
1767 }
1768 }
1769 }
1770
1771 #[cfg(feature = "_dual-core")]
1772 let mut dma_ch_to_irq: BTreeMap<&str, Vec<String>> = BTreeMap::new();
1773
1774 #[cfg(feature = "_dual-core")]
1775 for (irq, channels) in &dma_irqs {
1776 for channel in channels {
1777 dma_ch_to_irq.entry(channel).or_default().push(irq.to_string());
1778 }
1779 }
1780
1497 for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() { 1781 for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() {
1498 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. 1782 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1499 if has_dmamux && ch.dmamux.is_none() { 1783 if has_dmamux && ch.dmamux.is_none() {
@@ -1502,6 +1786,16 @@ fn main() {
1502 1786
1503 let name = format_ident!("{}", ch.name); 1787 let name = format_ident!("{}", ch.name);
1504 let idx = ch_idx as u8; 1788 let idx = ch_idx as u8;
1789 #[cfg(feature = "_dual-core")]
1790 let irq = {
1791 let irq_name = if let Some(x) = &dma_ch_to_irq.get(ch.name) {
1792 format_ident!("{}", x.get(0).unwrap())
1793 } else {
1794 panic!("failed to find dma interrupt")
1795 };
1796 quote!(crate::pac::Interrupt::#irq_name)
1797 };
1798
1505 g.extend(quote!(dma_channel_impl!(#name, #idx);)); 1799 g.extend(quote!(dma_channel_impl!(#name, #idx);));
1506 1800
1507 let dma = format_ident!("{}", ch.dma); 1801 let dma = format_ident!("{}", ch.dma);
@@ -1532,10 +1826,20 @@ fn main() {
1532 None => quote!(), 1826 None => quote!(),
1533 }; 1827 };
1534 1828
1829 #[cfg(not(feature = "_dual-core"))]
1830 dmas.extend(quote! {
1831 crate::dma::ChannelInfo {
1832 dma: #dma_info,
1833 num: #ch_num,
1834 #dmamux
1835 },
1836 });
1837 #[cfg(feature = "_dual-core")]
1535 dmas.extend(quote! { 1838 dmas.extend(quote! {
1536 crate::dma::ChannelInfo { 1839 crate::dma::ChannelInfo {
1537 dma: #dma_info, 1840 dma: #dma_info,
1538 num: #ch_num, 1841 num: #ch_num,
1842 irq: #irq,
1539 #dmamux 1843 #dmamux
1540 }, 1844 },
1541 }); 1845 });
@@ -1544,26 +1848,6 @@ fn main() {
1544 // ======== 1848 // ========
1545 // Generate DMA IRQs. 1849 // Generate DMA IRQs.
1546 1850
1547 let mut dma_irqs: BTreeMap<&str, Vec<String>> = BTreeMap::new();
1548
1549 for p in METADATA.peripherals {
1550 if let Some(r) = &p.registers {
1551 if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" {
1552 for irq in p.interrupts {
1553 let ch_name = format!("{}_{}", p.name, irq.signal);
1554 let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap();
1555
1556 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1557 if has_dmamux && ch.dmamux.is_none() {
1558 continue;
1559 }
1560
1561 dma_irqs.entry(irq.interrupt).or_default().push(ch_name);
1562 }
1563 }
1564 }
1565 }
1566
1567 let dma_irqs: TokenStream = dma_irqs 1851 let dma_irqs: TokenStream = dma_irqs
1568 .iter() 1852 .iter()
1569 .map(|(irq, channels)| { 1853 .map(|(irq, channels)| {
@@ -1589,6 +1873,100 @@ fn main() {
1589 pub(crate) const DMA_CHANNELS: &[crate::dma::ChannelInfo] = &[#dmas]; 1873 pub(crate) const DMA_CHANNELS: &[crate::dma::ChannelInfo] = &[#dmas];
1590 }); 1874 });
1591 1875
1876 // ========
1877 // Generate gpio_block() function
1878
1879 let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as usize;
1880 let gpio_stride = 0x400 as usize;
1881
1882 for p in METADATA.peripherals {
1883 if let Some(bi) = &p.registers {
1884 if bi.kind == "gpio" {
1885 assert_eq!(0, (p.address as usize - gpio_base) % gpio_stride);
1886 }
1887 }
1888 }
1889
1890 g.extend(quote!(
1891 pub fn gpio_block(n: usize) -> crate::pac::gpio::Gpio {{
1892 unsafe {{ crate::pac::gpio::Gpio::from_ptr((#gpio_base + #gpio_stride*n) as _) }}
1893 }}
1894 ));
1895
1896 // ========
1897 // Generate flash constants
1898
1899 let flash_regions: Vec<&MemoryRegion> = memory
1900 .iter()
1901 .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_"))
1902 .collect();
1903 let first_flash = flash_regions.first().unwrap();
1904 let total_flash_size = flash_regions
1905 .iter()
1906 .map(|x| x.size)
1907 .reduce(|acc, item| acc + item)
1908 .unwrap();
1909 let write_sizes: HashSet<_> = flash_regions
1910 .iter()
1911 .map(|r| r.settings.as_ref().unwrap().write_size)
1912 .collect();
1913 assert_eq!(1, write_sizes.len());
1914
1915 let flash_base = first_flash.address as usize;
1916 let total_flash_size = total_flash_size as usize;
1917 let write_size = (*write_sizes.iter().next().unwrap()) as usize;
1918
1919 g.extend(quote!(
1920 pub const FLASH_BASE: usize = #flash_base;
1921 pub const FLASH_SIZE: usize = #total_flash_size;
1922 pub const WRITE_SIZE: usize = #write_size;
1923 ));
1924
1925 // ========
1926 // Generate EEPROM constants
1927
1928 cfgs.declare("eeprom");
1929
1930 let eeprom_memory_regions: Vec<&MemoryRegion> =
1931 memory.iter().filter(|x| x.kind == MemoryRegionKind::Eeprom).collect();
1932
1933 if !eeprom_memory_regions.is_empty() {
1934 cfgs.enable("eeprom");
1935
1936 let mut sorted_eeprom_regions = eeprom_memory_regions.clone();
1937 sorted_eeprom_regions.sort_by_key(|r| r.address);
1938
1939 let first_eeprom_address = sorted_eeprom_regions[0].address;
1940 let mut total_eeprom_size = 0;
1941 let mut current_expected_address = first_eeprom_address;
1942
1943 for region in sorted_eeprom_regions.iter() {
1944 if region.address != current_expected_address {
1945 // For STM32L0 and STM32L1, EEPROM regions (if multiple) are expected to be contiguous.
1946 // If they are not, this indicates an issue with the chip metadata or an unsupported configuration.
1947 panic!(
1948 "EEPROM regions for chip {} are not contiguous, which is unexpected for L0/L1 series. \
1949 First region: '{}' at {:#X}. Found next non-contiguous region: '{}' at {:#X}. \
1950 Please verify chip metadata. Embassy currently assumes contiguous EEPROM for these series.",
1951 chip_name, sorted_eeprom_regions[0].name, first_eeprom_address, region.name, region.address
1952 );
1953 }
1954 total_eeprom_size += region.size;
1955 current_expected_address += region.size;
1956 }
1957
1958 let eeprom_base_usize = first_eeprom_address as usize;
1959 let total_eeprom_size_usize = total_eeprom_size as usize;
1960
1961 g.extend(quote! {
1962 pub const EEPROM_BASE: usize = #eeprom_base_usize;
1963 pub const EEPROM_SIZE: usize = #total_eeprom_size_usize;
1964 });
1965 }
1966
1967 // ========
1968 // Generate macro-tables
1969
1592 for irq in METADATA.interrupts { 1970 for irq in METADATA.interrupts {
1593 let name = irq.name.to_ascii_uppercase(); 1971 let name = irq.name.to_ascii_uppercase();
1594 interrupts_table.push(vec![name.clone()]); 1972 interrupts_table.push(vec![name.clone()]);
@@ -1683,6 +2061,11 @@ fn main() {
1683 } 2061 }
1684 2062
1685 println!("cargo:rerun-if-changed=build.rs"); 2063 println!("cargo:rerun-if-changed=build.rs");
2064
2065 if cfg!(feature = "memory-x") {
2066 gen_memory_x(memory, out_dir);
2067 println!("cargo:rustc-link-search={}", out_dir.display());
2068 }
1686} 2069}
1687 2070
1688enum GetOneError { 2071enum GetOneError {
@@ -1768,3 +2151,97 @@ fn rustfmt(path: impl AsRef<Path>) {
1768 } 2151 }
1769 } 2152 }
1770} 2153}
2154
2155fn gen_memory_x(memory: &[MemoryRegion], out_dir: &Path) {
2156 let mut memory_x = String::new();
2157
2158 let flash = get_memory_range(memory, MemoryRegionKind::Flash);
2159 let ram = get_memory_range(memory, MemoryRegionKind::Ram);
2160
2161 write!(memory_x, "MEMORY\n{{\n").unwrap();
2162 writeln!(
2163 memory_x,
2164 " FLASH : ORIGIN = 0x{:08x}, LENGTH = {:>4}K /* {} */",
2165 flash.0,
2166 flash.1 / 1024,
2167 flash.2
2168 )
2169 .unwrap();
2170 writeln!(
2171 memory_x,
2172 " RAM : ORIGIN = 0x{:08x}, LENGTH = {:>4}K /* {} */",
2173 ram.0,
2174 ram.1 / 1024,
2175 ram.2
2176 )
2177 .unwrap();
2178 write!(memory_x, "}}").unwrap();
2179
2180 std::fs::write(out_dir.join("memory.x"), memory_x.as_bytes()).unwrap();
2181}
2182
2183fn get_memory_range(memory: &[MemoryRegion], kind: MemoryRegionKind) -> (u32, u32, String) {
2184 let mut mems: Vec<_> = memory.iter().filter(|m| m.kind == kind && m.size != 0).collect();
2185 mems.sort_by_key(|m| m.address);
2186
2187 let mut start = u32::MAX;
2188 let mut end = u32::MAX;
2189 let mut names = Vec::new();
2190 let mut best: Option<(u32, u32, String)> = None;
2191 for m in mems {
2192 if !mem_filter(&METADATA.name, &m.name) {
2193 continue;
2194 }
2195
2196 if m.address != end {
2197 names = Vec::new();
2198 start = m.address;
2199 end = m.address;
2200 }
2201
2202 end += m.size;
2203 names.push(m.name.to_string());
2204
2205 if best.is_none() || end - start > best.as_ref().unwrap().1 {
2206 best = Some((start, end - start, names.join(" + ")));
2207 }
2208 }
2209
2210 best.unwrap()
2211}
2212
2213fn mem_filter(chip: &str, region: &str) -> bool {
2214 // in STM32WB, SRAM2a/SRAM2b are reserved for the radio core.
2215 if chip.starts_with("STM32WB")
2216 && !chip.starts_with("STM32WBA")
2217 && !chip.starts_with("STM32WB0")
2218 && region.starts_with("SRAM2")
2219 {
2220 return false;
2221 }
2222
2223 true
2224}
2225
2226#[derive(Copy, Clone, Debug)]
2227struct Frac {
2228 num: u32,
2229 denom: u32,
2230}
2231
2232impl Frac {
2233 fn simplify(self) -> Self {
2234 let d = gcd(self.num, self.denom);
2235 Self {
2236 num: self.num / d,
2237 denom: self.denom / d,
2238 }
2239 }
2240}
2241
2242fn gcd(a: u32, b: u32) -> u32 {
2243 if b == 0 {
2244 return a;
2245 }
2246 gcd(b, a % b)
2247}
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
new file mode 100644
index 000000000..936ad7413
--- /dev/null
+++ b/embassy-stm32/src/adc/c0.rs
@@ -0,0 +1,467 @@
1use pac::adc::vals::Scandir;
2#[allow(unused)]
3use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc;
5
6use super::{
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
8};
9use crate::dma::Transfer;
10use crate::time::Hertz;
11use crate::{pac, rcc, Peri};
12
13/// Default VREF voltage used for sample conversion to millivolts.
14pub const VREF_DEFAULT_MV: u32 = 3300;
15/// VREF voltage used for factory calibration of VREFINTCAL register.
16pub const VREF_CALIB_MV: u32 = 3300;
17
18const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25);
19
20const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20;
21
22const TEMP_CHANNEL: u8 = 9;
23const VREF_CHANNEL: u8 = 10;
24
25const NUM_HW_CHANNELS: u8 = 22;
26const CHSELR_SQ_SIZE: usize = 8;
27const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
28const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
29
30// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs,
31// this currently cannot be modeled with stm32-data,
32// so these are available from the software on all ADCs.
33/// Internal voltage reference channel.
34pub struct VrefInt;
35impl<T: Instance> AdcChannel<T> for VrefInt {}
36impl<T: Instance> SealedAdcChannel<T> for VrefInt {
37 fn channel(&self) -> u8 {
38 VREF_CHANNEL
39 }
40}
41
42/// Internal temperature channel.
43pub struct Temperature;
44impl<T: Instance> AdcChannel<T> for Temperature {}
45impl<T: Instance> SealedAdcChannel<T> for Temperature {
46 fn channel(&self) -> u8 {
47 TEMP_CHANNEL
48 }
49}
50
51#[derive(Debug)]
52pub enum Prescaler {
53 NotDivided,
54 DividedBy2,
55 DividedBy4,
56 DividedBy6,
57 DividedBy8,
58 DividedBy10,
59 DividedBy12,
60 DividedBy16,
61 DividedBy32,
62 DividedBy64,
63 DividedBy128,
64 DividedBy256,
65}
66
67impl Prescaler {
68 fn from_ker_ck(frequency: Hertz) -> Self {
69 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
70 match raw_prescaler {
71 0 => Self::NotDivided,
72 1 => Self::DividedBy2,
73 2..=3 => Self::DividedBy4,
74 4..=5 => Self::DividedBy6,
75 6..=7 => Self::DividedBy8,
76 8..=9 => Self::DividedBy10,
77 10..=11 => Self::DividedBy12,
78 _ => unimplemented!(),
79 }
80 }
81
82 #[allow(unused)]
83 fn divisor(&self) -> u32 {
84 match self {
85 Prescaler::NotDivided => 1,
86 Prescaler::DividedBy2 => 2,
87 Prescaler::DividedBy4 => 4,
88 Prescaler::DividedBy6 => 6,
89 Prescaler::DividedBy8 => 8,
90 Prescaler::DividedBy10 => 10,
91 Prescaler::DividedBy12 => 12,
92 Prescaler::DividedBy16 => 16,
93 Prescaler::DividedBy32 => 32,
94 Prescaler::DividedBy64 => 64,
95 Prescaler::DividedBy128 => 128,
96 Prescaler::DividedBy256 => 256,
97 }
98 }
99
100 fn presc(&self) -> Presc {
101 match self {
102 Prescaler::NotDivided => Presc::DIV1,
103 Prescaler::DividedBy2 => Presc::DIV2,
104 Prescaler::DividedBy4 => Presc::DIV4,
105 Prescaler::DividedBy6 => Presc::DIV6,
106 Prescaler::DividedBy8 => Presc::DIV8,
107 Prescaler::DividedBy10 => Presc::DIV10,
108 Prescaler::DividedBy12 => Presc::DIV12,
109 Prescaler::DividedBy16 => Presc::DIV16,
110 Prescaler::DividedBy32 => Presc::DIV32,
111 Prescaler::DividedBy64 => Presc::DIV64,
112 Prescaler::DividedBy128 => Presc::DIV128,
113 Prescaler::DividedBy256 => Presc::DIV256,
114 }
115 }
116}
117
118#[cfg(feature = "defmt")]
119impl<'a> defmt::Format for Prescaler {
120 fn format(&self, fmt: defmt::Formatter) {
121 match self {
122 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"),
123 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"),
124 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"),
125 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"),
126 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"),
127 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"),
128 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"),
129 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"),
130 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"),
131 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"),
132 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"),
133 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"),
134 }
135 }
136}
137
138/// Number of samples used for averaging.
139/// TODO: Implement hardware averaging setting.
140#[allow(unused)]
141pub enum Averaging {
142 Disabled,
143 Samples2,
144 Samples4,
145 Samples8,
146 Samples16,
147 Samples32,
148 Samples64,
149 Samples128,
150 Samples256,
151 Samples512,
152 Samples1024,
153}
154
155impl<'d, T: Instance> Adc<'d, T> {
156 /// Create a new ADC driver.
157 pub fn new(adc: Peri<'d, T>, sample_time: SampleTime, resolution: Resolution) -> Self {
158 rcc::enable_and_reset::<T>();
159
160 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
161
162 let prescaler = Prescaler::from_ker_ck(T::frequency());
163 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
164
165 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
166 debug!("ADC frequency set to {}", frequency);
167
168 if frequency > MAX_ADC_CLK_FREQ {
169 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
170 }
171
172 let mut s = Self {
173 adc,
174 sample_time: SampleTime::from_bits(0),
175 };
176
177 s.power_up();
178
179 s.set_resolution(resolution);
180
181 s.calibrate();
182
183 s.enable();
184
185 s.configure_default();
186
187 s.set_sample_time_all_channels(sample_time);
188
189 s
190 }
191
192 fn power_up(&mut self) {
193 T::regs().cr().modify(|reg| {
194 reg.set_advregen(true);
195 });
196
197 // "The software must wait for the ADC voltage regulator startup time."
198 // See datasheet for the value.
199 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1);
200 }
201
202 fn calibrate(&mut self) {
203 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
204 let autoff_value = T::regs().cfgr1().read().autoff();
205 T::regs().cfgr1().modify(|w| w.set_autoff(false));
206
207 T::regs().cr().modify(|w| w.set_adcal(true));
208
209 // "ADCAL bit stays at 1 during all the calibration sequence."
210 // "It is then cleared by hardware as soon the calibration completes."
211 while T::regs().cr().read().adcal() {}
212
213 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
214
215 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
216 }
217
218 fn enable(&mut self) {
219 T::regs().isr().modify(|w| w.set_adrdy(true));
220 T::regs().cr().modify(|w| w.set_aden(true));
221 // ADRDY is "ADC ready". Wait until it will be True.
222 while !T::regs().isr().read().adrdy() {}
223 }
224
225 fn configure_default(&mut self) {
226 // single conversion mode, software trigger
227 T::regs().cfgr1().modify(|w| {
228 w.set_cont(false);
229 w.set_exten(Exten::DISABLED);
230 w.set_align(Align::RIGHT);
231 });
232 }
233
234 /// Enable reading the voltage reference internal channel.
235 pub fn enable_vrefint(&self) -> VrefInt {
236 T::common_regs().ccr().modify(|reg| {
237 reg.set_vrefen(true);
238 });
239
240 VrefInt {}
241 }
242
243 /// Enable reading the temperature internal channel.
244 pub fn enable_temperature(&self) -> Temperature {
245 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!");
246 T::common_regs().ccr().modify(|reg| {
247 reg.set_tsen(true);
248 });
249
250 Temperature {}
251 }
252
253 /// Set the ADC sample time.
254 /// Shall only be called when ADC is not converting.
255 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
256 self.sample_time = sample_time;
257
258 // Set all channels to use SMP1 field as source.
259 T::regs().smpr().modify(|w| {
260 w.smpsel(0);
261 w.set_smp1(sample_time);
262 });
263 }
264
265 /// Set the ADC resolution.
266 pub fn set_resolution(&mut self, resolution: Resolution) {
267 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
268 }
269
270 /// Perform a single conversion.
271 fn convert(&mut self) -> u16 {
272 // Set single conversion mode.
273 T::regs().cfgr1().modify(|w| w.set_cont(false));
274
275 // Start conversion
276 T::regs().cr().modify(|reg| {
277 reg.set_adstart(true);
278 });
279
280 // Waiting for End Of Conversion (EOC).
281 while !T::regs().isr().read().eoc() {}
282
283 T::regs().dr().read().data() as u16
284 }
285
286 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
287 Self::configure_channel(channel);
288 T::regs().cfgr1().write(|reg| {
289 reg.set_chselrmod(false);
290 reg.set_align(Align::RIGHT);
291 });
292 self.convert()
293 }
294
295 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
296 assert!(
297 channel_sequence.len() <= CHSELR_SQ_SIZE,
298 "Seqenced read set cannot be more than {} in size.",
299 CHSELR_SQ_SIZE
300 );
301 let mut last_sq_set: usize = 0;
302 T::regs().chselr_sq().write(|w| {
303 for (i, channel) in channel_sequence.enumerate() {
304 assert!(
305 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
306 "Sequencer only support HW channels smaller than {}.",
307 CHSELR_SQ_MAX_CHANNEL
308 );
309 w.set_sq(i, channel.channel());
310 last_sq_set = i;
311 }
312
313 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
314 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
315 }
316 });
317
318 Self::apply_channel_conf()
319 }
320
321 async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) {
322 // Enable overrun control, so no new DMA requests will be generated until
323 // previous DR values is read.
324 T::regs().isr().modify(|reg| {
325 reg.set_ovr(true);
326 });
327
328 // Set continuous mode with oneshot dma.
329 T::regs().cfgr1().modify(|reg| {
330 reg.set_discen(false);
331 reg.set_cont(true);
332 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
333 reg.set_dmaen(true);
334 reg.set_ovrmod(Ovrmod::PRESERVE);
335 });
336
337 let request = rx_dma.request();
338 let transfer = unsafe {
339 Transfer::new_read(
340 rx_dma,
341 request,
342 T::regs().dr().as_ptr() as *mut u16,
343 readings,
344 Default::default(),
345 )
346 };
347
348 // Start conversion.
349 T::regs().cr().modify(|reg| {
350 reg.set_adstart(true);
351 });
352
353 // Wait for conversion sequence to finish.
354 transfer.await;
355
356 // Ensure conversions are finished.
357 Self::cancel_conversions();
358
359 // Reset configuration.
360 T::regs().cfgr1().modify(|reg| {
361 reg.set_cont(false);
362 reg.set_dmacfg(Dmacfg::from_bits(0));
363 reg.set_dmaen(false);
364 });
365 }
366
367 /// Read one or multiple ADC channels using DMA in hardware order.
368 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
369 /// Readings won't be in the same order as in the `set`!
370 ///
371 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
372 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
373 /// TODO(chudsaviet): externalize generic code and merge with read().
374 pub async fn read_in_hw_order(
375 &mut self,
376 rx_dma: Peri<'_, impl RxDma<T>>,
377 hw_channel_selection: u32,
378 scandir: Scandir,
379 readings: &mut [u16],
380 ) {
381 assert!(
382 hw_channel_selection != 0,
383 "Some bits in `hw_channel_selection` shall be set."
384 );
385 assert!(
386 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
387 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
388 NUM_HW_CHANNELS
389 );
390 // To check for correct readings slice size, we shall solve Hamming weight problem,
391 // which is either slow or memory consuming.
392 // Since we have limited resources, we don't do it here.
393 // Not doing this have a great potential for a bug through.
394
395 // Ensure no conversions are ongoing.
396 Self::cancel_conversions();
397
398 T::regs().cfgr1().modify(|reg| {
399 reg.set_chselrmod(false);
400 reg.set_scandir(scandir);
401 reg.set_align(Align::RIGHT);
402 });
403
404 // Set required channels for multi-convert.
405 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
406
407 Self::apply_channel_conf();
408
409 self.dma_convert(rx_dma, readings).await
410 }
411
412 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
413 // In STM32C0, only lower 14 ADC channels can be read this way.
414 // For other channels, use `read_in_hw_order()` or blocking read.
415 pub async fn read(
416 &mut self,
417 rx_dma: Peri<'_, impl RxDma<T>>,
418 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
419 readings: &mut [u16],
420 ) {
421 assert!(
422 channel_sequence.len() != 0,
423 "Asynchronous read channel sequence cannot be empty."
424 );
425 assert!(
426 channel_sequence.len() == readings.len(),
427 "Channel sequence length must be equal to readings length."
428 );
429
430 // Ensure no conversions are ongoing.
431 Self::cancel_conversions();
432
433 T::regs().cfgr1().modify(|reg| {
434 reg.set_chselrmod(true);
435 reg.set_align(Align::RIGHT);
436 });
437
438 Self::setup_channel_sequencer(channel_sequence);
439
440 self.dma_convert(rx_dma, readings).await
441 }
442
443 fn configure_channel(channel: &mut impl AdcChannel<T>) {
444 channel.setup();
445 // write() because we want all other bits to be set to 0.
446 T::regs()
447 .chselr()
448 .write(|w| w.set_chsel(channel.channel().into(), true));
449
450 Self::apply_channel_conf();
451 }
452
453 fn apply_channel_conf() {
454 // Trigger and wait for the channel selection procedure to complete.
455 T::regs().isr().modify(|w| w.set_ccrdy(false));
456 while !T::regs().isr().read().ccrdy() {}
457 }
458
459 fn cancel_conversions() {
460 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
461 T::regs().cr().modify(|reg| {
462 reg.set_adstp(Adstp::STOP);
463 });
464 while T::regs().cr().read().adstart() {}
465 }
466 }
467}
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index b37ec260f..3cdc9d8fb 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -2,12 +2,12 @@ use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref;
6
7use super::blocking_delay_us; 5use super::blocking_delay_us;
8use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
7use crate::interrupt::typelevel::Interrupt;
8use crate::interrupt::{self};
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{interrupt, rcc, Peripheral}; 10use crate::{rcc, Peri};
11 11
12pub const VDDA_CALIB_MV: u32 = 3300; 12pub const VDDA_CALIB_MV: u32 = 3300;
13pub const ADC_MAX: u32 = (1 << 12) - 1; 13pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -22,12 +22,9 @@ pub struct InterruptHandler<T: Instance> {
22impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 22impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
23 unsafe fn on_interrupt() { 23 unsafe fn on_interrupt() {
24 if T::regs().sr().read().eoc() { 24 if T::regs().sr().read().eoc() {
25 T::regs().cr1().modify(|w| w.set_eocie(false)); 25 T::regs().cr1().modify(|w| w.set_eocie(false)); // End of Convert interrupt disable
26 } else { 26 T::state().waker.wake();
27 return;
28 } 27 }
29
30 T::state().waker.wake();
31 } 28 }
32} 29}
33 30
@@ -48,8 +45,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
48} 45}
49 46
50impl<'d, T: Instance> Adc<'d, T> { 47impl<'d, T: Instance> Adc<'d, T> {
51 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 48 pub fn new(adc: Peri<'d, T>) -> Self {
52 into_ref!(adc);
53 rcc::enable_and_reset::<T>(); 49 rcc::enable_and_reset::<T>();
54 T::regs().cr2().modify(|reg| reg.set_adon(true)); 50 T::regs().cr2().modify(|reg| reg.set_adon(true));
55 51
@@ -72,6 +68,9 @@ impl<'d, T: Instance> Adc<'d, T> {
72 // One cycle after calibration 68 // One cycle after calibration
73 blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); 69 blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1);
74 70
71 T::Interrupt::unpend();
72 unsafe { T::Interrupt::enable() };
73
75 Self { 74 Self {
76 adc, 75 adc,
77 sample_time: SampleTime::from_bits(0), 76 sample_time: SampleTime::from_bits(0),
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index ac88c9742..3aeb6f2c7 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -2,13 +2,11 @@ use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref;
6
7use super::blocking_delay_us; 5use super::blocking_delay_us;
8use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
9use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{interrupt, rcc, Peripheral}; 9use crate::{interrupt, rcc, Peri};
12 10
13pub const VDDA_CALIB_MV: u32 = 3300; 11pub const VDDA_CALIB_MV: u32 = 3300;
14pub const ADC_MAX: u32 = (1 << 12) - 1; 12pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -42,7 +40,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Vref {
42impl Vref { 40impl Vref {
43 /// The value that vref would be if vdda was at 3300mv 41 /// The value that vref would be if vdda was at 3300mv
44 pub fn value(&self) -> u16 { 42 pub fn value(&self) -> u16 {
45 crate::pac::VREFINTCAL.data().read().value() 43 crate::pac::VREFINTCAL.data().read()
46 } 44 }
47} 45}
48 46
@@ -56,13 +54,11 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
56 54
57impl<'d, T: Instance> Adc<'d, T> { 55impl<'d, T: Instance> Adc<'d, T> {
58 pub fn new( 56 pub fn new(
59 adc: impl Peripheral<P = T> + 'd, 57 adc: Peri<'d, T>,
60 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 58 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
61 ) -> Self { 59 ) -> Self {
62 use crate::pac::adc::vals; 60 use crate::pac::adc::vals;
63 61
64 into_ref!(adc);
65
66 rcc::enable_and_reset::<T>(); 62 rcc::enable_and_reset::<T>();
67 63
68 // Enable the adc regulator 64 // Enable the adc regulator
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 689c2871d..944e971bb 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -3,14 +3,13 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_futures::yield_now; 5use embassy_futures::yield_now;
6use embassy_hal_internal::into_ref;
7use embassy_time::Instant; 6use embassy_time::Instant;
8 7
9use super::Resolution; 8use super::Resolution;
10use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 9use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
11use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
12use crate::time::Hertz; 11use crate::time::Hertz;
13use crate::{interrupt, rcc, Peripheral}; 12use crate::{interrupt, rcc, Peri};
14 13
15const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; 14const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
16 15
@@ -74,7 +73,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Vref<T> {
74impl<T: Instance> Vref<T> { 73impl<T: Instance> Vref<T> {
75 /// The value that vref would be if vdda was at 3000mv 74 /// The value that vref would be if vdda was at 3000mv
76 pub fn calibrated_value(&self) -> u16 { 75 pub fn calibrated_value(&self) -> u16 {
77 crate::pac::VREFINTCAL.data().read().value() 76 crate::pac::VREFINTCAL.data().read()
78 } 77 }
79 78
80 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { 79 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration {
@@ -138,11 +137,9 @@ impl<T: Instance> Drop for Temperature<T> {
138 137
139impl<'d, T: Instance> Adc<'d, T> { 138impl<'d, T: Instance> Adc<'d, T> {
140 pub fn new( 139 pub fn new(
141 adc: impl Peripheral<P = T> + 'd, 140 adc: Peri<'d, T>,
142 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 141 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
143 ) -> Self { 142 ) -> Self {
144 into_ref!(adc);
145
146 rcc::enable_and_reset::<T>(); 143 rcc::enable_and_reset::<T>();
147 144
148 //let r = T::regs(); 145 //let r = T::regs();
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index c1e584f59..1fce3085a 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,10 +1,17 @@
1#[allow(unused)] 1#[allow(unused)]
2#[cfg(stm32h7)]
2use pac::adc::vals::{Adcaldif, Difsel, Exten}; 3use pac::adc::vals::{Adcaldif, Difsel, Exten};
4#[allow(unused)]
5#[cfg(stm32g4)]
6use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
3use pac::adccommon::vals::Presc; 7use pac::adccommon::vals::Presc;
8use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
4 9
5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; 10use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime};
11use crate::adc::SealedAdcChannel;
12use crate::dma::Transfer;
6use crate::time::Hertz; 13use crate::time::Hertz;
7use crate::{pac, rcc, Peripheral}; 14use crate::{pac, rcc, Peri};
8 15
9/// Default VREF voltage used for sample conversion to millivolts. 16/// Default VREF voltage used for sample conversion to millivolts.
10pub const VREF_DEFAULT_MV: u32 = 3300; 17pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -128,8 +135,7 @@ impl Prescaler {
128 135
129impl<'d, T: Instance> Adc<'d, T> { 136impl<'d, T: Instance> Adc<'d, T> {
130 /// Create a new ADC driver. 137 /// Create a new ADC driver.
131 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 138 pub fn new(adc: Peri<'d, T>) -> Self {
132 embassy_hal_internal::into_ref!(adc);
133 rcc::enable_and_reset::<T>(); 139 rcc::enable_and_reset::<T>();
134 140
135 let prescaler = Prescaler::from_ker_ck(T::frequency()); 141 let prescaler = Prescaler::from_ker_ck(T::frequency());
@@ -137,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> {
137 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 143 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
138 144
139 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 145 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
140 info!("ADC frequency set to {} Hz", frequency.0); 146 trace!("ADC frequency set to {}", frequency);
141 147
142 if frequency > MAX_ADC_CLK_FREQ { 148 if frequency > MAX_ADC_CLK_FREQ {
143 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 149 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
@@ -165,32 +171,58 @@ impl<'d, T: Instance> Adc<'d, T> {
165 reg.set_advregen(true); 171 reg.set_advregen(true);
166 }); 172 });
167 173
168 blocking_delay_us(10); 174 blocking_delay_us(20);
169 } 175 }
170 176
171 fn configure_differential_inputs(&mut self) { 177 fn configure_differential_inputs(&mut self) {
172 T::regs().difsel().modify(|w| { 178 T::regs().difsel().modify(|w| {
173 for n in 0..18 { 179 for n in 0..18 {
174 w.set_difsel(n, Difsel::SINGLEENDED); 180 w.set_difsel(n, Difsel::SINGLE_ENDED);
175 } 181 }
176 }); 182 });
177 } 183 }
178 184
179 fn calibrate(&mut self) { 185 fn calibrate(&mut self) {
180 T::regs().cr().modify(|w| { 186 T::regs().cr().modify(|w| {
181 w.set_adcaldif(Adcaldif::SINGLEENDED); 187 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
182 }); 188 });
183 189
184 T::regs().cr().modify(|w| w.set_adcal(true)); 190 T::regs().cr().modify(|w| w.set_adcal(true));
185 191
186 while T::regs().cr().read().adcal() {} 192 while T::regs().cr().read().adcal() {}
193
194 blocking_delay_us(20);
195
196 T::regs().cr().modify(|w| {
197 w.set_adcaldif(Adcaldif::DIFFERENTIAL);
198 });
199
200 T::regs().cr().modify(|w| w.set_adcal(true));
201
202 while T::regs().cr().read().adcal() {}
203
204 blocking_delay_us(20);
187 } 205 }
188 206
189 fn enable(&mut self) { 207 fn enable(&mut self) {
190 T::regs().isr().write(|w| w.set_adrdy(true)); 208 // Make sure bits are off
191 T::regs().cr().modify(|w| w.set_aden(true)); 209 while T::regs().cr().read().addis() {
192 while !T::regs().isr().read().adrdy() {} 210 // spin
193 T::regs().isr().write(|w| w.set_adrdy(true)); 211 }
212
213 if !T::regs().cr().read().aden() {
214 // Enable ADC
215 T::regs().isr().modify(|reg| {
216 reg.set_adrdy(true);
217 });
218 T::regs().cr().modify(|reg| {
219 reg.set_aden(true);
220 });
221
222 while !T::regs().isr().read().adrdy() {
223 // spin
224 }
225 }
194 } 226 }
195 227
196 fn configure(&mut self) { 228 fn configure(&mut self) {
@@ -228,6 +260,68 @@ impl<'d, T: Instance> Adc<'d, T> {
228 Vbat {} 260 Vbat {}
229 } 261 }
230 262
263 /// Enable differential channel.
264 /// Caution:
265 /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i]
266 /// is connected to another channel. As a consequence, this channel is no longer usable in
267 /// single-ended mode or in differential mode and must never be configured to be converted.
268 /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the
269 /// channel on the other ADC unusable. The only exception is when ADC master and the slave
270 /// operate in interleaved mode.
271 #[cfg(stm32g4)]
272 pub fn set_differential_channel(&mut self, ch: usize, enable: bool) {
273 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
274 T::regs().difsel().modify(|w| {
275 w.set_difsel(
276 ch,
277 if enable {
278 Difsel::DIFFERENTIAL
279 } else {
280 Difsel::SINGLE_ENDED
281 },
282 );
283 });
284 T::regs().cr().modify(|w| w.set_aden(true));
285 }
286
287 #[cfg(stm32g4)]
288 pub fn set_differential(&mut self, channel: &mut impl AdcChannel<T>, enable: bool) {
289 self.set_differential_channel(channel.channel() as usize, enable);
290 }
291
292 /// Set oversampling shift.
293 #[cfg(stm32g4)]
294 pub fn set_oversampling_shift(&mut self, shift: u8) {
295 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
296 }
297
298 /// Set oversampling ratio.
299 #[cfg(stm32g4)]
300 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
301 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
302 }
303
304 /// Enable oversampling in regular mode.
305 #[cfg(stm32g4)]
306 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
307 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
308 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
309 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
310 }
311
312 // Reads that are not implemented as INJECTED in "blocking_read"
313 // #[cfg(stm32g4)]
314 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) {
315 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
316 // }
317
318 // #[cfg(stm32g4)]
319 // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) {
320 // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored),
321 // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
322 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
323 // }
324
231 /// Set the ADC sample time. 325 /// Set the ADC sample time.
232 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 326 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
233 self.sample_time = sample_time; 327 self.sample_time = sample_time;
@@ -261,23 +355,146 @@ impl<'d, T: Instance> Adc<'d, T> {
261 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 355 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
262 channel.setup(); 356 channel.setup();
263 357
264 self.read_channel(channel.channel()) 358 self.read_channel(channel)
265 } 359 }
266 360
267 fn read_channel(&mut self, channel: u8) -> u16 { 361 /// Read one or multiple ADC channels using DMA.
362 ///
363 /// `sequence` iterator and `readings` must have the same length.
364 ///
365 /// Example
366 /// ```rust,ignore
367 /// use embassy_stm32::adc::{Adc, AdcChannel}
368 ///
369 /// let mut adc = Adc::new(p.ADC1);
370 /// let mut adc_pin0 = p.PA0.into();
371 /// let mut adc_pin1 = p.PA1.into();
372 /// let mut measurements = [0u16; 2];
373 ///
374 /// adc.read(
375 /// p.DMA1_CH2.reborrow(),
376 /// [
377 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
378 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
379 /// ]
380 /// .into_iter(),
381 /// &mut measurements,
382 /// )
383 /// .await;
384 /// defmt::info!("measurements: {}", measurements);
385 /// ```
386 pub async fn read(
387 &mut self,
388 rx_dma: Peri<'_, impl RxDma<T>>,
389 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
390 readings: &mut [u16],
391 ) {
392 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
393 assert!(
394 sequence.len() == readings.len(),
395 "Sequence length must be equal to readings length"
396 );
397 assert!(
398 sequence.len() <= 16,
399 "Asynchronous read sequence cannot be more than 16 in length"
400 );
401
402 // Ensure no conversions are ongoing and ADC is enabled.
403 Self::cancel_conversions();
404 self.enable();
405
406 // Set sequence length
407 T::regs().sqr1().modify(|w| {
408 w.set_l(sequence.len() as u8 - 1);
409 });
410
411 // Configure channels and ranks
412 for (_i, (channel, sample_time)) in sequence.enumerate() {
413 Self::configure_channel(channel, sample_time);
414
415 match _i {
416 0..=3 => {
417 T::regs().sqr1().modify(|w| {
418 w.set_sq(_i, channel.channel());
419 });
420 }
421 4..=8 => {
422 T::regs().sqr2().modify(|w| {
423 w.set_sq(_i - 4, channel.channel());
424 });
425 }
426 9..=13 => {
427 T::regs().sqr3().modify(|w| {
428 w.set_sq(_i - 9, channel.channel());
429 });
430 }
431 14..=15 => {
432 T::regs().sqr4().modify(|w| {
433 w.set_sq(_i - 14, channel.channel());
434 });
435 }
436 _ => unreachable!(),
437 }
438 }
439
440 // Set continuous mode with oneshot dma.
441 // Clear overrun flag before starting transfer.
442 T::regs().isr().modify(|reg| {
443 reg.set_ovr(true);
444 });
445
446 T::regs().cfgr().modify(|reg| {
447 reg.set_discen(false);
448 reg.set_cont(true);
449 reg.set_dmacfg(Dmacfg::ONE_SHOT);
450 reg.set_dmaen(Dmaen::ENABLE);
451 });
452
453 let request = rx_dma.request();
454 let transfer = unsafe {
455 Transfer::new_read(
456 rx_dma,
457 request,
458 T::regs().dr().as_ptr() as *mut u16,
459 readings,
460 Default::default(),
461 )
462 };
463
464 // Start conversion
465 T::regs().cr().modify(|reg| {
466 reg.set_adstart(true);
467 });
468
469 // Wait for conversion sequence to finish.
470 transfer.await;
471
472 // Ensure conversions are finished.
473 Self::cancel_conversions();
474
475 // Reset configuration.
476 T::regs().cfgr().modify(|reg| {
477 reg.set_cont(false);
478 });
479 }
480
481 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
268 // Configure channel 482 // Configure channel
269 Self::set_channel_sample_time(channel, self.sample_time); 483 Self::set_channel_sample_time(channel.channel(), sample_time);
484 }
270 485
486 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
487 Self::configure_channel(channel, self.sample_time);
271 #[cfg(stm32h7)] 488 #[cfg(stm32h7)]
272 { 489 {
273 T::regs().cfgr2().modify(|w| w.set_lshift(0)); 490 T::regs().cfgr2().modify(|w| w.set_lshift(0));
274 T::regs() 491 T::regs()
275 .pcsel() 492 .pcsel()
276 .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); 493 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
277 } 494 }
278 495
279 T::regs().sqr1().write(|reg| { 496 T::regs().sqr1().write(|reg| {
280 reg.set_sq(0, channel); 497 reg.set_sq(0, channel.channel());
281 reg.set_l(0); 498 reg.set_l(0);
282 }); 499 });
283 500
@@ -292,4 +509,13 @@ impl<'d, T: Instance> Adc<'d, T> {
292 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); 509 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
293 } 510 }
294 } 511 }
512
513 fn cancel_conversions() {
514 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
515 T::regs().cr().modify(|reg| {
516 reg.set_adstp(Adstp::STOP);
517 });
518 while T::regs().cr().read().adstart() {}
519 }
520 }
295} 521}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 2f36df240..f46e87f38 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -4,37 +4,46 @@
4#![allow(missing_docs)] // TODO 4#![allow(missing_docs)] // TODO
5#![cfg_attr(adc_f3_v2, allow(unused))] 5#![cfg_attr(adc_f3_v2, allow(unused))]
6 6
7#[cfg(not(adc_f3_v2))] 7#[cfg(not(any(adc_f3_v2)))]
8#[cfg_attr(adc_f1, path = "f1.rs")] 8#[cfg_attr(adc_f1, path = "f1.rs")]
9#[cfg_attr(adc_f3, path = "f3.rs")] 9#[cfg_attr(adc_f3, path = "f3.rs")]
10#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] 10#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
11#[cfg_attr(adc_v1, path = "v1.rs")] 11#[cfg_attr(adc_v1, path = "v1.rs")]
12#[cfg_attr(adc_l0, path = "v1.rs")] 12#[cfg_attr(adc_l0, path = "v1.rs")]
13#[cfg_attr(adc_v2, path = "v2.rs")] 13#[cfg_attr(adc_v2, path = "v2.rs")]
14#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] 14#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0), path = "v3.rs")]
15#[cfg_attr(adc_v4, path = "v4.rs")] 15#[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")]
16#[cfg_attr(adc_g4, path = "g4.rs")] 16#[cfg_attr(adc_g4, path = "g4.rs")]
17#[cfg_attr(adc_c0, path = "c0.rs")]
17mod _version; 18mod _version;
18 19
19use core::marker::PhantomData; 20use core::marker::PhantomData;
20 21
21#[allow(unused)] 22#[allow(unused)]
22#[cfg(not(adc_f3_v2))] 23#[cfg(not(any(adc_f3_v2)))]
23pub use _version::*; 24pub use _version::*;
25use embassy_hal_internal::{impl_peripheral, PeripheralType};
24#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] 26#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
25use embassy_sync::waitqueue::AtomicWaker; 27use embassy_sync::waitqueue::AtomicWaker;
26 28
29#[cfg(adc_u5)]
30#[path = "u5_adc4.rs"]
31pub mod adc4;
32
33pub use crate::pac::adc::vals;
27#[cfg(not(any(adc_f1, adc_f3_v2)))] 34#[cfg(not(any(adc_f1, adc_f3_v2)))]
28pub use crate::pac::adc::vals::Res as Resolution; 35pub use crate::pac::adc::vals::Res as Resolution;
29pub use crate::pac::adc::vals::SampleTime; 36pub use crate::pac::adc::vals::SampleTime;
30use crate::peripherals; 37use crate::peripherals;
31 38
32dma_trait!(RxDma, Instance); 39dma_trait!(RxDma, Instance);
40#[cfg(adc_u5)]
41dma_trait!(RxDma4, adc4::Instance);
33 42
34/// Analog to Digital driver. 43/// Analog to Digital driver.
35pub struct Adc<'d, T: Instance> { 44pub struct Adc<'d, T: Instance> {
36 #[allow(unused)] 45 #[allow(unused)]
37 adc: crate::PeripheralRef<'d, T>, 46 adc: crate::Peri<'d, T>,
38 #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] 47 #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))]
39 sample_time: SampleTime, 48 sample_time: SampleTime,
40} 49}
@@ -64,7 +73,7 @@ trait SealedInstance {
64} 73}
65 74
66pub(crate) trait SealedAdcChannel<T> { 75pub(crate) trait SealedAdcChannel<T> {
67 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] 76 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
68 fn setup(&mut self) {} 77 fn setup(&mut self) {}
69 78
70 #[allow(unused)] 79 #[allow(unused)]
@@ -98,10 +107,13 @@ pub(crate) fn blocking_delay_us(us: u32) {
98 adc_f3_v1_1, 107 adc_f3_v1_1,
99 adc_g0, 108 adc_g0,
100 adc_u0, 109 adc_u0,
101 adc_h5 110 adc_h5,
111 adc_h7rs,
112 adc_u5,
113 adc_c0
102)))] 114)))]
103#[allow(private_bounds)] 115#[allow(private_bounds)]
104pub trait Instance: SealedInstance + crate::Peripheral<P = Self> { 116pub trait Instance: SealedInstance + crate::PeripheralType {
105 type Interrupt: crate::interrupt::typelevel::Interrupt; 117 type Interrupt: crate::interrupt::typelevel::Interrupt;
106} 118}
107/// ADC instance. 119/// ADC instance.
@@ -117,10 +129,13 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
117 adc_f3_v1_1, 129 adc_f3_v1_1,
118 adc_g0, 130 adc_g0,
119 adc_u0, 131 adc_u0,
120 adc_h5 132 adc_h5,
133 adc_h7rs,
134 adc_u5,
135 adc_c0
121))] 136))]
122#[allow(private_bounds)] 137#[allow(private_bounds)]
123pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral { 138pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral {
124 type Interrupt: crate::interrupt::typelevel::Interrupt; 139 type Interrupt: crate::interrupt::typelevel::Interrupt;
125} 140}
126 141
@@ -129,7 +144,7 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::R
129pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { 144pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
130 #[allow(unused_mut)] 145 #[allow(unused_mut)]
131 fn degrade_adc(mut self) -> AnyAdcChannel<T> { 146 fn degrade_adc(mut self) -> AnyAdcChannel<T> {
132 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] 147 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
133 self.setup(); 148 self.setup();
134 149
135 AnyAdcChannel { 150 AnyAdcChannel {
@@ -147,7 +162,7 @@ pub struct AnyAdcChannel<T> {
147 channel: u8, 162 channel: u8,
148 _phantom: PhantomData<T>, 163 _phantom: PhantomData<T>,
149} 164}
150 165impl_peripheral!(AnyAdcChannel<T: Instance>);
151impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {} 166impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {}
152impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> { 167impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
153 fn channel(&self) -> u8 { 168 fn channel(&self) -> u8 {
@@ -155,6 +170,45 @@ impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
155 } 170 }
156} 171}
157 172
173impl<T> AnyAdcChannel<T> {
174 #[allow(unused)]
175 pub fn get_hw_channel(&self) -> u8 {
176 self.channel
177 }
178}
179
180#[cfg(adc_u5)]
181foreach_adc!(
182 (ADC4, $common_inst:ident, $clock:ident) => {
183 impl crate::adc::adc4::SealedInstance for peripherals::ADC4 {
184 fn regs() -> crate::pac::adc::Adc4 {
185 crate::pac::ADC4
186 }
187 }
188
189 impl crate::adc::adc4::Instance for peripherals::ADC4 {
190 type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL;
191 }
192 };
193
194 ($inst:ident, $common_inst:ident, $clock:ident) => {
195 impl crate::adc::SealedInstance for peripherals::$inst {
196 fn regs() -> crate::pac::adc::Adc {
197 crate::pac::$inst
198 }
199
200 fn common_regs() -> crate::pac::adccommon::AdcCommon {
201 return crate::pac::$common_inst
202 }
203 }
204
205 impl crate::adc::Instance for peripherals::$inst {
206 type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
207 }
208 };
209);
210
211#[cfg(not(adc_u5))]
158foreach_adc!( 212foreach_adc!(
159 ($inst:ident, $common_inst:ident, $clock:ident) => { 213 ($inst:ident, $common_inst:ident, $clock:ident) => {
160 impl crate::adc::SealedInstance for peripherals::$inst { 214 impl crate::adc::SealedInstance for peripherals::$inst {
@@ -182,11 +236,11 @@ foreach_adc!(
182 236
183macro_rules! impl_adc_pin { 237macro_rules! impl_adc_pin {
184 ($inst:ident, $pin:ident, $ch:expr) => { 238 ($inst:ident, $pin:ident, $ch:expr) => {
185 impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {} 239 impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {}
186 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin { 240 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {
187 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] 241 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
188 fn setup(&mut self) { 242 fn setup(&mut self) {
189 <Self as crate::gpio::SealedPin>::set_as_analog(self); 243 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self);
190 } 244 }
191 245
192 fn channel(&self) -> u8 { 246 fn channel(&self) -> u8 {
@@ -204,7 +258,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
204 match res { 258 match res {
205 #[cfg(adc_v4)] 259 #[cfg(adc_v4)]
206 Resolution::BITS16 => (1 << 16) - 1, 260 Resolution::BITS16 => (1 << 16) - 1,
207 #[cfg(adc_v4)] 261 #[cfg(any(adc_v4, adc_u5))]
208 Resolution::BITS14 => (1 << 14) - 1, 262 Resolution::BITS14 => (1 << 14) - 1,
209 #[cfg(adc_v4)] 263 #[cfg(adc_v4)]
210 Resolution::BITS14V => (1 << 14) - 1, 264 Resolution::BITS14V => (1 << 14) - 1,
@@ -213,7 +267,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
213 Resolution::BITS12 => (1 << 12) - 1, 267 Resolution::BITS12 => (1 << 12) - 1,
214 Resolution::BITS10 => (1 << 10) - 1, 268 Resolution::BITS10 => (1 << 10) - 1,
215 Resolution::BITS8 => (1 << 8) - 1, 269 Resolution::BITS8 => (1 << 8) - 1,
216 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] 270 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_c0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))]
217 Resolution::BITS6 => (1 << 6) - 1, 271 Resolution::BITS6 => (1 << 6) - 1,
218 #[allow(unreachable_patterns)] 272 #[allow(unreachable_patterns)]
219 _ => core::unreachable!(), 273 _ => core::unreachable!(),
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
index 3b064044e..6f69e8486 100644
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ b/embassy-stm32/src/adc/ringbuffered_v2.rs
@@ -2,14 +2,15 @@ use core::marker::PhantomData;
2use core::mem; 2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
4 4
5use embassy_hal_internal::{into_ref, Peripheral};
6use stm32_metapac::adc::vals::SampleTime; 5use stm32_metapac::adc::vals::SampleTime;
7 6
8use crate::adc::{Adc, AdcChannel, Instance, RxDma}; 7use crate::adc::{Adc, AdcChannel, Instance, RxDma};
9use crate::dma::ringbuffer::OverrunError;
10use crate::dma::{Priority, ReadableRingBuffer, TransferOptions}; 8use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
11use crate::pac::adc::vals; 9use crate::pac::adc::vals;
12use crate::rcc; 10use crate::{rcc, Peri};
11
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OverrunError;
13 14
14fn clear_interrupt_flags(r: crate::pac::adc::Adc) { 15fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
15 r.sr().modify(|regs| { 16 r.sr().modify(|regs| {
@@ -101,13 +102,8 @@ impl<'d, T: Instance> Adc<'d, T> {
101 /// It is critical to call `read` frequently to prevent DMA buffer overrun. 102 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
102 /// 103 ///
103 /// [`read`]: #method.read 104 /// [`read`]: #method.read
104 pub fn into_ring_buffered( 105 pub fn into_ring_buffered(self, dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> RingBufferedAdc<'d, T> {
105 self,
106 dma: impl Peripheral<P = impl RxDma<T>> + 'd,
107 dma_buf: &'d mut [u16],
108 ) -> RingBufferedAdc<'d, T> {
109 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 106 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
110 into_ref!(dma);
111 107
112 let opts: crate::dma::TransferOptions = TransferOptions { 108 let opts: crate::dma::TransferOptions = TransferOptions {
113 half_transfer_ir: true, 109 half_transfer_ir: true,
@@ -203,16 +199,16 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
203 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())), 199 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
204 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())), 200 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
205 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())), 201 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
206 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(6, channel.channel())), 202 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
207 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(7, channel.channel())), 203 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
208 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(8, channel.channel())), 204 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
209 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(9, channel.channel())), 205 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
210 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(10, channel.channel())), 206 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
211 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(11, channel.channel())), 207 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
212 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(12, channel.channel())), 208 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
213 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(13, channel.channel())), 209 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
214 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(14, channel.channel())), 210 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
215 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(15, channel.channel())), 211 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
216 }; 212 };
217 213
218 if !was_on { 214 if !was_on {
@@ -226,9 +222,8 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
226 222
227 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer. 223 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
228 pub fn start(&mut self) -> Result<(), OverrunError> { 224 pub fn start(&mut self) -> Result<(), OverrunError> {
229 self.ring_buf.clear();
230
231 self.setup_adc(); 225 self.setup_adc();
226 self.ring_buf.clear();
232 227
233 Ok(()) 228 Ok(())
234 } 229 }
@@ -245,7 +240,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
245 /// [`start`]: #method.start 240 /// [`start`]: #method.start
246 pub fn teardown_adc(&mut self) { 241 pub fn teardown_adc(&mut self) {
247 // Stop the DMA transfer 242 // Stop the DMA transfer
248 self.ring_buf.request_stop(); 243 self.ring_buf.request_pause();
249 244
250 let r = T::regs(); 245 let r = T::regs();
251 246
@@ -311,7 +306,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
311 // DMA requests are issues as long as DMA=1 and data are converted. 306 // DMA requests are issues as long as DMA=1 and data are converted.
312 w.set_dds(vals::Dds::CONTINUOUS); 307 w.set_dds(vals::Dds::CONTINUOUS);
313 // EOC flag is set at the end of each conversion. 308 // EOC flag is set at the end of each conversion.
314 w.set_eocs(vals::Eocs::EACHCONVERSION); 309 w.set_eocs(vals::Eocs::EACH_CONVERSION);
315 }); 310 });
316 311
317 // Begin ADC conversions 312 // Begin ADC conversions
diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs
new file mode 100644
index 000000000..1dd664366
--- /dev/null
+++ b/embassy-stm32/src/adc/u5_adc4.rs
@@ -0,0 +1,478 @@
1#[allow(unused)]
2use pac::adc::vals::{Adc4Dmacfg, Adc4Exten, Adc4OversamplingRatio};
3
4use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel};
5use crate::dma::Transfer;
6pub use crate::pac::adc::regs::Adc4Chselrmod0;
7pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4SampleTime as SampleTime};
8use crate::time::Hertz;
9use crate::{pac, rcc, Peri};
10
11const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
12
13/// Default VREF voltage used for sample conversion to millivolts.
14pub const VREF_DEFAULT_MV: u32 = 3300;
15/// VREF voltage used for factory calibration of VREFINTCAL register.
16pub const VREF_CALIB_MV: u32 = 3300;
17
18const VREF_CHANNEL: u8 = 0;
19const VCORE_CHANNEL: u8 = 12;
20const TEMP_CHANNEL: u8 = 13;
21const VBAT_CHANNEL: u8 = 14;
22const DAC_CHANNEL: u8 = 21;
23
24// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
25/// Internal voltage reference channel.
26pub struct VrefInt;
27impl<T: Instance> AdcChannel<T> for VrefInt {}
28impl<T: Instance> SealedAdcChannel<T> for VrefInt {
29 fn channel(&self) -> u8 {
30 VREF_CHANNEL
31 }
32}
33
34/// Internal temperature channel.
35pub struct Temperature;
36impl<T: Instance> AdcChannel<T> for Temperature {}
37impl<T: Instance> SealedAdcChannel<T> for Temperature {
38 fn channel(&self) -> u8 {
39 TEMP_CHANNEL
40 }
41}
42
43/// Internal battery voltage channel.
44pub struct Vbat;
45impl<T: Instance> AdcChannel<T> for Vbat {}
46impl<T: Instance> SealedAdcChannel<T> for Vbat {
47 fn channel(&self) -> u8 {
48 VBAT_CHANNEL
49 }
50}
51
52/// Internal DAC channel.
53pub struct Dac;
54impl<T: Instance> AdcChannel<T> for Dac {}
55impl<T: Instance> SealedAdcChannel<T> for Dac {
56 fn channel(&self) -> u8 {
57 DAC_CHANNEL
58 }
59}
60
61/// Internal Vcore channel.
62pub struct Vcore;
63impl<T: Instance> AdcChannel<T> for Vcore {}
64impl<T: Instance> SealedAdcChannel<T> for Vcore {
65 fn channel(&self) -> u8 {
66 VCORE_CHANNEL
67 }
68}
69
70pub enum DacChannel {
71 OUT1,
72 OUT2,
73}
74
75/// Number of samples used for averaging.
76pub enum Averaging {
77 Disabled,
78 Samples2,
79 Samples4,
80 Samples8,
81 Samples16,
82 Samples32,
83 Samples64,
84 Samples128,
85 Samples256,
86}
87
88pub const fn resolution_to_max_count(res: Resolution) -> u32 {
89 match res {
90 Resolution::BITS12 => (1 << 12) - 1,
91 Resolution::BITS10 => (1 << 10) - 1,
92 Resolution::BITS8 => (1 << 8) - 1,
93 Resolution::BITS6 => (1 << 6) - 1,
94 #[allow(unreachable_patterns)]
95 _ => core::unreachable!(),
96 }
97}
98
99// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
100// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
101#[allow(unused)]
102enum Prescaler {
103 NotDivided,
104 DividedBy2,
105 DividedBy4,
106 DividedBy6,
107 DividedBy8,
108 DividedBy10,
109 DividedBy12,
110 DividedBy16,
111 DividedBy32,
112 DividedBy64,
113 DividedBy128,
114 DividedBy256,
115}
116
117impl Prescaler {
118 fn from_ker_ck(frequency: Hertz) -> Self {
119 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
120 match raw_prescaler {
121 0 => Self::NotDivided,
122 1 => Self::DividedBy2,
123 2..=3 => Self::DividedBy4,
124 4..=5 => Self::DividedBy6,
125 6..=7 => Self::DividedBy8,
126 8..=9 => Self::DividedBy10,
127 10..=11 => Self::DividedBy12,
128 _ => unimplemented!(),
129 }
130 }
131
132 fn divisor(&self) -> u32 {
133 match self {
134 Prescaler::NotDivided => 1,
135 Prescaler::DividedBy2 => 2,
136 Prescaler::DividedBy4 => 4,
137 Prescaler::DividedBy6 => 6,
138 Prescaler::DividedBy8 => 8,
139 Prescaler::DividedBy10 => 10,
140 Prescaler::DividedBy12 => 12,
141 Prescaler::DividedBy16 => 16,
142 Prescaler::DividedBy32 => 32,
143 Prescaler::DividedBy64 => 64,
144 Prescaler::DividedBy128 => 128,
145 Prescaler::DividedBy256 => 256,
146 }
147 }
148
149 fn presc(&self) -> Presc {
150 match self {
151 Prescaler::NotDivided => Presc::DIV1,
152 Prescaler::DividedBy2 => Presc::DIV2,
153 Prescaler::DividedBy4 => Presc::DIV4,
154 Prescaler::DividedBy6 => Presc::DIV6,
155 Prescaler::DividedBy8 => Presc::DIV8,
156 Prescaler::DividedBy10 => Presc::DIV10,
157 Prescaler::DividedBy12 => Presc::DIV12,
158 Prescaler::DividedBy16 => Presc::DIV16,
159 Prescaler::DividedBy32 => Presc::DIV32,
160 Prescaler::DividedBy64 => Presc::DIV64,
161 Prescaler::DividedBy128 => Presc::DIV128,
162 Prescaler::DividedBy256 => Presc::DIV256,
163 }
164 }
165}
166
167pub trait SealedInstance {
168 #[allow(unused)]
169 fn regs() -> crate::pac::adc::Adc4;
170}
171
172pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral {
173 type Interrupt: crate::interrupt::typelevel::Interrupt;
174}
175
176pub struct Adc4<'d, T: Instance> {
177 #[allow(unused)]
178 adc: crate::Peri<'d, T>,
179}
180
181#[derive(Debug)]
182pub enum Adc4Error {
183 InvalidSequence,
184 DMAError,
185}
186
187impl<'d, T: Instance> Adc4<'d, T> {
188 /// Create a new ADC driver.
189 pub fn new(adc: Peri<'d, T>) -> Self {
190 rcc::enable_and_reset::<T>();
191 let prescaler = Prescaler::from_ker_ck(T::frequency());
192
193 T::regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
194
195 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
196 info!("ADC4 frequency set to {}", frequency);
197
198 if frequency > MAX_ADC_CLK_FREQ {
199 panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
200 }
201
202 let mut s = Self { adc };
203
204 s.power_up();
205
206 s.calibrate();
207 blocking_delay_us(1);
208
209 s.enable();
210 s.configure();
211
212 s
213 }
214
215 fn power_up(&mut self) {
216 T::regs().isr().modify(|w| {
217 w.set_ldordy(true);
218 });
219 T::regs().cr().modify(|w| {
220 w.set_advregen(true);
221 });
222 while !T::regs().isr().read().ldordy() {}
223
224 T::regs().isr().modify(|w| {
225 w.set_ldordy(true);
226 });
227 }
228
229 fn calibrate(&mut self) {
230 T::regs().cr().modify(|w| w.set_adcal(true));
231 while T::regs().cr().read().adcal() {}
232 T::regs().isr().modify(|w| w.set_eocal(true));
233 }
234
235 fn enable(&mut self) {
236 T::regs().isr().write(|w| w.set_adrdy(true));
237 T::regs().cr().modify(|w| w.set_aden(true));
238 while !T::regs().isr().read().adrdy() {}
239 T::regs().isr().write(|w| w.set_adrdy(true));
240 }
241
242 fn configure(&mut self) {
243 // single conversion mode, software trigger
244 T::regs().cfgr1().modify(|w| {
245 w.set_cont(false);
246 w.set_discen(false);
247 w.set_exten(Adc4Exten::DISABLED);
248 w.set_chselrmod(false);
249 });
250
251 // only use one channel at the moment
252 T::regs().smpr().modify(|w| {
253 for i in 0..24 {
254 w.set_smpsel(i, false);
255 }
256 });
257 }
258
259 /// Enable reading the voltage reference internal channel.
260 pub fn enable_vrefint(&self) -> VrefInt {
261 T::regs().ccr().modify(|w| {
262 w.set_vrefen(true);
263 });
264
265 VrefInt {}
266 }
267
268 /// Enable reading the temperature internal channel.
269 pub fn enable_temperature(&self) -> Temperature {
270 T::regs().ccr().modify(|w| {
271 w.set_vsensesel(true);
272 });
273
274 Temperature {}
275 }
276
277 /// Enable reading the vbat internal channel.
278 pub fn enable_vbat(&self) -> Vbat {
279 T::regs().ccr().modify(|w| {
280 w.set_vbaten(true);
281 });
282
283 Vbat {}
284 }
285
286 /// Enable reading the vbat internal channel.
287 pub fn enable_vcore(&self) -> Vcore {
288 Vcore {}
289 }
290
291 /// Enable reading the vbat internal channel.
292 pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac {
293 let mux;
294 match dac {
295 DacChannel::OUT1 => mux = false,
296 DacChannel::OUT2 => mux = true,
297 }
298 T::regs().or().modify(|w| w.set_chn21sel(mux));
299 Dac {}
300 }
301
302 /// Set the ADC sample time.
303 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
304 T::regs().smpr().modify(|w| {
305 w.set_smp(0, sample_time);
306 });
307 }
308
309 /// Get the ADC sample time.
310 pub fn sample_time(&self) -> SampleTime {
311 T::regs().smpr().read().smp(0)
312 }
313
314 /// Set the ADC resolution.
315 pub fn set_resolution(&mut self, resolution: Resolution) {
316 T::regs().cfgr1().modify(|w| w.set_res(resolution.into()));
317 }
318
319 /// Set hardware averaging.
320 pub fn set_averaging(&mut self, averaging: Averaging) {
321 let (enable, samples, right_shift) = match averaging {
322 Averaging::Disabled => (false, Adc4OversamplingRatio::OVERSAMPLE2X, 0),
323 Averaging::Samples2 => (true, Adc4OversamplingRatio::OVERSAMPLE2X, 1),
324 Averaging::Samples4 => (true, Adc4OversamplingRatio::OVERSAMPLE4X, 2),
325 Averaging::Samples8 => (true, Adc4OversamplingRatio::OVERSAMPLE8X, 3),
326 Averaging::Samples16 => (true, Adc4OversamplingRatio::OVERSAMPLE16X, 4),
327 Averaging::Samples32 => (true, Adc4OversamplingRatio::OVERSAMPLE32X, 5),
328 Averaging::Samples64 => (true, Adc4OversamplingRatio::OVERSAMPLE64X, 6),
329 Averaging::Samples128 => (true, Adc4OversamplingRatio::OVERSAMPLE128X, 7),
330 Averaging::Samples256 => (true, Adc4OversamplingRatio::OVERSAMPLE256X, 8),
331 };
332
333 T::regs().cfgr2().modify(|w| {
334 w.set_ovsr(samples);
335 w.set_ovss(right_shift);
336 w.set_ovse(enable)
337 })
338 }
339
340 /// Read an ADC channel.
341 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
342 channel.setup();
343
344 // Select channel
345 T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32));
346 T::regs().chselrmod0().modify(|w| {
347 w.set_chsel(channel.channel() as usize, true);
348 });
349
350 // Reset interrupts
351 T::regs().isr().modify(|reg| {
352 reg.set_eos(true);
353 reg.set_eoc(true);
354 });
355
356 // Start conversion
357 T::regs().cr().modify(|reg| {
358 reg.set_adstart(true);
359 });
360
361 while !T::regs().isr().read().eos() {
362 // spin
363 }
364
365 T::regs().dr().read().0 as u16
366 }
367
368 /// Read one or multiple ADC channels using DMA.
369 ///
370 /// `sequence` iterator and `readings` must have the same length.
371 /// The channels in `sequence` must be in ascending order.
372 ///
373 /// Example
374 /// ```rust,ignore
375 /// use embassy_stm32::adc::adc4;
376 /// use embassy_stm32::adc::AdcChannel;
377 ///
378 /// let mut adc4 = adc4::Adc4::new(p.ADC4);
379 /// let mut adc4_pin1 = p.PC1;
380 /// let mut adc4_pin2 = p.PC0;
381 /// let mut.into()d41 = adc4_pin1.into();
382 /// let mut.into()d42 = adc4_pin2.into();
383 /// let mut measurements = [0u16; 2];
384 /// // not that the channels must be in ascending order
385 /// adc4.read(
386 /// &mut p.GPDMA1_CH1,
387 /// [
388 /// &mut.into()d42,
389 /// &mut.into()d41,
390 /// ]
391 /// .into_iter(),
392 /// &mut measurements,
393 /// ).await.unwrap();
394 /// ```
395 pub async fn read(
396 &mut self,
397 rx_dma: Peri<'_, impl RxDma4<T>>,
398 sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
399 readings: &mut [u16],
400 ) -> Result<(), Adc4Error> {
401 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
402 assert!(
403 sequence.len() == readings.len(),
404 "Sequence length must be equal to readings length"
405 );
406
407 // Ensure no conversions are ongoing
408 Self::cancel_conversions();
409
410 T::regs().isr().modify(|reg| {
411 reg.set_ovr(true);
412 reg.set_eos(true);
413 reg.set_eoc(true);
414 });
415
416 T::regs().cfgr1().modify(|reg| {
417 reg.set_dmaen(true);
418 reg.set_dmacfg(Adc4Dmacfg::ONE_SHOT);
419 reg.set_chselrmod(false);
420 });
421
422 // Verify and activate sequence
423 let mut prev_channel: i16 = -1;
424 T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32));
425 for channel in sequence {
426 let channel_num = channel.channel;
427 if channel_num as i16 <= prev_channel {
428 return Err(Adc4Error::InvalidSequence);
429 };
430 prev_channel = channel_num as i16;
431
432 T::regs().chselrmod0().modify(|w| {
433 w.set_chsel(channel.channel as usize, true);
434 });
435 }
436
437 let request = rx_dma.request();
438 let transfer = unsafe {
439 Transfer::new_read(
440 rx_dma,
441 request,
442 T::regs().dr().as_ptr() as *mut u16,
443 readings,
444 Default::default(),
445 )
446 };
447
448 // Start conversion
449 T::regs().cr().modify(|reg| {
450 reg.set_adstart(true);
451 });
452
453 transfer.await;
454
455 // Ensure conversions are finished.
456 Self::cancel_conversions();
457
458 // Reset configuration.
459 T::regs().cfgr1().modify(|reg| {
460 reg.set_dmaen(false);
461 });
462
463 if T::regs().isr().read().ovr() {
464 Err(Adc4Error::DMAError)
465 } else {
466 Ok(())
467 }
468 }
469
470 fn cancel_conversions() {
471 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
472 T::regs().cr().modify(|reg| {
473 reg.set_adstp(true);
474 });
475 while T::regs().cr().read().adstart() {}
476 }
477 }
478}
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 9bec2e13b..fb6f5b7d0 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -2,7 +2,6 @@ use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref;
6#[cfg(adc_l0)] 5#[cfg(adc_l0)]
7use stm32_metapac::adc::vals::Ckmode; 6use stm32_metapac::adc::vals::Ckmode;
8 7
@@ -10,7 +9,7 @@ use super::blocking_delay_us;
10use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 9use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
11use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
12use crate::peripherals::ADC1; 11use crate::peripherals::ADC1;
13use crate::{interrupt, rcc, Peripheral}; 12use crate::{interrupt, rcc, Peri};
14 13
15pub const VDDA_CALIB_MV: u32 = 3300; 14pub const VDDA_CALIB_MV: u32 = 3300;
16pub const VREF_INT: u32 = 1230; 15pub const VREF_INT: u32 = 1230;
@@ -63,10 +62,9 @@ impl super::SealedAdcChannel<ADC1> for Temperature {
63 62
64impl<'d, T: Instance> Adc<'d, T> { 63impl<'d, T: Instance> Adc<'d, T> {
65 pub fn new( 64 pub fn new(
66 adc: impl Peripheral<P = T> + 'd, 65 adc: Peri<'d, T>,
67 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 66 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
68 ) -> Self { 67 ) -> Self {
69 into_ref!(adc);
70 rcc::enable_and_reset::<T>(); 68 rcc::enable_and_reset::<T>();
71 69
72 // Delay 1μs when using HSI14 as the ADC clock. 70 // Delay 1μs when using HSI14 as the ADC clock.
@@ -160,7 +158,7 @@ impl<'d, T: Instance> Adc<'d, T> {
160 channel.setup(); 158 channel.setup();
161 159
162 // A.7.5 Single conversion sequence code example - Software trigger 160 // A.7.5 Single conversion sequence code example - Software trigger
163 T::regs().chselr().write(|reg| reg.set_chselx(ch_num as usize, true)); 161 T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true));
164 162
165 self.convert().await 163 self.convert().await
166 } 164 }
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 842a5ee6d..e94a25b24 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,10 +1,8 @@
1use embassy_hal_internal::into_ref;
2
3use super::blocking_delay_us; 1use super::blocking_delay_us;
4use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 2use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
5use crate::peripherals::ADC1; 3use crate::peripherals::ADC1;
6use crate::time::Hertz; 4use crate::time::Hertz;
7use crate::{rcc, Peripheral}; 5use crate::{rcc, Peri};
8 6
9mod ringbuffered_v2; 7mod ringbuffered_v2;
10pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; 8pub use ringbuffered_v2::{RingBufferedAdc, Sequence};
@@ -97,8 +95,7 @@ impl<'d, T> Adc<'d, T>
97where 95where
98 T: Instance, 96 T: Instance,
99{ 97{
100 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 98 pub fn new(adc: Peri<'d, T>) -> Self {
101 into_ref!(adc);
102 rcc::enable_and_reset::<T>(); 99 rcc::enable_and_reset::<T>();
103 100
104 let presc = Prescaler::from_pclk2(T::frequency()); 101 let presc = Prescaler::from_pclk2(T::frequency());
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 9441e42ff..313244e19 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,12 +1,11 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2use embassy_hal_internal::into_ref;
3use pac::adc::vals::Dmacfg; 2use pac::adc::vals::Dmacfg;
4 3
5use super::{ 4use super::{
6 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 5 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
7}; 6};
8use crate::dma::Transfer; 7use crate::dma::Transfer;
9use crate::{pac, rcc, Peripheral}; 8use crate::{pac, rcc, Peri};
10 9
11/// Default VREF voltage used for sample conversion to millivolts. 10/// Default VREF voltage used for sample conversion to millivolts.
12pub const VREF_DEFAULT_MV: u32 = 3300; 11pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -20,7 +19,7 @@ impl<T: Instance> SealedAdcChannel<T> for VrefInt {
20 cfg_if! { 19 cfg_if! {
21 if #[cfg(adc_g0)] { 20 if #[cfg(adc_g0)] {
22 let val = 13; 21 let val = 13;
23 } else if #[cfg(adc_h5)] { 22 } else if #[cfg(any(adc_h5, adc_h7rs))] {
24 let val = 17; 23 let val = 17;
25 } else if #[cfg(adc_u0)] { 24 } else if #[cfg(adc_u0)] {
26 let val = 12; 25 let val = 12;
@@ -39,7 +38,7 @@ impl<T: Instance> SealedAdcChannel<T> for Temperature {
39 cfg_if! { 38 cfg_if! {
40 if #[cfg(adc_g0)] { 39 if #[cfg(adc_g0)] {
41 let val = 12; 40 let val = 12;
42 } else if #[cfg(adc_h5)] { 41 } else if #[cfg(any(adc_h5, adc_h7rs))] {
43 let val = 16; 42 let val = 16;
44 } else if #[cfg(adc_u0)] { 43 } else if #[cfg(adc_u0)] {
45 let val = 11; 44 let val = 11;
@@ -58,9 +57,9 @@ impl<T: Instance> SealedAdcChannel<T> for Vbat {
58 cfg_if! { 57 cfg_if! {
59 if #[cfg(adc_g0)] { 58 if #[cfg(adc_g0)] {
60 let val = 14; 59 let val = 14;
61 } else if #[cfg(adc_h5)] { 60 } else if #[cfg(any(adc_h5, adc_h7rs))] {
62 let val = 2; 61 let val = 2;
63 } else if #[cfg(adc_h5)] { 62 } else if #[cfg(any(adc_h5, adc_h7rs))] {
64 let val = 13; 63 let val = 13;
65 } else { 64 } else {
66 let val = 18; 65 let val = 18;
@@ -71,7 +70,7 @@ impl<T: Instance> SealedAdcChannel<T> for Vbat {
71} 70}
72 71
73cfg_if! { 72cfg_if! {
74 if #[cfg(adc_h5)] { 73 if #[cfg(any(adc_h5, adc_h7rs))] {
75 pub struct VddCore; 74 pub struct VddCore;
76 impl<T: Instance> AdcChannel<T> for VddCore {} 75 impl<T: Instance> AdcChannel<T> for VddCore {}
77 impl<T: Instance> super::SealedAdcChannel<T> for VddCore { 76 impl<T: Instance> super::SealedAdcChannel<T> for VddCore {
@@ -95,8 +94,7 @@ cfg_if! {
95} 94}
96 95
97impl<'d, T: Instance> Adc<'d, T> { 96impl<'d, T: Instance> Adc<'d, T> {
98 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 97 pub fn new(adc: Peri<'d, T>) -> Self {
99 into_ref!(adc);
100 rcc::enable_and_reset::<T>(); 98 rcc::enable_and_reset::<T>();
101 T::regs().cr().modify(|reg| { 99 T::regs().cr().modify(|reg| {
102 #[cfg(not(any(adc_g0, adc_u0)))] 100 #[cfg(not(any(adc_g0, adc_u0)))]
@@ -173,7 +171,7 @@ impl<'d, T: Instance> Adc<'d, T> {
173 T::regs().ccr().modify(|reg| { 171 T::regs().ccr().modify(|reg| {
174 reg.set_tsen(true); 172 reg.set_tsen(true);
175 }); 173 });
176 } else if #[cfg(adc_h5)] { 174 } else if #[cfg(any(adc_h5, adc_h7rs))] {
177 T::common_regs().ccr().modify(|reg| { 175 T::common_regs().ccr().modify(|reg| {
178 reg.set_tsen(true); 176 reg.set_tsen(true);
179 }); 177 });
@@ -193,7 +191,7 @@ impl<'d, T: Instance> Adc<'d, T> {
193 T::regs().ccr().modify(|reg| { 191 T::regs().ccr().modify(|reg| {
194 reg.set_vbaten(true); 192 reg.set_vbaten(true);
195 }); 193 });
196 } else if #[cfg(adc_h5)] { 194 } else if #[cfg(any(adc_h5, adc_h7rs))] {
197 T::common_regs().ccr().modify(|reg| { 195 T::common_regs().ccr().modify(|reg| {
198 reg.set_vbaten(true); 196 reg.set_vbaten(true);
199 }); 197 });
@@ -262,6 +260,9 @@ impl<'d, T: Instance> Adc<'d, T> {
262 /// 260 ///
263 /// `sequence` iterator and `readings` must have the same length. 261 /// `sequence` iterator and `readings` must have the same length.
264 /// 262 ///
263 /// Note: The order of values in `readings` is defined by the pin ADC
264 /// channel number and not the pin order in `sequence`.
265 ///
265 /// Example 266 /// Example
266 /// ```rust,ignore 267 /// ```rust,ignore
267 /// use embassy_stm32::adc::{Adc, AdcChannel} 268 /// use embassy_stm32::adc::{Adc, AdcChannel}
@@ -271,8 +272,8 @@ impl<'d, T: Instance> Adc<'d, T> {
271 /// let mut adc_pin1 = p.PA1.degrade_adc(); 272 /// let mut adc_pin1 = p.PA1.degrade_adc();
272 /// let mut measurements = [0u16; 2]; 273 /// let mut measurements = [0u16; 2];
273 /// 274 ///
274 /// adc.read_async( 275 /// adc.read(
275 /// p.DMA1_CH2, 276 /// p.DMA1_CH2.reborrow(),
276 /// [ 277 /// [
277 /// (&mut *adc_pin0, SampleTime::CYCLES160_5), 278 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
278 /// (&mut *adc_pin1, SampleTime::CYCLES160_5), 279 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
@@ -285,7 +286,7 @@ impl<'d, T: Instance> Adc<'d, T> {
285 /// ``` 286 /// ```
286 pub async fn read( 287 pub async fn read(
287 &mut self, 288 &mut self,
288 rx_dma: &mut impl RxDma<T>, 289 rx_dma: Peri<'_, impl RxDma<T>>,
289 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, 290 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
290 readings: &mut [u16], 291 readings: &mut [u16],
291 ) { 292 ) {
@@ -366,14 +367,14 @@ impl<'d, T: Instance> Adc<'d, T> {
366 T::regs().cfgr().modify(|reg| { 367 T::regs().cfgr().modify(|reg| {
367 reg.set_discen(false); 368 reg.set_discen(false);
368 reg.set_cont(true); 369 reg.set_cont(true);
369 reg.set_dmacfg(Dmacfg::ONESHOT); 370 reg.set_dmacfg(Dmacfg::ONE_SHOT);
370 reg.set_dmaen(true); 371 reg.set_dmaen(true);
371 }); 372 });
372 #[cfg(any(adc_g0, adc_u0))] 373 #[cfg(any(adc_g0, adc_u0))]
373 T::regs().cfgr1().modify(|reg| { 374 T::regs().cfgr1().modify(|reg| {
374 reg.set_discen(false); 375 reg.set_discen(false);
375 reg.set_cont(true); 376 reg.set_cont(true);
376 reg.set_dmacfg(Dmacfg::ONESHOT); 377 reg.set_dmacfg(Dmacfg::ONE_SHOT);
377 reg.set_dmaen(true); 378 reg.set_dmaen(true);
378 }); 379 });
379 380
@@ -413,7 +414,7 @@ impl<'d, T: Instance> Adc<'d, T> {
413 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 414 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
414 // RM0492, RM0481, etc. 415 // RM0492, RM0481, etc.
415 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 416 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
416 #[cfg(adc_h5)] 417 #[cfg(any(adc_h5, adc_h7rs))]
417 if channel.channel() == 0 { 418 if channel.channel() == 0 {
418 T::regs().or().modify(|reg| reg.set_op0(true)); 419 T::regs().or().modify(|reg| reg.set_op0(true));
419 } 420 }
@@ -446,7 +447,7 @@ impl<'d, T: Instance> Adc<'d, T> {
446 447
447 // RM0492, RM0481, etc. 448 // RM0492, RM0481, etc.
448 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 449 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
449 #[cfg(adc_h5)] 450 #[cfg(any(adc_h5, adc_h7rs))]
450 if channel.channel() == 0 { 451 if channel.channel() == 0 {
451 T::regs().or().modify(|reg| reg.set_op0(false)); 452 T::regs().or().modify(|reg| reg.set_op0(false));
452 } 453 }
@@ -474,7 +475,7 @@ impl<'d, T: Instance> Adc<'d, T> {
474 if #[cfg(any(adc_g0, adc_u0))] { 475 if #[cfg(any(adc_g0, adc_u0))] {
475 // On G0 and U6 all channels use the same sampling time. 476 // On G0 and U6 all channels use the same sampling time.
476 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 477 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
477 } else if #[cfg(adc_h5)] { 478 } else if #[cfg(any(adc_h5, adc_h7rs))] {
478 match _ch { 479 match _ch {
479 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 480 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())),
480 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 481 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())),
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 63b5b58ea..39e0d51b9 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -1,5 +1,7 @@
1#[cfg(not(stm32u5))]
2use pac::adc::vals::{Adcaldif, Boost};
1#[allow(unused)] 3#[allow(unused)]
2use pac::adc::vals::{Adcaldif, Adstp, Boost, Difsel, Dmngt, Exten, Pcsel}; 4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
3use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
4 6
5use super::{ 7use super::{
@@ -7,7 +9,7 @@ use super::{
7}; 9};
8use crate::dma::Transfer; 10use crate::dma::Transfer;
9use crate::time::Hertz; 11use crate::time::Hertz;
10use crate::{pac, rcc, Peripheral}; 12use crate::{pac, rcc, Peri};
11 13
12/// Default VREF voltage used for sample conversion to millivolts. 14/// Default VREF voltage used for sample conversion to millivolts.
13pub const VREF_DEFAULT_MV: u32 = 3300; 15pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -19,6 +21,8 @@ pub const VREF_CALIB_MV: u32 = 3300;
19const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); 21const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
20#[cfg(stm32h7)] 22#[cfg(stm32h7)]
21const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
24#[cfg(stm32u5)]
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
22 26
23#[cfg(stm32g4)] 27#[cfg(stm32g4)]
24const VREF_CHANNEL: u8 = 18; 28const VREF_CHANNEL: u8 = 18;
@@ -31,8 +35,16 @@ const VREF_CHANNEL: u8 = 19;
31const TEMP_CHANNEL: u8 = 18; 35const TEMP_CHANNEL: u8 = 18;
32 36
33// TODO this should be 14 for H7a/b/35 37// TODO this should be 14 for H7a/b/35
38#[cfg(not(stm32u5))]
34const VBAT_CHANNEL: u8 = 17; 39const VBAT_CHANNEL: u8 = 17;
35 40
41#[cfg(stm32u5)]
42const VREF_CHANNEL: u8 = 0;
43#[cfg(stm32u5)]
44const TEMP_CHANNEL: u8 = 19;
45#[cfg(stm32u5)]
46const VBAT_CHANNEL: u8 = 18;
47
36// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 48// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
37/// Internal voltage reference channel. 49/// Internal voltage reference channel.
38pub struct VrefInt; 50pub struct VrefInt;
@@ -146,8 +158,7 @@ pub enum Averaging {
146 158
147impl<'d, T: Instance> Adc<'d, T> { 159impl<'d, T: Instance> Adc<'d, T> {
148 /// Create a new ADC driver. 160 /// Create a new ADC driver.
149 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 161 pub fn new(adc: Peri<'d, T>) -> Self {
150 embassy_hal_internal::into_ref!(adc);
151 rcc::enable_and_reset::<T>(); 162 rcc::enable_and_reset::<T>();
152 163
153 let prescaler = Prescaler::from_ker_ck(T::frequency()); 164 let prescaler = Prescaler::from_ker_ck(T::frequency());
@@ -155,7 +166,7 @@ impl<'d, T: Instance> Adc<'d, T> {
155 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 166 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
156 167
157 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 168 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
158 info!("ADC frequency set to {} Hz", frequency.0); 169 info!("ADC frequency set to {}", frequency);
159 170
160 if frequency > MAX_ADC_CLK_FREQ { 171 if frequency > MAX_ADC_CLK_FREQ {
161 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 172 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
@@ -202,14 +213,15 @@ impl<'d, T: Instance> Adc<'d, T> {
202 fn configure_differential_inputs(&mut self) { 213 fn configure_differential_inputs(&mut self) {
203 T::regs().difsel().modify(|w| { 214 T::regs().difsel().modify(|w| {
204 for n in 0..20 { 215 for n in 0..20 {
205 w.set_difsel(n, Difsel::SINGLEENDED); 216 w.set_difsel(n, Difsel::SINGLE_ENDED);
206 } 217 }
207 }); 218 });
208 } 219 }
209 220
210 fn calibrate(&mut self) { 221 fn calibrate(&mut self) {
211 T::regs().cr().modify(|w| { 222 T::regs().cr().modify(|w| {
212 w.set_adcaldif(Adcaldif::SINGLEENDED); 223 #[cfg(not(adc_u5))]
224 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
213 w.set_adcallin(true); 225 w.set_adcallin(true);
214 }); 226 });
215 227
@@ -293,7 +305,7 @@ impl<'d, T: Instance> Adc<'d, T> {
293 305
294 T::regs().cfgr2().modify(|reg| { 306 T::regs().cfgr2().modify(|reg| {
295 reg.set_rovse(enable); 307 reg.set_rovse(enable);
296 reg.set_osvr(samples); 308 reg.set_ovsr(samples);
297 reg.set_ovss(right_shift); 309 reg.set_ovss(right_shift);
298 }) 310 })
299 } 311 }
@@ -331,12 +343,12 @@ impl<'d, T: Instance> Adc<'d, T> {
331 /// use embassy_stm32::adc::{Adc, AdcChannel} 343 /// use embassy_stm32::adc::{Adc, AdcChannel}
332 /// 344 ///
333 /// let mut adc = Adc::new(p.ADC1); 345 /// let mut adc = Adc::new(p.ADC1);
334 /// let mut adc_pin0 = p.PA0.degrade_adc(); 346 /// let mut adc_pin0 = p.PA0.into();
335 /// let mut adc_pin2 = p.PA2.degrade_adc(); 347 /// let mut adc_pin2 = p.PA2.into();
336 /// let mut measurements = [0u16; 2]; 348 /// let mut measurements = [0u16; 2];
337 /// 349 ///
338 /// adc.read_async( 350 /// adc.read(
339 /// p.DMA2_CH0, 351 /// p.DMA2_CH0.reborrow(),
340 /// [ 352 /// [
341 /// (&mut *adc_pin0, SampleTime::CYCLES112), 353 /// (&mut *adc_pin0, SampleTime::CYCLES112),
342 /// (&mut *adc_pin2, SampleTime::CYCLES112), 354 /// (&mut *adc_pin2, SampleTime::CYCLES112),
@@ -349,7 +361,7 @@ impl<'d, T: Instance> Adc<'d, T> {
349 /// ``` 361 /// ```
350 pub async fn read( 362 pub async fn read(
351 &mut self, 363 &mut self,
352 rx_dma: &mut impl RxDma<T>, 364 rx_dma: Peri<'_, impl RxDma<T>>,
353 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, 365 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
354 readings: &mut [u16], 366 readings: &mut [u16],
355 ) { 367 ) {
@@ -407,7 +419,7 @@ impl<'d, T: Instance> Adc<'d, T> {
407 }); 419 });
408 T::regs().cfgr().modify(|reg| { 420 T::regs().cfgr().modify(|reg| {
409 reg.set_cont(true); 421 reg.set_cont(true);
410 reg.set_dmngt(Dmngt::DMA_ONESHOT); 422 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
411 }); 423 });
412 424
413 let request = rx_dma.request(); 425 let request = rx_dma.request();
@@ -446,7 +458,7 @@ impl<'d, T: Instance> Adc<'d, T> {
446 458
447 Self::set_channel_sample_time(channel, sample_time); 459 Self::set_channel_sample_time(channel, sample_time);
448 460
449 #[cfg(stm32h7)] 461 #[cfg(any(stm32h7, stm32u5))]
450 { 462 {
451 T::regs().cfgr2().modify(|w| w.set_lshift(0)); 463 T::regs().cfgr2().modify(|w| w.set_lshift(0));
452 T::regs() 464 T::regs()
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 278c93ff4..305666d5b 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -6,7 +6,7 @@ use core::marker::PhantomData;
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_hal_internal::interrupt::InterruptExt; 8use embassy_hal_internal::interrupt::InterruptExt;
9use embassy_hal_internal::into_ref; 9use embassy_hal_internal::PeripheralType;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
11use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
@@ -17,11 +17,11 @@ use self::registers::{Registers, RxFifo};
17pub use super::common::{BufferedCanReceiver, BufferedCanSender}; 17pub use super::common::{BufferedCanReceiver, BufferedCanSender};
18use super::frame::{Envelope, Frame}; 18use super::frame::{Envelope, Frame};
19use super::util; 19use super::util;
20use crate::can::enums::{BusError, TryReadError}; 20use crate::can::enums::{BusError, InternalOperation, TryReadError};
21use crate::gpio::{AfType, OutputType, Pull, Speed}; 21use crate::gpio::{AfType, OutputType, Pull, Speed};
22use crate::interrupt::typelevel::Interrupt; 22use crate::interrupt::typelevel::Interrupt;
23use crate::rcc::{self, RccPeripheral}; 23use crate::rcc::{self, RccPeripheral};
24use crate::{interrupt, peripherals, Peripheral}; 24use crate::{interrupt, peripherals, Peri};
25 25
26/// Interrupt handler. 26/// Interrupt handler.
27pub struct TxInterruptHandler<T: Instance> { 27pub struct TxInterruptHandler<T: Instance> {
@@ -68,7 +68,6 @@ pub struct SceInterruptHandler<T: Instance> {
68 68
69impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { 69impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> {
70 unsafe fn on_interrupt() { 70 unsafe fn on_interrupt() {
71 info!("sce irq");
72 let msr = T::regs().msr(); 71 let msr = T::regs().msr();
73 let msr_val = msr.read(); 72 let msr_val = msr.read();
74 73
@@ -76,9 +75,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
76 msr.modify(|m| m.set_slaki(true)); 75 msr.modify(|m| m.set_slaki(true));
77 T::state().err_waker.wake(); 76 T::state().err_waker.wake();
78 } else if msr_val.erri() { 77 } else if msr_val.erri() {
79 info!("Error interrupt");
80 // Disable the interrupt, but don't acknowledge the error, so that it can be 78 // Disable the interrupt, but don't acknowledge the error, so that it can be
81 // forwarded off the the bus message consumer. If we don't provide some way for 79 // forwarded off the bus message consumer. If we don't provide some way for
82 // downstream code to determine that it has already provided this bus error instance 80 // downstream code to determine that it has already provided this bus error instance
83 // to the bus message consumer, we are doomed to re-provide a single error instance for 81 // to the bus message consumer, we are doomed to re-provide a single error instance for
84 // an indefinite amount of time. 82 // an indefinite amount of time.
@@ -175,16 +173,15 @@ impl<'d> Can<'d> {
175 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. 173 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
176 /// You must call [Can::enable_non_blocking] to use the peripheral. 174 /// You must call [Can::enable_non_blocking] to use the peripheral.
177 pub fn new<T: Instance>( 175 pub fn new<T: Instance>(
178 _peri: impl Peripheral<P = T> + 'd, 176 _peri: Peri<'d, T>,
179 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 177 rx: Peri<'d, impl RxPin<T>>,
180 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 178 tx: Peri<'d, impl TxPin<T>>,
181 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> 179 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
182 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> 180 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
183 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> 181 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
184 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> 182 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
185 + 'd, 183 + 'd,
186 ) -> Self { 184 ) -> Self {
187 into_ref!(_peri, rx, tx);
188 let info = T::info(); 185 let info = T::info();
189 let regs = &T::info().regs; 186 let regs = &T::info().regs;
190 187
@@ -504,6 +501,14 @@ impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_
504 pub fn reader(&self) -> BufferedCanReceiver { 501 pub fn reader(&self) -> BufferedCanReceiver {
505 self.rx.reader() 502 self.rx.reader()
506 } 503 }
504
505 /// Accesses the filter banks owned by this CAN peripheral.
506 ///
507 /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
508 /// peripheral instead.
509 pub fn modify_filters(&mut self) -> MasterFilters<'_> {
510 self.rx.modify_filters()
511 }
507} 512}
508 513
509/// CAN driver, transmit half. 514/// CAN driver, transmit half.
@@ -679,22 +684,18 @@ impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> {
679 684
680 /// Returns a sender that can be used for sending CAN frames. 685 /// Returns a sender that can be used for sending CAN frames.
681 pub fn writer(&self) -> BufferedCanSender { 686 pub fn writer(&self) -> BufferedCanSender {
687 (self.info.internal_operation)(InternalOperation::NotifySenderCreated);
682 BufferedCanSender { 688 BufferedCanSender {
683 tx_buf: self.tx_buf.sender().into(), 689 tx_buf: self.tx_buf.sender().into(),
684 waker: self.info.tx_waker, 690 waker: self.info.tx_waker,
691 internal_operation: self.info.internal_operation,
685 } 692 }
686 } 693 }
687} 694}
688 695
689impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> { 696impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> {
690 fn drop(&mut self) { 697 fn drop(&mut self) {
691 critical_section::with(|_| { 698 (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed);
692 let state = self.state as *const State;
693 unsafe {
694 let mut_state = state as *mut State;
695 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
696 }
697 });
698 } 699 }
699} 700}
700 701
@@ -735,6 +736,14 @@ impl<'d> CanRx<'d> {
735 ) -> BufferedCanRx<'d, RX_BUF_SIZE> { 736 ) -> BufferedCanRx<'d, RX_BUF_SIZE> {
736 BufferedCanRx::new(self.info, self.state, self, rxb) 737 BufferedCanRx::new(self.info, self.state, self, rxb)
737 } 738 }
739
740 /// Accesses the filter banks owned by this CAN peripheral.
741 ///
742 /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
743 /// peripheral instead.
744 pub fn modify_filters(&mut self) -> MasterFilters<'_> {
745 unsafe { MasterFilters::new(self.info) }
746 }
738} 747}
739 748
740/// User supplied buffer for RX Buffering 749/// User supplied buffer for RX Buffering
@@ -744,16 +753,16 @@ pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<
744pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> { 753pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> {
745 info: &'static Info, 754 info: &'static Info,
746 state: &'static State, 755 state: &'static State,
747 _rx: CanRx<'d>, 756 rx: CanRx<'d>,
748 rx_buf: &'static RxBuf<RX_BUF_SIZE>, 757 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
749} 758}
750 759
751impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { 760impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
752 fn new(info: &'static Info, state: &'static State, _rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { 761 fn new(info: &'static Info, state: &'static State, rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
753 BufferedCanRx { 762 BufferedCanRx {
754 info, 763 info,
755 state, 764 state,
756 _rx, 765 rx,
757 rx_buf, 766 rx_buf,
758 } 767 }
759 .setup() 768 .setup()
@@ -811,19 +820,25 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
811 820
812 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 821 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
813 pub fn reader(&self) -> BufferedCanReceiver { 822 pub fn reader(&self) -> BufferedCanReceiver {
814 self.rx_buf.receiver().into() 823 (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
824 BufferedCanReceiver {
825 rx_buf: self.rx_buf.receiver().into(),
826 internal_operation: self.info.internal_operation,
827 }
828 }
829
830 /// Accesses the filter banks owned by this CAN peripheral.
831 ///
832 /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
833 /// peripheral instead.
834 pub fn modify_filters(&mut self) -> MasterFilters<'_> {
835 self.rx.modify_filters()
815 } 836 }
816} 837}
817 838
818impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> { 839impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> {
819 fn drop(&mut self) { 840 fn drop(&mut self) {
820 critical_section::with(|_| { 841 (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
821 let state = self.state as *const State;
822 unsafe {
823 let mut_state = state as *mut State;
824 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
825 }
826 });
827 } 842 }
828} 843}
829 844
@@ -895,7 +910,7 @@ impl RxMode {
895 RxFifo::Fifo0 => 0usize, 910 RxFifo::Fifo0 => 0usize,
896 RxFifo::Fifo1 => 1usize, 911 RxFifo::Fifo1 => 1usize,
897 }; 912 };
898 T::regs().ier().write(|w| { 913 T::regs().ier().modify(|w| {
899 w.set_fmpie(fifo_idx, false); 914 w.set_fmpie(fifo_idx, false);
900 }); 915 });
901 waker.wake(); 916 waker.wake();
@@ -938,18 +953,22 @@ impl RxMode {
938 Self::NonBuffered(_) => { 953 Self::NonBuffered(_) => {
939 let registers = &info.regs; 954 let registers = &info.regs;
940 if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { 955 if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) {
941 registers.0.ier().write(|w| { 956 registers.0.ier().modify(|w| {
942 w.set_fmpie(0, true); 957 w.set_fmpie(0, true);
943 }); 958 });
944 Ok(msg) 959 Ok(msg)
945 } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) { 960 } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) {
946 registers.0.ier().write(|w| { 961 registers.0.ier().modify(|w| {
947 w.set_fmpie(1, true); 962 w.set_fmpie(1, true);
948 }); 963 });
949 Ok(msg) 964 Ok(msg)
950 } else if let Some(err) = registers.curr_error() { 965 } else if let Some(err) = registers.curr_error() {
951 Err(TryReadError::BusError(err)) 966 Err(TryReadError::BusError(err))
952 } else { 967 } else {
968 registers.0.ier().modify(|w| {
969 w.set_fmpie(0, true);
970 w.set_fmpie(1, true);
971 });
953 Err(TryReadError::Empty) 972 Err(TryReadError::Empty)
954 } 973 }
955 } 974 }
@@ -1022,6 +1041,8 @@ pub(crate) struct State {
1022 pub(crate) rx_mode: RxMode, 1041 pub(crate) rx_mode: RxMode,
1023 pub(crate) tx_mode: TxMode, 1042 pub(crate) tx_mode: TxMode,
1024 pub err_waker: AtomicWaker, 1043 pub err_waker: AtomicWaker,
1044 receiver_instance_count: usize,
1045 sender_instance_count: usize,
1025} 1046}
1026 1047
1027impl State { 1048impl State {
@@ -1030,6 +1051,8 @@ impl State {
1030 rx_mode: RxMode::NonBuffered(AtomicWaker::new()), 1051 rx_mode: RxMode::NonBuffered(AtomicWaker::new()),
1031 tx_mode: TxMode::NonBuffered(AtomicWaker::new()), 1052 tx_mode: TxMode::NonBuffered(AtomicWaker::new()),
1032 err_waker: AtomicWaker::new(), 1053 err_waker: AtomicWaker::new(),
1054 receiver_instance_count: 1,
1055 sender_instance_count: 1,
1033 } 1056 }
1034 } 1057 }
1035} 1058}
@@ -1041,6 +1064,7 @@ pub(crate) struct Info {
1041 rx1_interrupt: crate::interrupt::Interrupt, 1064 rx1_interrupt: crate::interrupt::Interrupt,
1042 sce_interrupt: crate::interrupt::Interrupt, 1065 sce_interrupt: crate::interrupt::Interrupt,
1043 tx_waker: fn(), 1066 tx_waker: fn(),
1067 internal_operation: fn(InternalOperation),
1044 1068
1045 /// The total number of filter banks available to the instance. 1069 /// The total number of filter banks available to the instance.
1046 /// 1070 ///
@@ -1053,11 +1077,12 @@ trait SealedInstance {
1053 fn regs() -> crate::pac::can::Can; 1077 fn regs() -> crate::pac::can::Can;
1054 fn state() -> &'static State; 1078 fn state() -> &'static State;
1055 unsafe fn mut_state() -> &'static mut State; 1079 unsafe fn mut_state() -> &'static mut State;
1080 fn internal_operation(val: InternalOperation);
1056} 1081}
1057 1082
1058/// CAN instance trait. 1083/// CAN instance trait.
1059#[allow(private_bounds)] 1084#[allow(private_bounds)]
1060pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + 'static { 1085pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {
1061 /// TX interrupt for this instance. 1086 /// TX interrupt for this instance.
1062 type TXInterrupt: crate::interrupt::typelevel::Interrupt; 1087 type TXInterrupt: crate::interrupt::typelevel::Interrupt;
1063 /// RX0 interrupt for this instance. 1088 /// RX0 interrupt for this instance.
@@ -1110,6 +1135,7 @@ foreach_peripheral!(
1110 rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ, 1135 rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ,
1111 sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ, 1136 sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ,
1112 tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend, 1137 tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend,
1138 internal_operation: peripherals::$inst::internal_operation,
1113 num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS, 1139 num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS,
1114 }; 1140 };
1115 &INFO 1141 &INFO
@@ -1125,6 +1151,37 @@ foreach_peripheral!(
1125 fn state() -> &'static State { 1151 fn state() -> &'static State {
1126 unsafe { peripherals::$inst::mut_state() } 1152 unsafe { peripherals::$inst::mut_state() }
1127 } 1153 }
1154
1155
1156 fn internal_operation(val: InternalOperation) {
1157 critical_section::with(|_| {
1158 //let state = self.state as *const State;
1159 unsafe {
1160 //let mut_state = state as *mut State;
1161 let mut_state = peripherals::$inst::mut_state();
1162 match val {
1163 InternalOperation::NotifySenderCreated => {
1164 mut_state.sender_instance_count += 1;
1165 }
1166 InternalOperation::NotifySenderDestroyed => {
1167 mut_state.sender_instance_count -= 1;
1168 if ( 0 == mut_state.sender_instance_count) {
1169 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
1170 }
1171 }
1172 InternalOperation::NotifyReceiverCreated => {
1173 mut_state.receiver_instance_count += 1;
1174 }
1175 InternalOperation::NotifyReceiverDestroyed => {
1176 mut_state.receiver_instance_count -= 1;
1177 if ( 0 == mut_state.receiver_instance_count) {
1178 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
1179 }
1180 }
1181 }
1182 }
1183 });
1184 }
1128 } 1185 }
1129 1186
1130 impl Instance for peripherals::$inst { 1187 impl Instance for peripherals::$inst {
diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs
index c5de1c683..c295b0f50 100644
--- a/embassy-stm32/src/can/bxcan/registers.rs
+++ b/embassy-stm32/src/can/bxcan/registers.rs
@@ -2,7 +2,7 @@ use core::cmp::Ordering;
2use core::convert::Infallible; 2use core::convert::Infallible;
3 3
4pub use embedded_can::{ExtendedId, Id, StandardId}; 4pub use embedded_can::{ExtendedId, Id, StandardId};
5use stm32_metapac::can::vals::Lec; 5use stm32_metapac::can::vals::{Lec, Rtr};
6 6
7use super::{Mailbox, TransmitStatus}; 7use super::{Mailbox, TransmitStatus};
8use crate::can::enums::BusError; 8use crate::can::enums::BusError;
@@ -166,16 +166,16 @@ impl Registers {
166 return Some(BusError::BusPassive); 166 return Some(BusError::BusPassive);
167 } else if err.ewgf() { 167 } else if err.ewgf() {
168 return Some(BusError::BusWarning); 168 return Some(BusError::BusWarning);
169 } else if err.lec() != Lec::NOERROR { 169 } else if err.lec() != Lec::NO_ERROR {
170 return Some(match err.lec() { 170 return Some(match err.lec() {
171 Lec::STUFF => BusError::Stuff, 171 Lec::STUFF => BusError::Stuff,
172 Lec::FORM => BusError::Form, 172 Lec::FORM => BusError::Form,
173 Lec::ACK => BusError::Acknowledge, 173 Lec::ACK => BusError::Acknowledge,
174 Lec::BITRECESSIVE => BusError::BitRecessive, 174 Lec::BIT_RECESSIVE => BusError::BitRecessive,
175 Lec::BITDOMINANT => BusError::BitDominant, 175 Lec::BIT_DOMINANT => BusError::BitDominant,
176 Lec::CRC => BusError::Crc, 176 Lec::CRC => BusError::Crc,
177 Lec::CUSTOM => BusError::Software, 177 Lec::CUSTOM => BusError::Software,
178 Lec::NOERROR => unreachable!(), 178 Lec::NO_ERROR => unreachable!(),
179 }); 179 });
180 } 180 }
181 None 181 None
@@ -299,13 +299,16 @@ impl Registers {
299 mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); 299 mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8));
300 300
301 mb.tdlr() 301 mb.tdlr()
302 .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.data()[0..4].try_into()))); 302 .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.raw_data()[0..4].try_into())));
303 mb.tdhr() 303 mb.tdhr()
304 .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.data()[4..8].try_into()))); 304 .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.raw_data()[4..8].try_into())));
305 let id: IdReg = frame.id().into(); 305 let id: IdReg = frame.id().into();
306 mb.tir().write(|w| { 306 mb.tir().write(|w| {
307 w.0 = id.0; 307 w.0 = id.0;
308 w.set_txrq(true); 308 w.set_txrq(true);
309 if frame.header().rtr() {
310 w.set_rtr(Rtr::REMOTE);
311 }
309 }); 312 });
310 } 313 }
311 314
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs
index a54b54f6e..386d4467c 100644
--- a/embassy-stm32/src/can/common.rs
+++ b/embassy-stm32/src/can/common.rs
@@ -1,43 +1,43 @@
1use embassy_sync::channel::{DynamicReceiver, DynamicSender}; 1use embassy_sync::channel::{SendDynamicReceiver, SendDynamicSender};
2 2
3use super::enums::*; 3use super::enums::*;
4use super::frame::*; 4use super::frame::*;
5 5
6pub(crate) struct ClassicBufferedRxInner { 6pub(crate) struct ClassicBufferedRxInner {
7 pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>, 7 pub rx_sender: SendDynamicSender<'static, Result<Envelope, BusError>>,
8} 8}
9pub(crate) struct ClassicBufferedTxInner { 9pub(crate) struct ClassicBufferedTxInner {
10 pub tx_receiver: DynamicReceiver<'static, Frame>, 10 pub tx_receiver: SendDynamicReceiver<'static, Frame>,
11} 11}
12 12
13#[cfg(any(can_fdcan_v1, can_fdcan_h7))] 13#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
14 14
15pub(crate) struct FdBufferedRxInner { 15pub(crate) struct FdBufferedRxInner {
16 pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>, 16 pub rx_sender: SendDynamicSender<'static, Result<FdEnvelope, BusError>>,
17} 17}
18 18
19#[cfg(any(can_fdcan_v1, can_fdcan_h7))] 19#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
20pub(crate) struct FdBufferedTxInner { 20pub(crate) struct FdBufferedTxInner {
21 pub tx_receiver: DynamicReceiver<'static, FdFrame>, 21 pub tx_receiver: SendDynamicReceiver<'static, FdFrame>,
22} 22}
23 23
24/// Sender that can be used for sending CAN frames. 24/// Sender that can be used for sending CAN frames.
25#[derive(Copy, Clone)] 25pub struct BufferedSender<'ch, FRAME> {
26pub struct BufferedCanSender { 26 pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>,
27 pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>,
28 pub(crate) waker: fn(), 27 pub(crate) waker: fn(),
28 pub(crate) internal_operation: fn(InternalOperation),
29} 29}
30 30
31impl BufferedCanSender { 31impl<'ch, FRAME> BufferedSender<'ch, FRAME> {
32 /// Async write frame to TX buffer. 32 /// Async write frame to TX buffer.
33 pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError<Frame>> { 33 pub fn try_write(&mut self, frame: FRAME) -> Result<(), embassy_sync::channel::TrySendError<FRAME>> {
34 self.tx_buf.try_send(frame)?; 34 self.tx_buf.try_send(frame)?;
35 (self.waker)(); 35 (self.waker)();
36 Ok(()) 36 Ok(())
37 } 37 }
38 38
39 /// Async write frame to TX buffer. 39 /// Async write frame to TX buffer.
40 pub async fn write(&mut self, frame: Frame) { 40 pub async fn write(&mut self, frame: FRAME) {
41 self.tx_buf.send(frame).await; 41 self.tx_buf.send(frame).await;
42 (self.waker)(); 42 (self.waker)();
43 } 43 }
@@ -48,5 +48,77 @@ impl BufferedCanSender {
48 } 48 }
49} 49}
50 50
51impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> {
52 fn clone(&self) -> Self {
53 (self.internal_operation)(InternalOperation::NotifySenderCreated);
54 Self {
55 tx_buf: self.tx_buf,
56 waker: self.waker,
57 internal_operation: self.internal_operation,
58 }
59 }
60}
61
62impl<'ch, FRAME> Drop for BufferedSender<'ch, FRAME> {
63 fn drop(&mut self) {
64 (self.internal_operation)(InternalOperation::NotifySenderDestroyed);
65 }
66}
67
68/// Sender that can be used for sending Classic CAN frames.
69pub type BufferedCanSender = BufferedSender<'static, Frame>;
70
51/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 71/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
52pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<Envelope, BusError>>; 72pub struct BufferedReceiver<'ch, ENVELOPE> {
73 pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result<ENVELOPE, BusError>>,
74 pub(crate) internal_operation: fn(InternalOperation),
75}
76
77impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> {
78 /// Receive the next frame.
79 ///
80 /// See [`Channel::receive()`].
81 pub fn receive(&self) -> embassy_sync::channel::DynamicReceiveFuture<'_, Result<ENVELOPE, BusError>> {
82 self.rx_buf.receive()
83 }
84
85 /// Attempt to immediately receive the next frame.
86 ///
87 /// See [`Channel::try_receive()`]
88 pub fn try_receive(&self) -> Result<Result<ENVELOPE, BusError>, embassy_sync::channel::TryReceiveError> {
89 self.rx_buf.try_receive()
90 }
91
92 /// Allows a poll_fn to poll until the channel is ready to receive
93 ///
94 /// See [`Channel::poll_ready_to_receive()`]
95 pub fn poll_ready_to_receive(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
96 self.rx_buf.poll_ready_to_receive(cx)
97 }
98
99 /// Poll the channel for the next frame
100 ///
101 /// See [`Channel::poll_receive()`]
102 pub fn poll_receive(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<Result<ENVELOPE, BusError>> {
103 self.rx_buf.poll_receive(cx)
104 }
105}
106
107impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> {
108 fn clone(&self) -> Self {
109 (self.internal_operation)(InternalOperation::NotifyReceiverCreated);
110 Self {
111 rx_buf: self.rx_buf,
112 internal_operation: self.internal_operation,
113 }
114 }
115}
116
117impl<'ch, ENVELOPE> Drop for BufferedReceiver<'ch, ENVELOPE> {
118 fn drop(&mut self) {
119 (self.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
120 }
121}
122
123/// A BufferedCanReceiver for Classic CAN frames.
124pub type BufferedCanReceiver = BufferedReceiver<'static, Envelope>;
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs
index a5cca424d..97cb47640 100644
--- a/embassy-stm32/src/can/enums.rs
+++ b/embassy-stm32/src/can/enums.rs
@@ -68,3 +68,17 @@ pub enum TryReadError {
68 /// Receive buffer is empty 68 /// Receive buffer is empty
69 Empty, 69 Empty,
70} 70}
71
72/// Internal Operation
73#[derive(Debug)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub enum InternalOperation {
76 /// Notify receiver created
77 NotifyReceiverCreated,
78 /// Notify receiver destroyed
79 NotifyReceiverDestroyed,
80 /// Notify sender created
81 NotifySenderCreated,
82 /// Notify sender destroyed
83 NotifySenderDestroyed,
84}
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
index 68161ca50..c6a66b469 100644
--- a/embassy-stm32/src/can/fd/config.rs
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -328,11 +328,15 @@ pub struct FdCanConfig {
328 /// 328 ///
329 /// Automatic retransmission is enabled by default. 329 /// Automatic retransmission is enabled by default.
330 pub automatic_retransmit: bool, 330 pub automatic_retransmit: bool,
331 /// Enabled or disables the pausing between transmissions 331 /// The transmit pause feature is intended for use in CAN systems where the CAN message
332 /// identifiers are permanently specified to specific values and cannot easily be changed.
332 /// 333 ///
333 /// This feature looses up burst transmissions coming from a single node and it protects against 334 /// These message identifiers can have a higher CAN arbitration priority than other defined
334 /// "babbling idiot" scenarios where the application program erroneously requests too many 335 /// messages, while in a specific application their relative arbitration priority must be inverse.
335 /// transmissions. 336 ///
337 /// This may lead to a case where one ECU sends a burst of CAN messages that cause
338 /// another ECU CAN messages to be delayed because that other messages have a lower
339 /// CAN arbitration priority.
336 pub transmit_pause: bool, 340 pub transmit_pause: bool,
337 /// Enabled or disables the pausing between transmissions 341 /// Enabled or disables the pausing between transmissions
338 /// 342 ///
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 07e3dddad..0a22f2c91 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -71,11 +71,28 @@ impl Registers {
71 } 71 }
72 } 72 }
73 73
74 #[cfg(feature = "time")]
75 pub fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
76 let now_embassy = embassy_time::Instant::now();
77 if ns_per_timer_tick == 0 {
78 return now_embassy;
79 }
80 let cantime = { self.regs.tscv().read().tsc() };
81 let delta = cantime.overflowing_sub(ts_val).0 as u64;
82 let ns = ns_per_timer_tick * delta as u64;
83 now_embassy - embassy_time::Duration::from_nanos(ns)
84 }
85
86 #[cfg(not(feature = "time"))]
87 pub fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
88 ts_val
89 }
90
74 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { 91 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
75 let mailbox = self.tx_buffer_element(bufidx); 92 let mailbox = self.tx_buffer_element(bufidx);
76 mailbox.reset(); 93 mailbox.reset();
77 put_tx_header(mailbox, header); 94 put_tx_header(mailbox, header);
78 put_tx_data(mailbox, &buffer[..header.len() as usize]); 95 put_tx_data(mailbox, buffer);
79 96
80 // Set <idx as Mailbox> as ready to transmit 97 // Set <idx as Mailbox> as ready to transmit
81 self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); 98 self.regs.txbar().modify(|w| w.set_ar(bufidx, true));
@@ -190,7 +207,7 @@ impl Registers {
190 DataLength::Fdcan(len) => len, 207 DataLength::Fdcan(len) => len,
191 DataLength::Classic(len) => len, 208 DataLength::Classic(len) => len,
192 }; 209 };
193 if len as usize > ClassicData::MAX_DATA_LEN { 210 if len as usize > 8 {
194 return None; 211 return None;
195 } 212 }
196 213
@@ -200,7 +217,7 @@ impl Registers {
200 if header_reg.rtr().bit() { 217 if header_reg.rtr().bit() {
201 F::new_remote(id, len as usize) 218 F::new_remote(id, len as usize)
202 } else { 219 } else {
203 F::new(id, &data) 220 F::new(id, &data[0..(len as usize)])
204 } 221 }
205 } else { 222 } else {
206 // Abort request failed because the frame was already sent (or being sent) on 223 // Abort request failed because the frame was already sent (or being sent) on
@@ -458,7 +475,7 @@ impl Registers {
458 /// [`FdCanConfig::set_transmit_pause`] 475 /// [`FdCanConfig::set_transmit_pause`]
459 #[inline] 476 #[inline]
460 pub fn set_transmit_pause(&self, enabled: bool) { 477 pub fn set_transmit_pause(&self, enabled: bool) {
461 self.regs.cccr().modify(|w| w.set_txp(!enabled)); 478 self.regs.cccr().modify(|w| w.set_txp(enabled));
462 } 479 }
463 480
464 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`] 481 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index c549313f3..97d22315a 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -4,16 +4,16 @@ use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_internal::interrupt::InterruptExt; 6use embassy_hal_internal::interrupt::InterruptExt;
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::PeripheralType;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; 9use embassy_sync::channel::Channel;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12use crate::can::fd::peripheral::Registers; 12use crate::can::fd::peripheral::Registers;
13use crate::gpio::{AfType, OutputType, Pull, Speed}; 13use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, peripherals, Peripheral}; 16use crate::{interrupt, peripherals, Peri};
17 17
18pub(crate) mod fd; 18pub(crate) mod fd;
19 19
@@ -52,36 +52,39 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
52 regs.ir().write(|w| w.set_tefn(true)); 52 regs.ir().write(|w| w.set_tefn(true));
53 } 53 }
54 54
55 match &T::state().tx_mode { 55 T::info().state.lock(|s| {
56 TxMode::NonBuffered(waker) => waker.wake(), 56 let state = s.borrow_mut();
57 TxMode::ClassicBuffered(buf) => { 57 match &state.tx_mode {
58 if !T::registers().tx_queue_is_full() { 58 TxMode::NonBuffered(waker) => waker.wake(),
59 match buf.tx_receiver.try_receive() { 59 TxMode::ClassicBuffered(buf) => {
60 Ok(frame) => { 60 if !T::registers().tx_queue_is_full() {
61 _ = T::registers().write(&frame); 61 match buf.tx_receiver.try_receive() {
62 Ok(frame) => {
63 _ = T::registers().write(&frame);
64 }
65 Err(_) => {}
62 } 66 }
63 Err(_) => {}
64 } 67 }
65 } 68 }
66 } 69 TxMode::FdBuffered(buf) => {
67 TxMode::FdBuffered(buf) => { 70 if !T::registers().tx_queue_is_full() {
68 if !T::registers().tx_queue_is_full() { 71 match buf.tx_receiver.try_receive() {
69 match buf.tx_receiver.try_receive() { 72 Ok(frame) => {
70 Ok(frame) => { 73 _ = T::registers().write(&frame);
71 _ = T::registers().write(&frame); 74 }
75 Err(_) => {}
72 } 76 }
73 Err(_) => {}
74 } 77 }
75 } 78 }
76 } 79 }
77 }
78 80
79 if ir.rfn(0) { 81 if ir.rfn(0) {
80 T::state().rx_mode.on_interrupt::<T>(0); 82 state.rx_mode.on_interrupt::<T>(0, state.ns_per_timer_tick);
81 } 83 }
82 if ir.rfn(1) { 84 if ir.rfn(1) {
83 T::state().rx_mode.on_interrupt::<T>(1); 85 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick);
84 } 86 }
87 });
85 88
86 if ir.bo() { 89 if ir.bo() {
87 regs.ir().write(|w| w.set_bo(true)); 90 regs.ir().write(|w| w.set_bo(true));
@@ -165,7 +168,6 @@ pub struct CanConfigurator<'d> {
165 _phantom: PhantomData<&'d ()>, 168 _phantom: PhantomData<&'d ()>,
166 config: crate::can::fd::config::FdCanConfig, 169 config: crate::can::fd::config::FdCanConfig,
167 info: &'static Info, 170 info: &'static Info,
168 state: &'static State,
169 /// Reference to internals. 171 /// Reference to internals.
170 properties: Properties, 172 properties: Properties,
171 periph_clock: crate::time::Hertz, 173 periph_clock: crate::time::Hertz,
@@ -175,27 +177,30 @@ impl<'d> CanConfigurator<'d> {
175 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. 177 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
176 /// You must call [Fdcan::enable_non_blocking] to use the peripheral. 178 /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
177 pub fn new<T: Instance>( 179 pub fn new<T: Instance>(
178 _peri: impl Peripheral<P = T> + 'd, 180 _peri: Peri<'d, T>,
179 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 181 rx: Peri<'d, impl RxPin<T>>,
180 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 182 tx: Peri<'d, impl TxPin<T>>,
181 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> 183 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
182 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> 184 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
183 + 'd, 185 + 'd,
184 ) -> CanConfigurator<'d> { 186 ) -> CanConfigurator<'d> {
185 into_ref!(_peri, rx, tx);
186
187 rx.set_as_af(rx.af_num(), AfType::input(Pull::None)); 187 rx.set_as_af(rx.af_num(), AfType::input(Pull::None));
188 tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 188 tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
189 189
190 rcc::enable_and_reset::<T>(); 190 rcc::enable_and_reset::<T>();
191 191
192 let info = T::info();
193 T::info().state.lock(|s| {
194 s.borrow_mut().tx_pin_port = Some(tx.pin_port());
195 s.borrow_mut().rx_pin_port = Some(rx.pin_port());
196 });
197 (info.internal_operation)(InternalOperation::NotifySenderCreated);
198 (info.internal_operation)(InternalOperation::NotifyReceiverCreated);
199
192 let mut config = crate::can::fd::config::FdCanConfig::default(); 200 let mut config = crate::can::fd::config::FdCanConfig::default();
193 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); 201 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
194 T::registers().into_config_mode(config); 202 T::registers().into_config_mode(config);
195 203
196 rx.set_as_af(rx.af_num(), AfType::input(Pull::None));
197 tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
198
199 unsafe { 204 unsafe {
200 T::IT0Interrupt::unpend(); // Not unsafe 205 T::IT0Interrupt::unpend(); // Not unsafe
201 T::IT0Interrupt::enable(); 206 T::IT0Interrupt::enable();
@@ -206,8 +211,7 @@ impl<'d> CanConfigurator<'d> {
206 Self { 211 Self {
207 _phantom: PhantomData, 212 _phantom: PhantomData,
208 config, 213 config,
209 info: T::info(), 214 info,
210 state: T::state(),
211 properties: Properties::new(T::info()), 215 properties: Properties::new(T::info()),
212 periph_clock: T::frequency(), 216 periph_clock: T::frequency(),
213 } 217 }
@@ -259,19 +263,16 @@ impl<'d> CanConfigurator<'d> {
259 /// Start in mode. 263 /// Start in mode.
260 pub fn start(self, mode: OperatingMode) -> Can<'d> { 264 pub fn start(self, mode: OperatingMode) -> Can<'d> {
261 let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit); 265 let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit);
262 critical_section::with(|_| { 266 self.info.state.lock(|s| {
263 let state = self.state as *const State; 267 s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick;
264 unsafe {
265 let mut_state = state as *mut State;
266 (*mut_state).ns_per_timer_tick = ns_per_timer_tick;
267 }
268 }); 268 });
269 self.info.regs.into_mode(self.config, mode); 269 self.info.regs.into_mode(self.config, mode);
270 (self.info.internal_operation)(InternalOperation::NotifySenderCreated);
271 (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
270 Can { 272 Can {
271 _phantom: PhantomData, 273 _phantom: PhantomData,
272 config: self.config, 274 config: self.config,
273 info: self.info, 275 info: self.info,
274 state: self.state,
275 _mode: mode, 276 _mode: mode,
276 properties: Properties::new(self.info), 277 properties: Properties::new(self.info),
277 } 278 }
@@ -293,12 +294,18 @@ impl<'d> CanConfigurator<'d> {
293 } 294 }
294} 295}
295 296
297impl<'d> Drop for CanConfigurator<'d> {
298 fn drop(&mut self) {
299 (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed);
300 (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
301 }
302}
303
296/// FDCAN Instance 304/// FDCAN Instance
297pub struct Can<'d> { 305pub struct Can<'d> {
298 _phantom: PhantomData<&'d ()>, 306 _phantom: PhantomData<&'d ()>,
299 config: crate::can::fd::config::FdCanConfig, 307 config: crate::can::fd::config::FdCanConfig,
300 info: &'static Info, 308 info: &'static Info,
301 state: &'static State,
302 _mode: OperatingMode, 309 _mode: OperatingMode,
303 properties: Properties, 310 properties: Properties,
304} 311}
@@ -312,7 +319,9 @@ impl<'d> Can<'d> {
312 /// Flush one of the TX mailboxes. 319 /// Flush one of the TX mailboxes.
313 pub async fn flush(&self, idx: usize) { 320 pub async fn flush(&self, idx: usize) {
314 poll_fn(|cx| { 321 poll_fn(|cx| {
315 self.state.tx_mode.register(cx.waker()); 322 self.info.state.lock(|s| {
323 s.borrow_mut().tx_mode.register(cx.waker());
324 });
316 325
317 if idx > 3 { 326 if idx > 3 {
318 panic!("Bad mailbox"); 327 panic!("Bad mailbox");
@@ -332,12 +341,12 @@ impl<'d> Can<'d> {
332 /// can be replaced, this call asynchronously waits for a frame to be successfully 341 /// can be replaced, this call asynchronously waits for a frame to be successfully
333 /// transmitted, then tries again. 342 /// transmitted, then tries again.
334 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { 343 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
335 self.state.tx_mode.write(self.info, frame).await 344 TxMode::write(self.info, frame).await
336 } 345 }
337 346
338 /// Returns the next received message frame 347 /// Returns the next received message frame
339 pub async fn read(&mut self) -> Result<Envelope, BusError> { 348 pub async fn read(&mut self) -> Result<Envelope, BusError> {
340 self.state.rx_mode.read_classic(self.info, self.state).await 349 RxMode::read_classic(self.info).await
341 } 350 }
342 351
343 /// Queues the message to be sent but exerts backpressure. If a lower-priority 352 /// Queues the message to be sent but exerts backpressure. If a lower-priority
@@ -345,40 +354,43 @@ impl<'d> Can<'d> {
345 /// can be replaced, this call asynchronously waits for a frame to be successfully 354 /// can be replaced, this call asynchronously waits for a frame to be successfully
346 /// transmitted, then tries again. 355 /// transmitted, then tries again.
347 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { 356 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
348 self.state.tx_mode.write_fd(self.info, frame).await 357 TxMode::write_fd(self.info, frame).await
349 } 358 }
350 359
351 /// Returns the next received message frame 360 /// Returns the next received message frame
352 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { 361 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
353 self.state.rx_mode.read_fd(self.info, self.state).await 362 RxMode::read_fd(self.info).await
354 } 363 }
355 364
356 /// Split instance into separate portions: Tx(write), Rx(read), common properties 365 /// Split instance into separate portions: Tx(write), Rx(read), common properties
357 pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { 366 pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) {
367 (self.info.internal_operation)(InternalOperation::NotifySenderCreated);
368 (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
358 ( 369 (
359 CanTx { 370 CanTx {
360 _phantom: PhantomData, 371 _phantom: PhantomData,
361 info: self.info, 372 info: self.info,
362 state: self.state,
363 config: self.config, 373 config: self.config,
364 _mode: self._mode, 374 _mode: self._mode,
365 }, 375 },
366 CanRx { 376 CanRx {
367 _phantom: PhantomData, 377 _phantom: PhantomData,
368 info: self.info, 378 info: self.info,
369 state: self.state,
370 _mode: self._mode, 379 _mode: self._mode,
371 }, 380 },
372 self.properties, 381 Properties {
382 info: self.properties.info,
383 },
373 ) 384 )
374 } 385 }
375 /// Join split rx and tx portions back together 386 /// Join split rx and tx portions back together
376 pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { 387 pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self {
388 (tx.info.internal_operation)(InternalOperation::NotifySenderCreated);
389 (tx.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
377 Can { 390 Can {
378 _phantom: PhantomData, 391 _phantom: PhantomData,
379 config: tx.config, 392 config: tx.config,
380 info: tx.info, 393 info: tx.info,
381 state: tx.state,
382 _mode: rx._mode, 394 _mode: rx._mode,
383 properties: Properties::new(tx.info), 395 properties: Properties::new(tx.info),
384 } 396 }
@@ -390,7 +402,7 @@ impl<'d> Can<'d> {
390 tx_buf: &'static mut TxBuf<TX_BUF_SIZE>, 402 tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
391 rxb: &'static mut RxBuf<RX_BUF_SIZE>, 403 rxb: &'static mut RxBuf<RX_BUF_SIZE>,
392 ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { 404 ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
393 BufferedCan::new(self.info, self.state, self._mode, tx_buf, rxb) 405 BufferedCan::new(self.info, self._mode, tx_buf, rxb)
394 } 406 }
395 407
396 /// Return a buffered instance of driver with CAN FD support. User must supply Buffers 408 /// Return a buffered instance of driver with CAN FD support. User must supply Buffers
@@ -399,7 +411,14 @@ impl<'d> Can<'d> {
399 tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>, 411 tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
400 rxb: &'static mut RxFdBuf<RX_BUF_SIZE>, 412 rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
401 ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { 413 ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
402 BufferedCanFd::new(self.info, self.state, self._mode, tx_buf, rxb) 414 BufferedCanFd::new(self.info, self._mode, tx_buf, rxb)
415 }
416}
417
418impl<'d> Drop for Can<'d> {
419 fn drop(&mut self) {
420 (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed);
421 (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
403 } 422 }
404} 423}
405 424
@@ -413,7 +432,6 @@ pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame,
413pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { 432pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
414 _phantom: PhantomData<&'d ()>, 433 _phantom: PhantomData<&'d ()>,
415 info: &'static Info, 434 info: &'static Info,
416 state: &'static State,
417 _mode: OperatingMode, 435 _mode: OperatingMode,
418 tx_buf: &'static TxBuf<TX_BUF_SIZE>, 436 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
419 rx_buf: &'static RxBuf<RX_BUF_SIZE>, 437 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
@@ -423,15 +441,15 @@ pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
423impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { 441impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
424 fn new( 442 fn new(
425 info: &'static Info, 443 info: &'static Info,
426 state: &'static State,
427 _mode: OperatingMode, 444 _mode: OperatingMode,
428 tx_buf: &'static TxBuf<TX_BUF_SIZE>, 445 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
429 rx_buf: &'static RxBuf<RX_BUF_SIZE>, 446 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
430 ) -> Self { 447 ) -> Self {
448 (info.internal_operation)(InternalOperation::NotifySenderCreated);
449 (info.internal_operation)(InternalOperation::NotifyReceiverCreated);
431 BufferedCan { 450 BufferedCan {
432 _phantom: PhantomData, 451 _phantom: PhantomData,
433 info, 452 info,
434 state,
435 _mode, 453 _mode,
436 tx_buf, 454 tx_buf,
437 rx_buf, 455 rx_buf,
@@ -447,19 +465,15 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
447 465
448 fn setup(self) -> Self { 466 fn setup(self) -> Self {
449 // We don't want interrupts being processed while we change modes. 467 // We don't want interrupts being processed while we change modes.
450 critical_section::with(|_| { 468 self.info.state.lock(|s| {
451 let rx_inner = super::common::ClassicBufferedRxInner { 469 let rx_inner = super::common::ClassicBufferedRxInner {
452 rx_sender: self.rx_buf.sender().into(), 470 rx_sender: self.rx_buf.sender().into(),
453 }; 471 };
454 let tx_inner = super::common::ClassicBufferedTxInner { 472 let tx_inner = super::common::ClassicBufferedTxInner {
455 tx_receiver: self.tx_buf.receiver().into(), 473 tx_receiver: self.tx_buf.receiver().into(),
456 }; 474 };
457 let state = self.state as *const State; 475 s.borrow_mut().rx_mode = RxMode::ClassicBuffered(rx_inner);
458 unsafe { 476 s.borrow_mut().tx_mode = TxMode::ClassicBuffered(tx_inner);
459 let mut_state = state as *mut State;
460 (*mut_state).rx_mode = RxMode::ClassicBuffered(rx_inner);
461 (*mut_state).tx_mode = TxMode::ClassicBuffered(tx_inner);
462 }
463 }); 477 });
464 self 478 self
465 } 479 }
@@ -478,28 +492,28 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
478 492
479 /// Returns a sender that can be used for sending CAN frames. 493 /// Returns a sender that can be used for sending CAN frames.
480 pub fn writer(&self) -> BufferedCanSender { 494 pub fn writer(&self) -> BufferedCanSender {
495 (self.info.internal_operation)(InternalOperation::NotifySenderCreated);
481 BufferedCanSender { 496 BufferedCanSender {
482 tx_buf: self.tx_buf.sender().into(), 497 tx_buf: self.tx_buf.sender().into(),
483 waker: self.info.tx_waker, 498 waker: self.info.tx_waker,
499 internal_operation: self.info.internal_operation,
484 } 500 }
485 } 501 }
486 502
487 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 503 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
488 pub fn reader(&self) -> BufferedCanReceiver { 504 pub fn reader(&self) -> BufferedCanReceiver {
489 self.rx_buf.receiver().into() 505 (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
506 BufferedCanReceiver {
507 rx_buf: self.rx_buf.receiver().into(),
508 internal_operation: self.info.internal_operation,
509 }
490 } 510 }
491} 511}
492 512
493impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { 513impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
494 fn drop(&mut self) { 514 fn drop(&mut self) {
495 critical_section::with(|_| { 515 (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed);
496 let state = self.state as *const State; 516 (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
497 unsafe {
498 let mut_state = state as *mut State;
499 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
500 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
501 }
502 });
503 } 517 }
504} 518}
505 519
@@ -509,41 +523,16 @@ pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Resul
509/// User supplied buffer for TX buffering 523/// User supplied buffer for TX buffering
510pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; 524pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
511 525
512/// Sender that can be used for sending CAN frames. 526/// Sender that can be used for sending Classic CAN frames.
513#[derive(Copy, Clone)] 527pub type BufferedFdCanSender = super::common::BufferedSender<'static, FdFrame>;
514pub struct BufferedFdCanSender {
515 tx_buf: DynamicSender<'static, FdFrame>,
516 waker: fn(),
517}
518
519impl BufferedFdCanSender {
520 /// Async write frame to TX buffer.
521 pub fn try_write(&mut self, frame: FdFrame) -> Result<(), embassy_sync::channel::TrySendError<FdFrame>> {
522 self.tx_buf.try_send(frame)?;
523 (self.waker)();
524 Ok(())
525 }
526
527 /// Async write frame to TX buffer.
528 pub async fn write(&mut self, frame: FdFrame) {
529 self.tx_buf.send(frame).await;
530 (self.waker)();
531 }
532
533 /// Allows a poll_fn to poll until the channel is ready to write
534 pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
535 self.tx_buf.poll_ready_to_send(cx)
536 }
537}
538 528
539/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 529/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
540pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>; 530pub type BufferedFdCanReceiver = super::common::BufferedReceiver<'static, FdEnvelope>;
541 531
542/// Buffered FDCAN Instance 532/// Buffered FDCAN Instance
543pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { 533pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
544 _phantom: PhantomData<&'d ()>, 534 _phantom: PhantomData<&'d ()>,
545 info: &'static Info, 535 info: &'static Info,
546 state: &'static State,
547 _mode: OperatingMode, 536 _mode: OperatingMode,
548 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, 537 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
549 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, 538 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
@@ -553,15 +542,15 @@ pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
553impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { 542impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
554 fn new( 543 fn new(
555 info: &'static Info, 544 info: &'static Info,
556 state: &'static State,
557 _mode: OperatingMode, 545 _mode: OperatingMode,
558 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, 546 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
559 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, 547 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
560 ) -> Self { 548 ) -> Self {
549 (info.internal_operation)(InternalOperation::NotifySenderCreated);
550 (info.internal_operation)(InternalOperation::NotifyReceiverCreated);
561 BufferedCanFd { 551 BufferedCanFd {
562 _phantom: PhantomData, 552 _phantom: PhantomData,
563 info, 553 info,
564 state,
565 _mode, 554 _mode,
566 tx_buf, 555 tx_buf,
567 rx_buf, 556 rx_buf,
@@ -577,19 +566,15 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
577 566
578 fn setup(self) -> Self { 567 fn setup(self) -> Self {
579 // We don't want interrupts being processed while we change modes. 568 // We don't want interrupts being processed while we change modes.
580 critical_section::with(|_| { 569 self.info.state.lock(|s| {
581 let rx_inner = super::common::FdBufferedRxInner { 570 let rx_inner = super::common::FdBufferedRxInner {
582 rx_sender: self.rx_buf.sender().into(), 571 rx_sender: self.rx_buf.sender().into(),
583 }; 572 };
584 let tx_inner = super::common::FdBufferedTxInner { 573 let tx_inner = super::common::FdBufferedTxInner {
585 tx_receiver: self.tx_buf.receiver().into(), 574 tx_receiver: self.tx_buf.receiver().into(),
586 }; 575 };
587 let state = self.state as *const State; 576 s.borrow_mut().rx_mode = RxMode::FdBuffered(rx_inner);
588 unsafe { 577 s.borrow_mut().tx_mode = TxMode::FdBuffered(tx_inner);
589 let mut_state = state as *mut State;
590 (*mut_state).rx_mode = RxMode::FdBuffered(rx_inner);
591 (*mut_state).tx_mode = TxMode::FdBuffered(tx_inner);
592 }
593 }); 578 });
594 self 579 self
595 } 580 }
@@ -608,28 +593,28 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
608 593
609 /// Returns a sender that can be used for sending CAN frames. 594 /// Returns a sender that can be used for sending CAN frames.
610 pub fn writer(&self) -> BufferedFdCanSender { 595 pub fn writer(&self) -> BufferedFdCanSender {
596 (self.info.internal_operation)(InternalOperation::NotifySenderCreated);
611 BufferedFdCanSender { 597 BufferedFdCanSender {
612 tx_buf: self.tx_buf.sender().into(), 598 tx_buf: self.tx_buf.sender().into(),
613 waker: self.info.tx_waker, 599 waker: self.info.tx_waker,
600 internal_operation: self.info.internal_operation,
614 } 601 }
615 } 602 }
616 603
617 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 604 /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
618 pub fn reader(&self) -> BufferedFdCanReceiver { 605 pub fn reader(&self) -> BufferedFdCanReceiver {
619 self.rx_buf.receiver().into() 606 (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated);
607 BufferedFdCanReceiver {
608 rx_buf: self.rx_buf.receiver().into(),
609 internal_operation: self.info.internal_operation,
610 }
620 } 611 }
621} 612}
622 613
623impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { 614impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
624 fn drop(&mut self) { 615 fn drop(&mut self) {
625 critical_section::with(|_| { 616 (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed);
626 let state = self.state as *const State; 617 (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
627 unsafe {
628 let mut_state = state as *mut State;
629 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
630 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
631 }
632 });
633 } 618 }
634} 619}
635 620
@@ -637,19 +622,24 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for Buffer
637pub struct CanRx<'d> { 622pub struct CanRx<'d> {
638 _phantom: PhantomData<&'d ()>, 623 _phantom: PhantomData<&'d ()>,
639 info: &'static Info, 624 info: &'static Info,
640 state: &'static State,
641 _mode: OperatingMode, 625 _mode: OperatingMode,
642} 626}
643 627
644impl<'d> CanRx<'d> { 628impl<'d> CanRx<'d> {
645 /// Returns the next received message frame 629 /// Returns the next received message frame
646 pub async fn read(&mut self) -> Result<Envelope, BusError> { 630 pub async fn read(&mut self) -> Result<Envelope, BusError> {
647 self.state.rx_mode.read_classic(&self.info, &self.state).await 631 RxMode::read_classic(&self.info).await
648 } 632 }
649 633
650 /// Returns the next received message frame 634 /// Returns the next received message frame
651 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { 635 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
652 self.state.rx_mode.read_fd(&self.info, &self.state).await 636 RxMode::read_fd(&self.info).await
637 }
638}
639
640impl<'d> Drop for CanRx<'d> {
641 fn drop(&mut self) {
642 (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed);
653 } 643 }
654} 644}
655 645
@@ -657,7 +647,6 @@ impl<'d> CanRx<'d> {
657pub struct CanTx<'d> { 647pub struct CanTx<'d> {
658 _phantom: PhantomData<&'d ()>, 648 _phantom: PhantomData<&'d ()>,
659 info: &'static Info, 649 info: &'static Info,
660 state: &'static State,
661 config: crate::can::fd::config::FdCanConfig, 650 config: crate::can::fd::config::FdCanConfig,
662 _mode: OperatingMode, 651 _mode: OperatingMode,
663} 652}
@@ -668,7 +657,7 @@ impl<'c, 'd> CanTx<'d> {
668 /// can be replaced, this call asynchronously waits for a frame to be successfully 657 /// can be replaced, this call asynchronously waits for a frame to be successfully
669 /// transmitted, then tries again. 658 /// transmitted, then tries again.
670 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { 659 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
671 self.state.tx_mode.write(self.info, frame).await 660 TxMode::write(self.info, frame).await
672 } 661 }
673 662
674 /// Queues the message to be sent but exerts backpressure. If a lower-priority 663 /// Queues the message to be sent but exerts backpressure. If a lower-priority
@@ -676,7 +665,13 @@ impl<'c, 'd> CanTx<'d> {
676 /// can be replaced, this call asynchronously waits for a frame to be successfully 665 /// can be replaced, this call asynchronously waits for a frame to be successfully
677 /// transmitted, then tries again. 666 /// transmitted, then tries again.
678 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { 667 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
679 self.state.tx_mode.write_fd(self.info, frame).await 668 TxMode::write_fd(self.info, frame).await
669 }
670}
671
672impl<'d> Drop for CanTx<'d> {
673 fn drop(&mut self) {
674 (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed);
680 } 675 }
681} 676}
682 677
@@ -696,19 +691,19 @@ impl RxMode {
696 } 691 }
697 } 692 }
698 693
699 fn on_interrupt<T: Instance>(&self, fifonr: usize) { 694 fn on_interrupt<T: Instance>(&self, fifonr: usize, ns_per_timer_tick: u64) {
700 T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true)); 695 T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true));
701 match self { 696 match self {
702 RxMode::NonBuffered(waker) => { 697 RxMode::NonBuffered(waker) => {
703 waker.wake(); 698 waker.wake();
704 } 699 }
705 RxMode::ClassicBuffered(buf) => { 700 RxMode::ClassicBuffered(buf) => {
706 if let Some(result) = self.try_read::<T>() { 701 if let Some(result) = self.try_read::<T>(ns_per_timer_tick) {
707 let _ = buf.rx_sender.try_send(result); 702 let _ = buf.rx_sender.try_send(result);
708 } 703 }
709 } 704 }
710 RxMode::FdBuffered(buf) => { 705 RxMode::FdBuffered(buf) => {
711 if let Some(result) = self.try_read_fd::<T>() { 706 if let Some(result) = self.try_read_fd::<T>(ns_per_timer_tick) {
712 let _ = buf.rx_sender.try_send(result); 707 let _ = buf.rx_sender.try_send(result);
713 } 708 }
714 } 709 }
@@ -716,12 +711,12 @@ impl RxMode {
716 } 711 }
717 712
718 //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { 713 //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
719 fn try_read<T: Instance>(&self) -> Option<Result<Envelope, BusError>> { 714 fn try_read<T: Instance>(&self, ns_per_timer_tick: u64) -> Option<Result<Envelope, BusError>> {
720 if let Some((frame, ts)) = T::registers().read(0) { 715 if let Some((frame, ts)) = T::registers().read(0) {
721 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 716 let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts);
722 Some(Ok(Envelope { ts, frame })) 717 Some(Ok(Envelope { ts, frame }))
723 } else if let Some((frame, ts)) = T::registers().read(1) { 718 } else if let Some((frame, ts)) = T::registers().read(1) {
724 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 719 let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts);
725 Some(Ok(Envelope { ts, frame })) 720 Some(Ok(Envelope { ts, frame }))
726 } else if let Some(err) = T::registers().curr_error() { 721 } else if let Some(err) = T::registers().curr_error() {
727 // TODO: this is probably wrong 722 // TODO: this is probably wrong
@@ -731,12 +726,12 @@ impl RxMode {
731 } 726 }
732 } 727 }
733 728
734 fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> { 729 fn try_read_fd<T: Instance>(&self, ns_per_timer_tick: u64) -> Option<Result<FdEnvelope, BusError>> {
735 if let Some((frame, ts)) = T::registers().read(0) { 730 if let Some((frame, ts)) = T::registers().read(0) {
736 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 731 let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts);
737 Some(Ok(FdEnvelope { ts, frame })) 732 Some(Ok(FdEnvelope { ts, frame }))
738 } else if let Some((frame, ts)) = T::registers().read(1) { 733 } else if let Some((frame, ts)) = T::registers().read(1) {
739 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 734 let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts);
740 Some(Ok(FdEnvelope { ts, frame })) 735 Some(Ok(FdEnvelope { ts, frame }))
741 } else if let Some(err) = T::registers().curr_error() { 736 } else if let Some(err) = T::registers().curr_error() {
742 // TODO: this is probably wrong 737 // TODO: this is probably wrong
@@ -746,16 +741,12 @@ impl RxMode {
746 } 741 }
747 } 742 }
748 743
749 fn read<F: CanHeader>( 744 fn read<F: CanHeader>(info: &'static Info, ns_per_timer_tick: u64) -> Option<Result<(F, Timestamp), BusError>> {
750 &self,
751 info: &'static Info,
752 state: &'static State,
753 ) -> Option<Result<(F, Timestamp), BusError>> {
754 if let Some((msg, ts)) = info.regs.read(0) { 745 if let Some((msg, ts)) = info.regs.read(0) {
755 let ts = info.calc_timestamp(state.ns_per_timer_tick, ts); 746 let ts = info.regs.calc_timestamp(ns_per_timer_tick, ts);
756 Some(Ok((msg, ts))) 747 Some(Ok((msg, ts)))
757 } else if let Some((msg, ts)) = info.regs.read(1) { 748 } else if let Some((msg, ts)) = info.regs.read(1) {
758 let ts = info.calc_timestamp(state.ns_per_timer_tick, ts); 749 let ts = info.regs.calc_timestamp(ns_per_timer_tick, ts);
759 Some(Ok((msg, ts))) 750 Some(Ok((msg, ts)))
760 } else if let Some(err) = info.regs.curr_error() { 751 } else if let Some(err) = info.regs.curr_error() {
761 // TODO: this is probably wrong 752 // TODO: this is probably wrong
@@ -765,16 +756,15 @@ impl RxMode {
765 } 756 }
766 } 757 }
767 758
768 async fn read_async<F: CanHeader>( 759 async fn read_async<F: CanHeader>(info: &'static Info) -> Result<(F, Timestamp), BusError> {
769 &self,
770 info: &'static Info,
771 state: &'static State,
772 ) -> Result<(F, Timestamp), BusError> {
773 //let _ = self.read::<F>(info, state);
774 poll_fn(move |cx| { 760 poll_fn(move |cx| {
775 state.err_waker.register(cx.waker()); 761 let ns_per_timer_tick = info.state.lock(|s| {
776 self.register(cx.waker()); 762 let state = s.borrow_mut();
777 match self.read::<_>(info, state) { 763 state.err_waker.register(cx.waker());
764 state.rx_mode.register(cx.waker());
765 state.ns_per_timer_tick
766 });
767 match RxMode::read::<_>(info, ns_per_timer_tick) {
778 Some(result) => Poll::Ready(result), 768 Some(result) => Poll::Ready(result),
779 None => Poll::Pending, 769 None => Poll::Pending,
780 } 770 }
@@ -782,15 +772,15 @@ impl RxMode {
782 .await 772 .await
783 } 773 }
784 774
785 async fn read_classic(&self, info: &'static Info, state: &'static State) -> Result<Envelope, BusError> { 775 async fn read_classic(info: &'static Info) -> Result<Envelope, BusError> {
786 match self.read_async::<_>(info, state).await { 776 match RxMode::read_async::<_>(info).await {
787 Ok((frame, ts)) => Ok(Envelope { ts, frame }), 777 Ok((frame, ts)) => Ok(Envelope { ts, frame }),
788 Err(e) => Err(e), 778 Err(e) => Err(e),
789 } 779 }
790 } 780 }
791 781
792 async fn read_fd(&self, info: &'static Info, state: &'static State) -> Result<FdEnvelope, BusError> { 782 async fn read_fd(info: &'static Info) -> Result<FdEnvelope, BusError> {
793 match self.read_async::<_>(info, state).await { 783 match RxMode::read_async::<_>(info).await {
794 Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }), 784 Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
795 Err(e) => Err(e), 785 Err(e) => Err(e),
796 } 786 }
@@ -819,9 +809,11 @@ impl TxMode {
819 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 809 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
820 /// can be replaced, this call asynchronously waits for a frame to be successfully 810 /// can be replaced, this call asynchronously waits for a frame to be successfully
821 /// transmitted, then tries again. 811 /// transmitted, then tries again.
822 async fn write_generic<F: embedded_can::Frame + CanHeader>(&self, info: &'static Info, frame: &F) -> Option<F> { 812 async fn write_generic<F: embedded_can::Frame + CanHeader>(info: &'static Info, frame: &F) -> Option<F> {
823 poll_fn(|cx| { 813 poll_fn(|cx| {
824 self.register(cx.waker()); 814 info.state.lock(|s| {
815 s.borrow_mut().tx_mode.register(cx.waker());
816 });
825 817
826 if let Ok(dropped) = info.regs.write(frame) { 818 if let Ok(dropped) = info.regs.write(frame) {
827 return Poll::Ready(dropped); 819 return Poll::Ready(dropped);
@@ -838,16 +830,16 @@ impl TxMode {
838 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 830 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
839 /// can be replaced, this call asynchronously waits for a frame to be successfully 831 /// can be replaced, this call asynchronously waits for a frame to be successfully
840 /// transmitted, then tries again. 832 /// transmitted, then tries again.
841 async fn write(&self, info: &'static Info, frame: &Frame) -> Option<Frame> { 833 async fn write(info: &'static Info, frame: &Frame) -> Option<Frame> {
842 self.write_generic::<_>(info, frame).await 834 TxMode::write_generic::<_>(info, frame).await
843 } 835 }
844 836
845 /// Queues the message to be sent but exerts backpressure. If a lower-priority 837 /// Queues the message to be sent but exerts backpressure. If a lower-priority
846 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 838 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
847 /// can be replaced, this call asynchronously waits for a frame to be successfully 839 /// can be replaced, this call asynchronously waits for a frame to be successfully
848 /// transmitted, then tries again. 840 /// transmitted, then tries again.
849 async fn write_fd(&self, info: &'static Info, frame: &FdFrame) -> Option<FdFrame> { 841 async fn write_fd(info: &'static Info, frame: &FdFrame) -> Option<FdFrame> {
850 self.write_generic::<_>(info, frame).await 842 TxMode::write_generic::<_>(info, frame).await
851 } 843 }
852} 844}
853 845
@@ -922,6 +914,10 @@ struct State {
922 pub rx_mode: RxMode, 914 pub rx_mode: RxMode,
923 pub tx_mode: TxMode, 915 pub tx_mode: TxMode,
924 pub ns_per_timer_tick: u64, 916 pub ns_per_timer_tick: u64,
917 receiver_instance_count: usize,
918 sender_instance_count: usize,
919 tx_pin_port: Option<u8>,
920 rx_pin_port: Option<u8>,
925 921
926 pub err_waker: AtomicWaker, 922 pub err_waker: AtomicWaker,
927} 923}
@@ -933,34 +929,22 @@ impl State {
933 tx_mode: TxMode::NonBuffered(AtomicWaker::new()), 929 tx_mode: TxMode::NonBuffered(AtomicWaker::new()),
934 ns_per_timer_tick: 0, 930 ns_per_timer_tick: 0,
935 err_waker: AtomicWaker::new(), 931 err_waker: AtomicWaker::new(),
932 receiver_instance_count: 0,
933 sender_instance_count: 0,
934 tx_pin_port: None,
935 rx_pin_port: None,
936 } 936 }
937 } 937 }
938} 938}
939 939
940type SharedState = embassy_sync::blocking_mutex::Mutex<CriticalSectionRawMutex, core::cell::RefCell<State>>;
940struct Info { 941struct Info {
941 regs: Registers, 942 regs: Registers,
942 interrupt0: crate::interrupt::Interrupt, 943 interrupt0: crate::interrupt::Interrupt,
943 _interrupt1: crate::interrupt::Interrupt, 944 _interrupt1: crate::interrupt::Interrupt,
944 tx_waker: fn(), 945 tx_waker: fn(),
945} 946 internal_operation: fn(InternalOperation),
946 947 state: SharedState,
947impl Info {
948 #[cfg(feature = "time")]
949 fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
950 let now_embassy = embassy_time::Instant::now();
951 if ns_per_timer_tick == 0 {
952 return now_embassy;
953 }
954 let cantime = { self.regs.regs.tscv().read().tsc() };
955 let delta = cantime.overflowing_sub(ts_val).0 as u64;
956 let ns = ns_per_timer_tick * delta as u64;
957 now_embassy - embassy_time::Duration::from_nanos(ns)
958 }
959
960 #[cfg(not(feature = "time"))]
961 fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
962 ts_val
963 }
964} 948}
965 949
966trait SealedInstance { 950trait SealedInstance {
@@ -968,14 +952,12 @@ trait SealedInstance {
968 952
969 fn info() -> &'static Info; 953 fn info() -> &'static Info;
970 fn registers() -> crate::can::fd::peripheral::Registers; 954 fn registers() -> crate::can::fd::peripheral::Registers;
971 fn state() -> &'static State; 955 fn internal_operation(val: InternalOperation);
972 unsafe fn mut_state() -> &'static mut State;
973 fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp;
974} 956}
975 957
976/// Instance trait 958/// Instance trait
977#[allow(private_bounds)] 959#[allow(private_bounds)]
978pub trait Instance: SealedInstance + RccPeripheral + 'static { 960pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {
979 /// Interrupt 0 961 /// Interrupt 0
980 type IT0Interrupt: crate::interrupt::typelevel::Interrupt; 962 type IT0Interrupt: crate::interrupt::typelevel::Interrupt;
981 /// Interrupt 1 963 /// Interrupt 1
@@ -983,7 +965,7 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static {
983} 965}
984 966
985/// Fdcan Instance struct 967/// Fdcan Instance struct
986pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); 968pub struct FdcanInstance<'a, T: Instance>(Peri<'a, T>);
987 969
988macro_rules! impl_fdcan { 970macro_rules! impl_fdcan {
989 ($inst:ident, 971 ($inst:ident,
@@ -992,42 +974,56 @@ macro_rules! impl_fdcan {
992 impl SealedInstance for peripherals::$inst { 974 impl SealedInstance for peripherals::$inst {
993 const MSG_RAM_OFFSET: usize = $msg_ram_offset; 975 const MSG_RAM_OFFSET: usize = $msg_ram_offset;
994 976
977 fn internal_operation(val: InternalOperation) {
978 peripherals::$inst::info().state.lock(|s| {
979 let mut mut_state = s.borrow_mut();
980 match val {
981 InternalOperation::NotifySenderCreated => {
982 mut_state.sender_instance_count += 1;
983 }
984 InternalOperation::NotifySenderDestroyed => {
985 mut_state.sender_instance_count -= 1;
986 if ( 0 == mut_state.sender_instance_count) {
987 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
988 }
989 }
990 InternalOperation::NotifyReceiverCreated => {
991 mut_state.receiver_instance_count += 1;
992 }
993 InternalOperation::NotifyReceiverDestroyed => {
994 mut_state.receiver_instance_count -= 1;
995 if ( 0 == mut_state.receiver_instance_count) {
996 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
997 }
998 }
999 }
1000 if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 {
1001 unsafe {
1002 let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap());
1003 tx_pin.set_as_disconnected();
1004 let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap());
1005 rx_pin.set_as_disconnected();
1006 rcc::disable::<peripherals::$inst>();
1007 }
1008 }
1009 });
1010 }
1011
995 fn info() -> &'static Info { 1012 fn info() -> &'static Info {
1013
996 static INFO: Info = Info { 1014 static INFO: Info = Info {
997 regs: Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset}, 1015 regs: Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset},
998 interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ, 1016 interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ,
999 _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ, 1017 _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ,
1000 tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend, 1018 tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend,
1019 internal_operation: peripherals::$inst::internal_operation,
1020 state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())),
1001 }; 1021 };
1002 &INFO 1022 &INFO
1003 } 1023 }
1004 fn registers() -> Registers { 1024 fn registers() -> Registers {
1005 Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} 1025 Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
1006 } 1026 }
1007 unsafe fn mut_state() -> &'static mut State {
1008 static mut STATE: State = State::new();
1009 &mut *core::ptr::addr_of_mut!(STATE)
1010 }
1011 fn state() -> &'static State {
1012 unsafe { peripherals::$inst::mut_state() }
1013 }
1014
1015 #[cfg(feature = "time")]
1016 fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
1017 let now_embassy = embassy_time::Instant::now();
1018 if ns_per_timer_tick == 0 {
1019 return now_embassy;
1020 }
1021 let cantime = { Self::registers().regs.tscv().read().tsc() };
1022 let delta = cantime.overflowing_sub(ts_val).0 as u64;
1023 let ns = ns_per_timer_tick * delta as u64;
1024 now_embassy - embassy_time::Duration::from_nanos(ns)
1025 }
1026
1027 #[cfg(not(feature = "time"))]
1028 fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
1029 ts_val
1030 }
1031 1027
1032 } 1028 }
1033 1029
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
index d2d1f7aa6..0fbab053b 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -104,15 +104,13 @@ pub trait CanHeader: Sized {
104#[derive(Debug, Copy, Clone)] 104#[derive(Debug, Copy, Clone)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))] 105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub struct ClassicData { 106pub struct ClassicData {
107 pub(crate) bytes: [u8; Self::MAX_DATA_LEN], 107 pub(crate) bytes: [u8; 8],
108} 108}
109 109
110impl ClassicData { 110impl ClassicData {
111 pub(crate) const MAX_DATA_LEN: usize = 8;
112 /// Creates a data payload from a raw byte slice. 111 /// Creates a data payload from a raw byte slice.
113 /// 112 ///
114 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or 113 /// Returns `FrameCreateError` if `data` is more than 8 bytes (which is the maximum).
115 /// cannot be represented with an FDCAN DLC.
116 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> { 114 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
117 if data.len() > 8 { 115 if data.len() > 8 {
118 return Err(FrameCreateError::InvalidDataLength); 116 return Err(FrameCreateError::InvalidDataLength);
@@ -129,6 +127,11 @@ impl ClassicData {
129 &self.bytes 127 &self.bytes
130 } 128 }
131 129
130 /// Raw mutable read access to data.
131 pub fn raw_mut(&mut self) -> &mut [u8] {
132 &mut self.bytes
133 }
134
132 /// Checks if the length can be encoded in FDCAN DLC field. 135 /// Checks if the length can be encoded in FDCAN DLC field.
133 pub const fn is_valid_len(len: usize) -> bool { 136 pub const fn is_valid_len(len: usize) -> bool {
134 match len { 137 match len {
@@ -206,7 +209,17 @@ impl Frame {
206 209
207 /// Get reference to data 210 /// Get reference to data
208 pub fn data(&self) -> &[u8] { 211 pub fn data(&self) -> &[u8] {
209 &self.data.raw() 212 &self.data.raw()[..self.can_header.len as usize]
213 }
214
215 /// Get reference to underlying 8-byte raw data buffer, some bytes on the tail might be undefined.
216 pub fn raw_data(&self) -> &[u8] {
217 self.data.raw()
218 }
219
220 /// Get mutable reference to data
221 pub fn data_mut(&mut self) -> &mut [u8] {
222 &mut self.data.raw_mut()[..self.can_header.len as usize]
210 } 223 }
211 224
212 /// Get priority of frame 225 /// Get priority of frame
@@ -250,7 +263,7 @@ impl embedded_can::Frame for Frame {
250 self.can_header.len as usize 263 self.can_header.len as usize
251 } 264 }
252 fn data(&self) -> &[u8] { 265 fn data(&self) -> &[u8] {
253 &self.data.raw() 266 &self.data()
254 } 267 }
255} 268}
256 269
@@ -314,6 +327,11 @@ impl FdData {
314 &self.bytes 327 &self.bytes
315 } 328 }
316 329
330 /// Raw mutable read access to data.
331 pub fn raw_mut(&mut self) -> &mut [u8] {
332 &mut self.bytes
333 }
334
317 /// Checks if the length can be encoded in FDCAN DLC field. 335 /// Checks if the length can be encoded in FDCAN DLC field.
318 pub const fn is_valid_len(len: usize) -> bool { 336 pub const fn is_valid_len(len: usize) -> bool {
319 match len { 337 match len {
@@ -390,7 +408,12 @@ impl FdFrame {
390 408
391 /// Get reference to data 409 /// Get reference to data
392 pub fn data(&self) -> &[u8] { 410 pub fn data(&self) -> &[u8] {
393 &self.data.raw() 411 &self.data.raw()[..self.can_header.len as usize]
412 }
413
414 /// Get mutable reference to data
415 pub fn data_mut(&mut self) -> &mut [u8] {
416 &mut self.data.raw_mut()[..self.can_header.len as usize]
394 } 417 }
395} 418}
396 419
@@ -428,7 +451,7 @@ impl embedded_can::Frame for FdFrame {
428 self.can_header.len as usize 451 self.can_header.len as usize
429 } 452 }
430 fn data(&self) -> &[u8] { 453 fn data(&self) -> &[u8] {
431 &self.data.raw() 454 &self.data()
432 } 455 }
433} 456}
434 457
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index fb342d2e7..320774857 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -1,7 +1,7 @@
1//! coordinate rotation digital computer (CORDIC) 1//! coordinate rotation digital computer (CORDIC)
2 2
3use embassy_hal_internal::drop::OnDrop; 3use embassy_hal_internal::drop::OnDrop;
4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 4use embassy_hal_internal::{Peri, PeripheralType};
5 5
6use crate::pac::cordic::vals; 6use crate::pac::cordic::vals;
7use crate::{dma, peripherals, rcc}; 7use crate::{dma, peripherals, rcc};
@@ -16,7 +16,7 @@ pub mod utils;
16 16
17/// CORDIC driver 17/// CORDIC driver
18pub struct Cordic<'d, T: Instance> { 18pub struct Cordic<'d, T: Instance> {
19 peri: PeripheralRef<'d, T>, 19 peri: Peri<'d, T>,
20 config: Config, 20 config: Config,
21} 21}
22 22
@@ -137,7 +137,7 @@ trait SealedInstance {
137 137
138/// CORDIC instance trait 138/// CORDIC instance trait
139#[allow(private_bounds)] 139#[allow(private_bounds)]
140pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral {} 140pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral {}
141 141
142/// CORDIC configuration 142/// CORDIC configuration
143#[derive(Debug)] 143#[derive(Debug)]
@@ -198,11 +198,9 @@ impl<'d, T: Instance> Cordic<'d, T> {
198 /// Note: 198 /// Note:
199 /// If you need a peripheral -> CORDIC -> peripheral mode, 199 /// If you need a peripheral -> CORDIC -> peripheral mode,
200 /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config] 200 /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config]
201 pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self { 201 pub fn new(peri: Peri<'d, T>, config: Config) -> Self {
202 rcc::enable_and_reset::<T>(); 202 rcc::enable_and_reset::<T>();
203 203
204 into_ref!(peri);
205
206 let mut instance = Self { peri, config }; 204 let mut instance = Self { peri, config };
207 205
208 instance.reconfigure(); 206 instance.reconfigure();
@@ -378,8 +376,8 @@ impl<'d, T: Instance> Cordic<'d, T> {
378 /// If you want to make sure ARG2 is set to +1, consider run [.reconfigure()](Self::reconfigure). 376 /// If you want to make sure ARG2 is set to +1, consider run [.reconfigure()](Self::reconfigure).
379 pub async fn async_calc_32bit( 377 pub async fn async_calc_32bit(
380 &mut self, 378 &mut self,
381 write_dma: impl Peripheral<P = impl WriteDma<T>>, 379 mut write_dma: Peri<'_, impl WriteDma<T>>,
382 read_dma: impl Peripheral<P = impl ReadDma<T>>, 380 mut read_dma: Peri<'_, impl ReadDma<T>>,
383 arg: &[u32], 381 arg: &[u32],
384 res: &mut [u32], 382 res: &mut [u32],
385 arg1_only: bool, 383 arg1_only: bool,
@@ -393,8 +391,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
393 391
394 let active_res_buf = &mut res[..res_cnt]; 392 let active_res_buf = &mut res[..res_cnt];
395 393
396 into_ref!(write_dma, read_dma);
397
398 self.peri 394 self.peri
399 .set_argument_count(if arg1_only { AccessCount::One } else { AccessCount::Two }); 395 .set_argument_count(if arg1_only { AccessCount::One } else { AccessCount::Two });
400 396
@@ -416,7 +412,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
416 412
417 unsafe { 413 unsafe {
418 let write_transfer = dma::Transfer::new_write( 414 let write_transfer = dma::Transfer::new_write(
419 &mut write_dma, 415 write_dma.reborrow(),
420 write_req, 416 write_req,
421 arg, 417 arg,
422 T::regs().wdata().as_ptr() as *mut _, 418 T::regs().wdata().as_ptr() as *mut _,
@@ -424,7 +420,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
424 ); 420 );
425 421
426 let read_transfer = dma::Transfer::new_read( 422 let read_transfer = dma::Transfer::new_read(
427 &mut read_dma, 423 read_dma.reborrow(),
428 read_req, 424 read_req,
429 T::regs().rdata().as_ptr() as *mut _, 425 T::regs().rdata().as_ptr() as *mut _,
430 active_res_buf, 426 active_res_buf,
@@ -519,8 +515,8 @@ impl<'d, T: Instance> Cordic<'d, T> {
519 /// User will take respond to merge two u16 arguments into one u32 data, and/or split one u32 data into two u16 results. 515 /// User will take respond to merge two u16 arguments into one u32 data, and/or split one u32 data into two u16 results.
520 pub async fn async_calc_16bit( 516 pub async fn async_calc_16bit(
521 &mut self, 517 &mut self,
522 write_dma: impl Peripheral<P = impl WriteDma<T>>, 518 mut write_dma: Peri<'_, impl WriteDma<T>>,
523 read_dma: impl Peripheral<P = impl ReadDma<T>>, 519 mut read_dma: Peri<'_, impl ReadDma<T>>,
524 arg: &[u32], 520 arg: &[u32],
525 res: &mut [u32], 521 res: &mut [u32],
526 ) -> Result<usize, CordicError> { 522 ) -> Result<usize, CordicError> {
@@ -536,8 +532,6 @@ impl<'d, T: Instance> Cordic<'d, T> {
536 532
537 let active_res_buf = &mut res[..res_cnt]; 533 let active_res_buf = &mut res[..res_cnt];
538 534
539 into_ref!(write_dma, read_dma);
540
541 // In q1.15 mode, 1 write/read to access 2 arguments/results 535 // In q1.15 mode, 1 write/read to access 2 arguments/results
542 self.peri.set_argument_count(AccessCount::One); 536 self.peri.set_argument_count(AccessCount::One);
543 self.peri.set_result_count(AccessCount::One); 537 self.peri.set_result_count(AccessCount::One);
@@ -557,7 +551,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
557 551
558 unsafe { 552 unsafe {
559 let write_transfer = dma::Transfer::new_write( 553 let write_transfer = dma::Transfer::new_write(
560 &mut write_dma, 554 write_dma.reborrow(),
561 write_req, 555 write_req,
562 arg, 556 arg,
563 T::regs().wdata().as_ptr() as *mut _, 557 T::regs().wdata().as_ptr() as *mut _,
@@ -565,7 +559,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
565 ); 559 );
566 560
567 let read_transfer = dma::Transfer::new_read( 561 let read_transfer = dma::Transfer::new_read(
568 &mut read_dma, 562 read_dma.reborrow(),
569 read_req, 563 read_req,
570 T::regs().rdata().as_ptr() as *mut _, 564 T::regs().rdata().as_ptr() as *mut _,
571 active_res_buf, 565 active_res_buf,
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index f3d13de7c..13e5263de 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -1,23 +1,18 @@
1use embassy_hal_internal::{into_ref, PeripheralRef};
2
3use crate::pac::CRC as PAC_CRC; 1use crate::pac::CRC as PAC_CRC;
4use crate::peripherals::CRC; 2use crate::peripherals::CRC;
5use crate::{rcc, Peripheral}; 3use crate::{rcc, Peri};
6 4
7/// CRC driver. 5/// CRC driver.
8pub struct Crc<'d> { 6pub struct Crc<'d> {
9 _peri: PeripheralRef<'d, CRC>, 7 _peri: Peri<'d, CRC>,
10} 8}
11 9
12impl<'d> Crc<'d> { 10impl<'d> Crc<'d> {
13 /// Instantiates the CRC32 peripheral and initializes it to default values. 11 /// Instantiates the CRC32 peripheral and initializes it to default values.
14 pub fn new(peripheral: impl Peripheral<P = CRC> + 'd) -> Self { 12 pub fn new(peripheral: Peri<'d, CRC>) -> Self {
15 into_ref!(peripheral);
16
17 // Note: enable and reset come from RccPeripheral. 13 // Note: enable and reset come from RccPeripheral.
18 // enable CRC clock in RCC. 14 // enable CRC clock in RCC.
19 rcc::enable_and_reset::<CRC>(); 15 rcc::enable_and_reset::<CRC>();
20 // Peripheral the peripheral
21 let mut instance = Self { _peri: peripheral }; 16 let mut instance = Self { _peri: peripheral };
22 instance.reset(); 17 instance.reset();
23 instance 18 instance
@@ -28,22 +23,16 @@ impl<'d> Crc<'d> {
28 PAC_CRC.cr().write(|w| w.set_reset(true)); 23 PAC_CRC.cr().write(|w| w.set_reset(true));
29 } 24 }
30 25
31 /// Feeds a word to the peripheral and returns the current CRC value 26 /// Feeds a word into the CRC peripheral. Returns the computed CRC.
32 pub fn feed_word(&mut self, word: u32) -> u32 { 27 pub fn feed_word(&mut self, word: u32) -> u32 {
33 // write a single byte to the device, and return the result 28 // write a single byte to the device, and return the result
34 #[cfg(not(crc_v1))]
35 PAC_CRC.dr32().write_value(word);
36 #[cfg(crc_v1)]
37 PAC_CRC.dr().write_value(word); 29 PAC_CRC.dr().write_value(word);
38 self.read() 30 self.read()
39 } 31 }
40 32
41 /// Feed a slice of words to the peripheral and return the result. 33 /// Feeds a slice of words into the CRC peripheral. Returns the computed CRC.
42 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 34 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
43 for word in words { 35 for word in words {
44 #[cfg(not(crc_v1))]
45 PAC_CRC.dr32().write_value(*word);
46 #[cfg(crc_v1)]
47 PAC_CRC.dr().write_value(*word); 36 PAC_CRC.dr().write_value(*word);
48 } 37 }
49 38
@@ -51,12 +40,6 @@ impl<'d> Crc<'d> {
51 } 40 }
52 41
53 /// Read the CRC result value. 42 /// Read the CRC result value.
54 #[cfg(not(crc_v1))]
55 pub fn read(&self) -> u32 {
56 PAC_CRC.dr32().read()
57 }
58 /// Read the CRC result value.
59 #[cfg(crc_v1)]
60 pub fn read(&self) -> u32 { 43 pub fn read(&self) -> u32 {
61 PAC_CRC.dr().read() 44 PAC_CRC.dr().read()
62 } 45 }
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index 09d956d7c..d834d0971 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -1,17 +1,15 @@
1use embassy_hal_internal::{into_ref, PeripheralRef};
2
3use crate::pac::crc::vals; 1use crate::pac::crc::vals;
4use crate::pac::CRC as PAC_CRC; 2use crate::pac::CRC as PAC_CRC;
5use crate::peripherals::CRC; 3use crate::peripherals::CRC;
6use crate::{rcc, Peripheral}; 4use crate::{rcc, Peri};
7 5
8/// CRC driver. 6/// CRC driver.
9pub struct Crc<'d> { 7pub struct Crc<'d> {
10 _peripheral: PeripheralRef<'d, CRC>, 8 _peripheral: Peri<'d, CRC>,
11 _config: Config, 9 _config: Config,
12} 10}
13 11
14/// CRC configuration errlr 12/// CRC configuration error
15#[derive(Debug)] 13#[derive(Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))] 14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum ConfigError { 15pub enum ConfigError {
@@ -36,9 +34,9 @@ pub enum InputReverseConfig {
36 None, 34 None,
37 /// Reverse bytes 35 /// Reverse bytes
38 Byte, 36 Byte,
39 /// Reverse 16-bit halfwords. 37 /// Reverse 16-bit halfwords
40 Halfword, 38 Halfword,
41 /// Reverse 32-bit words. 39 /// Reverse 32-bit words
42 Word, 40 Word,
43} 41}
44 42
@@ -80,11 +78,10 @@ pub enum PolySize {
80 78
81impl<'d> Crc<'d> { 79impl<'d> Crc<'d> {
82 /// Instantiates the CRC32 peripheral and initializes it to default values. 80 /// Instantiates the CRC32 peripheral and initializes it to default values.
83 pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self { 81 pub fn new(peripheral: Peri<'d, CRC>, config: Config) -> Self {
84 // Note: enable and reset come from RccPeripheral. 82 // Note: enable and reset come from RccPeripheral.
85 // reset to default values and enable CRC clock in RCC. 83 // reset to default values and enable CRC clock in RCC.
86 rcc::enable_and_reset::<CRC>(); 84 rcc::enable_and_reset::<CRC>();
87 into_ref!(peripheral);
88 let mut instance = Self { 85 let mut instance = Self {
89 _peripheral: peripheral, 86 _peripheral: peripheral,
90 _config: config, 87 _config: config,
@@ -118,7 +115,7 @@ impl<'d> Crc<'d> {
118 w.set_rev_in(match self._config.reverse_in { 115 w.set_rev_in(match self._config.reverse_in {
119 InputReverseConfig::None => vals::RevIn::NORMAL, 116 InputReverseConfig::None => vals::RevIn::NORMAL,
120 InputReverseConfig::Byte => vals::RevIn::BYTE, 117 InputReverseConfig::Byte => vals::RevIn::BYTE,
121 InputReverseConfig::Halfword => vals::RevIn::HALFWORD, 118 InputReverseConfig::Halfword => vals::RevIn::HALF_WORD,
122 InputReverseConfig::Word => vals::RevIn::WORD, 119 InputReverseConfig::Word => vals::RevIn::WORD,
123 }); 120 });
124 // configure the polynomial. 121 // configure the polynomial.
@@ -130,45 +127,52 @@ impl<'d> Crc<'d> {
130 PolySize::Width32 => vals::Polysize::POLYSIZE32, 127 PolySize::Width32 => vals::Polysize::POLYSIZE32,
131 }); 128 });
132 }); 129 });
130 }
133 131
134 self.reset(); 132 /// Read the CRC result value.
133 pub fn read(&self) -> u32 {
134 PAC_CRC.dr32().read()
135 } 135 }
136 136
137 /// Feeds a byte into the CRC peripheral. Returns the computed checksum. 137 /// Feeds a byte into the CRC peripheral. Returns the computed CRC.
138 pub fn feed_byte(&mut self, byte: u8) -> u32 { 138 pub fn feed_byte(&mut self, byte: u8) -> u32 {
139 PAC_CRC.dr8().write_value(byte); 139 PAC_CRC.dr8().write_value(byte);
140 PAC_CRC.dr32().read() 140 self.read()
141 } 141 }
142 142
143 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. 143 /// Feeds a slice of bytes into the CRC peripheral. Returns the computed CRC.
144 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { 144 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
145 for byte in bytes { 145 for byte in bytes {
146 PAC_CRC.dr8().write_value(*byte); 146 PAC_CRC.dr8().write_value(*byte);
147 } 147 }
148 PAC_CRC.dr32().read() 148 self.read()
149 } 149 }
150 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. 150
151 /// Feeds a halfword into the CRC peripheral. Returns the computed CRC.
151 pub fn feed_halfword(&mut self, halfword: u16) -> u32 { 152 pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
152 PAC_CRC.dr16().write_value(halfword); 153 PAC_CRC.dr16().write_value(halfword);
153 PAC_CRC.dr32().read() 154 self.read()
154 } 155 }
155 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. 156
157 /// Feeds a slice of halfwords into the CRC peripheral. Returns the computed CRC.
156 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { 158 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
157 for halfword in halfwords { 159 for halfword in halfwords {
158 PAC_CRC.dr16().write_value(*halfword); 160 PAC_CRC.dr16().write_value(*halfword);
159 } 161 }
160 PAC_CRC.dr32().read() 162 self.read()
161 } 163 }
162 /// Feeds a words into the CRC peripheral. Returns the computed checksum. 164
165 /// Feeds a word into the CRC peripheral. Returns the computed CRC.
163 pub fn feed_word(&mut self, word: u32) -> u32 { 166 pub fn feed_word(&mut self, word: u32) -> u32 {
164 PAC_CRC.dr32().write_value(word as u32); 167 PAC_CRC.dr32().write_value(word as u32);
165 PAC_CRC.dr32().read() 168 self.read()
166 } 169 }
167 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. 170
171 /// Feeds a slice of words into the CRC peripheral. Returns the computed CRC.
168 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 172 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
169 for word in words { 173 for word in words {
170 PAC_CRC.dr32().write_value(*word as u32); 174 PAC_CRC.dr32().write_value(*word as u32);
171 } 175 }
172 PAC_CRC.dr32().read() 176 self.read()
173 } 177 }
174} 178}
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 8d600c73c..fba3c0fd7 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -4,12 +4,13 @@ use core::cmp::min;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::ptr; 5use core::ptr;
6 6
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{Peri, PeripheralType};
8use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
9 9
10use crate::dma::{NoDma, Transfer, TransferOptions}; 10use crate::dma::{ChannelAndRequest, TransferOptions};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, pac, peripherals, rcc, Peripheral}; 12use crate::mode::{Async, Blocking, Mode};
13use crate::{interrupt, pac, peripherals, rcc};
13 14
14const DES_BLOCK_SIZE: usize = 8; // 64 bits 15const DES_BLOCK_SIZE: usize = 8; // 64 bits
15const AES_BLOCK_SIZE: usize = 16; // 128 bits 16const AES_BLOCK_SIZE: usize = 16; // 128 bits
@@ -57,15 +58,10 @@ pub trait Cipher<'c> {
57 fn prepare_key(&self, _p: pac::cryp::Cryp) {} 58 fn prepare_key(&self, _p: pac::cryp::Cryp) {}
58 59
59 /// Performs any cipher-specific initialization. 60 /// Performs any cipher-specific initialization.
60 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, _p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {} 61 fn init_phase_blocking<T: Instance, M: Mode>(&self, _p: pac::cryp::Cryp, _cryp: &Cryp<T, M>) {}
61 62
62 /// Performs any cipher-specific initialization. 63 /// Performs any cipher-specific initialization.
63 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) 64 async fn init_phase<T: Instance>(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) {}
64 where
65 DmaIn: crate::cryp::DmaIn<T>,
66 DmaOut: crate::cryp::DmaOut<T>,
67 {
68 }
69 65
70 /// Called prior to processing the last data block for cipher-specific operations. 66 /// Called prior to processing the last data block for cipher-specific operations.
71 fn pre_final(&self, _p: pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { 67 fn pre_final(&self, _p: pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
@@ -73,10 +69,10 @@ pub trait Cipher<'c> {
73 } 69 }
74 70
75 /// Called after processing the last data block for cipher-specific operations. 71 /// Called after processing the last data block for cipher-specific operations.
76 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 72 fn post_final_blocking<T: Instance, M: Mode>(
77 &self, 73 &self,
78 _p: pac::cryp::Cryp, 74 _p: pac::cryp::Cryp,
79 _cryp: &Cryp<T, DmaIn, DmaOut>, 75 _cryp: &Cryp<T, M>,
80 _dir: Direction, 76 _dir: Direction,
81 _int_data: &mut [u8; AES_BLOCK_SIZE], 77 _int_data: &mut [u8; AES_BLOCK_SIZE],
82 _temp1: [u32; 4], 78 _temp1: [u32; 4],
@@ -85,18 +81,15 @@ pub trait Cipher<'c> {
85 } 81 }
86 82
87 /// Called after processing the last data block for cipher-specific operations. 83 /// Called after processing the last data block for cipher-specific operations.
88 async fn post_final<T: Instance, DmaIn, DmaOut>( 84 async fn post_final<T: Instance>(
89 &self, 85 &self,
90 _p: pac::cryp::Cryp, 86 _p: pac::cryp::Cryp,
91 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 87 _cryp: &mut Cryp<'_, T, Async>,
92 _dir: Direction, 88 _dir: Direction,
93 _int_data: &mut [u8; AES_BLOCK_SIZE], 89 _int_data: &mut [u8; AES_BLOCK_SIZE],
94 _temp1: [u32; 4], 90 _temp1: [u32; 4],
95 _padding_mask: [u8; 16], 91 _padding_mask: [u8; 16],
96 ) where 92 ) {
97 DmaIn: crate::cryp::DmaIn<T>,
98 DmaOut: crate::cryp::DmaOut<T>,
99 {
100 } 93 }
101 94
102 /// Returns the AAD header block as required by the cipher. 95 /// Returns the AAD header block as required by the cipher.
@@ -474,13 +467,13 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
474 p.cr().modify(|w| w.set_algomode3(true)); 467 p.cr().modify(|w| w.set_algomode3(true));
475 } 468 }
476 469
477 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) { 470 fn init_phase_blocking<T: Instance, M: Mode>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, M>) {
478 p.cr().modify(|w| w.set_gcm_ccmph(0)); 471 p.cr().modify(|w| w.set_gcm_ccmph(0));
479 p.cr().modify(|w| w.set_crypen(true)); 472 p.cr().modify(|w| w.set_crypen(true));
480 while p.cr().read().crypen() {} 473 while p.cr().read().crypen() {}
481 } 474 }
482 475
483 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { 476 async fn init_phase<T: Instance>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) {
484 p.cr().modify(|w| w.set_gcm_ccmph(0)); 477 p.cr().modify(|w| w.set_gcm_ccmph(0));
485 p.cr().modify(|w| w.set_crypen(true)); 478 p.cr().modify(|w| w.set_crypen(true));
486 while p.cr().read().crypen() {} 479 while p.cr().read().crypen() {}
@@ -508,10 +501,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
508 } 501 }
509 502
510 #[cfg(cryp_v2)] 503 #[cfg(cryp_v2)]
511 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 504 fn post_final_blocking<T: Instance, M: Mode>(
512 &self, 505 &self,
513 p: pac::cryp::Cryp, 506 p: pac::cryp::Cryp,
514 cryp: &Cryp<T, DmaIn, DmaOut>, 507 cryp: &Cryp<T, M>,
515 dir: Direction, 508 dir: Direction,
516 int_data: &mut [u8; AES_BLOCK_SIZE], 509 int_data: &mut [u8; AES_BLOCK_SIZE],
517 _temp1: [u32; 4], 510 _temp1: [u32; 4],
@@ -534,18 +527,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
534 } 527 }
535 528
536 #[cfg(cryp_v2)] 529 #[cfg(cryp_v2)]
537 async fn post_final<T: Instance, DmaIn, DmaOut>( 530 async fn post_final<T: Instance>(
538 &self, 531 &self,
539 p: pac::cryp::Cryp, 532 p: pac::cryp::Cryp,
540 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 533 cryp: &mut Cryp<'_, T, Async>,
541 dir: Direction, 534 dir: Direction,
542 int_data: &mut [u8; AES_BLOCK_SIZE], 535 int_data: &mut [u8; AES_BLOCK_SIZE],
543 _temp1: [u32; 4], 536 _temp1: [u32; 4],
544 padding_mask: [u8; AES_BLOCK_SIZE], 537 padding_mask: [u8; AES_BLOCK_SIZE],
545 ) where 538 ) {
546 DmaIn: crate::cryp::DmaIn<T>,
547 DmaOut: crate::cryp::DmaOut<T>,
548 {
549 if dir == Direction::Encrypt { 539 if dir == Direction::Encrypt {
550 // Handle special GCM partial block process. 540 // Handle special GCM partial block process.
551 p.cr().modify(|w| w.set_crypen(false)); 541 p.cr().modify(|w| w.set_crypen(false));
@@ -559,8 +549,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
559 549
560 let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 550 let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
561 551
562 let read = Cryp::<T, DmaIn, DmaOut>::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); 552 let read = Cryp::<T, Async>::read_bytes(cryp.outdma.as_mut().unwrap(), Self::BLOCK_SIZE, &mut out_data);
563 let write = Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); 553 let write = Cryp::<T, Async>::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, int_data);
564 554
565 embassy_futures::join::join(read, write).await; 555 embassy_futures::join::join(read, write).await;
566 556
@@ -615,13 +605,13 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
615 p.cr().modify(|w| w.set_algomode3(true)); 605 p.cr().modify(|w| w.set_algomode3(true));
616 } 606 }
617 607
618 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) { 608 fn init_phase_blocking<T: Instance, M: Mode>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, M>) {
619 p.cr().modify(|w| w.set_gcm_ccmph(0)); 609 p.cr().modify(|w| w.set_gcm_ccmph(0));
620 p.cr().modify(|w| w.set_crypen(true)); 610 p.cr().modify(|w| w.set_crypen(true));
621 while p.cr().read().crypen() {} 611 while p.cr().read().crypen() {}
622 } 612 }
623 613
624 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { 614 async fn init_phase<T: Instance>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) {
625 p.cr().modify(|w| w.set_gcm_ccmph(0)); 615 p.cr().modify(|w| w.set_gcm_ccmph(0));
626 p.cr().modify(|w| w.set_crypen(true)); 616 p.cr().modify(|w| w.set_crypen(true));
627 while p.cr().read().crypen() {} 617 while p.cr().read().crypen() {}
@@ -649,10 +639,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
649 } 639 }
650 640
651 #[cfg(cryp_v2)] 641 #[cfg(cryp_v2)]
652 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 642 fn post_final_blocking<T: Instance, M: Mode>(
653 &self, 643 &self,
654 p: pac::cryp::Cryp, 644 p: pac::cryp::Cryp,
655 cryp: &Cryp<T, DmaIn, DmaOut>, 645 cryp: &Cryp<T, M>,
656 dir: Direction, 646 dir: Direction,
657 int_data: &mut [u8; AES_BLOCK_SIZE], 647 int_data: &mut [u8; AES_BLOCK_SIZE],
658 _temp1: [u32; 4], 648 _temp1: [u32; 4],
@@ -675,18 +665,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
675 } 665 }
676 666
677 #[cfg(cryp_v2)] 667 #[cfg(cryp_v2)]
678 async fn post_final<T: Instance, DmaIn, DmaOut>( 668 async fn post_final<T: Instance>(
679 &self, 669 &self,
680 p: pac::cryp::Cryp, 670 p: pac::cryp::Cryp,
681 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 671 cryp: &mut Cryp<'_, T, Async>,
682 dir: Direction, 672 dir: Direction,
683 int_data: &mut [u8; AES_BLOCK_SIZE], 673 int_data: &mut [u8; AES_BLOCK_SIZE],
684 _temp1: [u32; 4], 674 _temp1: [u32; 4],
685 padding_mask: [u8; AES_BLOCK_SIZE], 675 padding_mask: [u8; AES_BLOCK_SIZE],
686 ) where 676 ) {
687 DmaIn: crate::cryp::DmaIn<T>,
688 DmaOut: crate::cryp::DmaOut<T>,
689 {
690 if dir == Direction::Encrypt { 677 if dir == Direction::Encrypt {
691 // Handle special GCM partial block process. 678 // Handle special GCM partial block process.
692 p.cr().modify(|w| w.set_crypen(false)); 679 p.cr().modify(|w| w.set_crypen(false));
@@ -700,8 +687,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
700 687
701 let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 688 let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
702 689
703 let read = Cryp::<T, DmaIn, DmaOut>::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); 690 let read = Cryp::<T, Async>::read_bytes(cryp.outdma.as_mut().unwrap(), Self::BLOCK_SIZE, &mut out_data);
704 let write = Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); 691 let write = Cryp::<T, Async>::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, int_data);
705 692
706 embassy_futures::join::join(read, write).await; 693 embassy_futures::join::join(read, write).await;
707 } 694 }
@@ -812,7 +799,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
812 p.cr().modify(|w| w.set_algomode3(true)); 799 p.cr().modify(|w| w.set_algomode3(true));
813 } 800 }
814 801
815 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, cryp: &Cryp<T, DmaIn, DmaOut>) { 802 fn init_phase_blocking<T: Instance, M: Mode>(&self, p: pac::cryp::Cryp, cryp: &Cryp<T, M>) {
816 p.cr().modify(|w| w.set_gcm_ccmph(0)); 803 p.cr().modify(|w| w.set_gcm_ccmph(0));
817 804
818 cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0); 805 cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0);
@@ -821,14 +808,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
821 while p.cr().read().crypen() {} 808 while p.cr().read().crypen() {}
822 } 809 }
823 810
824 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) 811 async fn init_phase<T: Instance>(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, Async>) {
825 where
826 DmaIn: crate::cryp::DmaIn<T>,
827 DmaOut: crate::cryp::DmaOut<T>,
828 {
829 p.cr().modify(|w| w.set_gcm_ccmph(0)); 812 p.cr().modify(|w| w.set_gcm_ccmph(0));
830 813
831 Cryp::<T, DmaIn, DmaOut>::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, &self.block0).await; 814 Cryp::<T, Async>::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, &self.block0).await;
832 815
833 p.cr().modify(|w| w.set_crypen(true)); 816 p.cr().modify(|w| w.set_crypen(true));
834 while p.cr().read().crypen() {} 817 while p.cr().read().crypen() {}
@@ -865,10 +848,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
865 } 848 }
866 849
867 #[cfg(cryp_v2)] 850 #[cfg(cryp_v2)]
868 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 851 fn post_final_blocking<T: Instance, M: Mode>(
869 &self, 852 &self,
870 p: pac::cryp::Cryp, 853 p: pac::cryp::Cryp,
871 cryp: &Cryp<T, DmaIn, DmaOut>, 854 cryp: &Cryp<T, M>,
872 dir: Direction, 855 dir: Direction,
873 int_data: &mut [u8; AES_BLOCK_SIZE], 856 int_data: &mut [u8; AES_BLOCK_SIZE],
874 temp1: [u32; 4], 857 temp1: [u32; 4],
@@ -902,18 +885,15 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
902 } 885 }
903 886
904 #[cfg(cryp_v2)] 887 #[cfg(cryp_v2)]
905 async fn post_final<T: Instance, DmaIn, DmaOut>( 888 async fn post_final<T: Instance>(
906 &self, 889 &self,
907 p: pac::cryp::Cryp, 890 p: pac::cryp::Cryp,
908 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 891 cryp: &mut Cryp<'_, T, Async>,
909 dir: Direction, 892 dir: Direction,
910 int_data: &mut [u8; AES_BLOCK_SIZE], 893 int_data: &mut [u8; AES_BLOCK_SIZE],
911 temp1: [u32; 4], 894 temp1: [u32; 4],
912 padding_mask: [u8; 16], 895 padding_mask: [u8; 16],
913 ) where 896 ) {
914 DmaIn: crate::cryp::DmaIn<T>,
915 DmaOut: crate::cryp::DmaOut<T>,
916 {
917 if dir == Direction::Decrypt { 897 if dir == Direction::Decrypt {
918 //Handle special CCM partial block process. 898 //Handle special CCM partial block process.
919 let mut temp2 = [0; 4]; 899 let mut temp2 = [0; 4];
@@ -937,7 +917,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
937 in_data[i] = int_word; 917 in_data[i] = int_word;
938 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; 918 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
939 } 919 }
940 Cryp::<T, DmaIn, DmaOut>::write_words(&mut cryp.indma, Self::BLOCK_SIZE, &in_data).await; 920 Cryp::<T, Async>::write_words(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, &in_data).await;
941 } 921 }
942 } 922 }
943} 923}
@@ -1007,26 +987,25 @@ pub enum Direction {
1007} 987}
1008 988
1009/// Crypto Accelerator Driver 989/// Crypto Accelerator Driver
1010pub struct Cryp<'d, T: Instance, DmaIn = NoDma, DmaOut = NoDma> { 990pub struct Cryp<'d, T: Instance, M: Mode> {
1011 _peripheral: PeripheralRef<'d, T>, 991 _peripheral: Peri<'d, T>,
1012 indma: PeripheralRef<'d, DmaIn>, 992 _phantom: PhantomData<M>,
1013 outdma: PeripheralRef<'d, DmaOut>, 993 indma: Option<ChannelAndRequest<'d>>,
994 outdma: Option<ChannelAndRequest<'d>>,
1014} 995}
1015 996
1016impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { 997impl<'d, T: Instance> Cryp<'d, T, Blocking> {
1017 /// Create a new CRYP driver. 998 /// Create a new CRYP driver in blocking mode.
1018 pub fn new( 999 pub fn new_blocking(
1019 peri: impl Peripheral<P = T> + 'd, 1000 peri: Peri<'d, T>,
1020 indma: impl Peripheral<P = DmaIn> + 'd,
1021 outdma: impl Peripheral<P = DmaOut> + 'd,
1022 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1001 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1023 ) -> Self { 1002 ) -> Self {
1024 rcc::enable_and_reset::<T>(); 1003 rcc::enable_and_reset::<T>();
1025 into_ref!(peri, indma, outdma);
1026 let instance = Self { 1004 let instance = Self {
1027 _peripheral: peri, 1005 _peripheral: peri,
1028 indma: indma, 1006 _phantom: PhantomData,
1029 outdma: outdma, 1007 indma: None,
1008 outdma: None,
1030 }; 1009 };
1031 1010
1032 T::Interrupt::unpend(); 1011 T::Interrupt::unpend();
@@ -1034,7 +1013,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1034 1013
1035 instance 1014 instance
1036 } 1015 }
1016}
1037 1017
1018impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> {
1038 /// Start a new encrypt or decrypt operation for the given cipher. 1019 /// Start a new encrypt or decrypt operation for the given cipher.
1039 pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>( 1020 pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(
1040 &self, 1021 &self,
@@ -1114,89 +1095,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1114 ctx 1095 ctx
1115 } 1096 }
1116 1097
1117 /// Start a new encrypt or decrypt operation for the given cipher.
1118 pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(
1119 &mut self,
1120 cipher: &'c C,
1121 dir: Direction,
1122 ) -> Context<'c, C>
1123 where
1124 DmaIn: crate::cryp::DmaIn<T>,
1125 DmaOut: crate::cryp::DmaOut<T>,
1126 {
1127 let mut ctx: Context<'c, C> = Context {
1128 dir,
1129 last_block_processed: false,
1130 cr: 0,
1131 iv: [0; 4],
1132 csgcmccm: [0; 8],
1133 csgcm: [0; 8],
1134 aad_complete: false,
1135 header_len: 0,
1136 payload_len: 0,
1137 cipher: cipher,
1138 phantom_data: PhantomData,
1139 header_processed: false,
1140 aad_buffer: [0; 16],
1141 aad_buffer_len: 0,
1142 };
1143
1144 T::regs().cr().modify(|w| w.set_crypen(false));
1145
1146 let key = ctx.cipher.key();
1147
1148 if key.len() == (128 / 8) {
1149 T::regs().cr().modify(|w| w.set_keysize(0));
1150 } else if key.len() == (192 / 8) {
1151 T::regs().cr().modify(|w| w.set_keysize(1));
1152 } else if key.len() == (256 / 8) {
1153 T::regs().cr().modify(|w| w.set_keysize(2));
1154 }
1155
1156 self.load_key(key);
1157
1158 // Set data type to 8-bit. This will match software implementations.
1159 T::regs().cr().modify(|w| w.set_datatype(2));
1160
1161 ctx.cipher.prepare_key(T::regs());
1162
1163 ctx.cipher.set_algomode(T::regs());
1164
1165 // Set encrypt/decrypt
1166 if dir == Direction::Encrypt {
1167 T::regs().cr().modify(|w| w.set_algodir(false));
1168 } else {
1169 T::regs().cr().modify(|w| w.set_algodir(true));
1170 }
1171
1172 // Load the IV into the registers.
1173 let iv = ctx.cipher.iv();
1174 let mut full_iv: [u8; 16] = [0; 16];
1175 full_iv[0..iv.len()].copy_from_slice(iv);
1176 let mut iv_idx = 0;
1177 let mut iv_word: [u8; 4] = [0; 4];
1178 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1179 iv_idx += 4;
1180 T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word));
1181 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1182 iv_idx += 4;
1183 T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
1184 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1185 iv_idx += 4;
1186 T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
1187 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1188 T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
1189
1190 // Flush in/out FIFOs
1191 T::regs().cr().modify(|w| w.fflush());
1192
1193 ctx.cipher.init_phase(T::regs(), self).await;
1194
1195 self.store_context(&mut ctx);
1196
1197 ctx
1198 }
1199
1200 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] 1098 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1201 /// Controls the header phase of cipher processing. 1099 /// Controls the header phase of cipher processing.
1202 /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. 1100 /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC.
@@ -1294,101 +1192,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1294 self.store_context(ctx); 1192 self.store_context(ctx);
1295 } 1193 }
1296 1194
1297 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1298 /// Controls the header phase of cipher processing.
1299 /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC.
1300 /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`.
1301 /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block.
1302 /// When supplying the last block of AAD, `last_aad_block` must be `true`.
1303 pub async fn aad<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>>(
1304 &mut self,
1305 ctx: &mut Context<'c, C>,
1306 aad: &[u8],
1307 last_aad_block: bool,
1308 ) where
1309 DmaIn: crate::cryp::DmaIn<T>,
1310 DmaOut: crate::cryp::DmaOut<T>,
1311 {
1312 self.load_context(ctx);
1313
1314 // Perform checks for correctness.
1315 if ctx.aad_complete {
1316 panic!("Cannot update AAD after starting payload!")
1317 }
1318
1319 ctx.header_len += aad.len() as u64;
1320
1321 // Header phase
1322 T::regs().cr().modify(|w| w.set_crypen(false));
1323 T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
1324 T::regs().cr().modify(|w| w.set_crypen(true));
1325
1326 // First write the header B1 block if not yet written.
1327 if !ctx.header_processed {
1328 ctx.header_processed = true;
1329 let header = ctx.cipher.get_header_block();
1330 ctx.aad_buffer[0..header.len()].copy_from_slice(header);
1331 ctx.aad_buffer_len += header.len();
1332 }
1333
1334 // Fill the header block to make a full block.
1335 let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len);
1336 ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]);
1337 ctx.aad_buffer_len += len_to_copy;
1338 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1339 let mut aad_len_remaining = aad.len() - len_to_copy;
1340
1341 if ctx.aad_buffer_len < C::BLOCK_SIZE {
1342 // The buffer isn't full and this is the last buffer, so process it as is (already padded).
1343 if last_aad_block {
1344 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await;
1345 assert_eq!(T::regs().sr().read().ifem(), true);
1346
1347 // Switch to payload phase.
1348 ctx.aad_complete = true;
1349 T::regs().cr().modify(|w| w.set_crypen(false));
1350 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1351 T::regs().cr().modify(|w| w.fflush());
1352 } else {
1353 // Just return because we don't yet have a full block to process.
1354 return;
1355 }
1356 } else {
1357 // Load the full block from the buffer.
1358 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await;
1359 assert_eq!(T::regs().sr().read().ifem(), true);
1360 }
1361
1362 // Handle a partial block that is passed in.
1363 ctx.aad_buffer_len = 0;
1364 let leftovers = aad_len_remaining % C::BLOCK_SIZE;
1365 ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]);
1366 ctx.aad_buffer_len += leftovers;
1367 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1368 aad_len_remaining -= leftovers;
1369 assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0);
1370
1371 // Load full data blocks into core.
1372 let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
1373 let start_index = len_to_copy;
1374 let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks);
1375 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &aad[start_index..end_index]).await;
1376
1377 if last_aad_block {
1378 if leftovers > 0 {
1379 Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await;
1380 assert_eq!(T::regs().sr().read().ifem(), true);
1381 }
1382 // Switch to payload phase.
1383 ctx.aad_complete = true;
1384 T::regs().cr().modify(|w| w.set_crypen(false));
1385 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1386 T::regs().cr().modify(|w| w.fflush());
1387 }
1388
1389 self.store_context(ctx);
1390 }
1391
1392 /// Performs encryption/decryption on the provided context. 1195 /// Performs encryption/decryption on the provided context.
1393 /// The context determines algorithm, mode, and state of the crypto accelerator. 1196 /// The context determines algorithm, mode, and state of the crypto accelerator.
1394 /// When the last piece of data is supplied, `last_block` should be `true`. 1197 /// When the last piece of data is supplied, `last_block` should be `true`.
@@ -1478,105 +1281,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1478 self.store_context(ctx); 1281 self.store_context(ctx);
1479 } 1282 }
1480 1283
1481 /// Performs encryption/decryption on the provided context.
1482 /// The context determines algorithm, mode, and state of the crypto accelerator.
1483 /// When the last piece of data is supplied, `last_block` should be `true`.
1484 /// This function panics under various mismatches of parameters.
1485 /// Output buffer must be at least as long as the input buffer.
1486 /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
1487 /// Padding or ciphertext stealing must be managed by the application for these modes.
1488 /// Data must also be a multiple of block size unless `last_block` is `true`.
1489 pub async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>(
1490 &mut self,
1491 ctx: &mut Context<'c, C>,
1492 input: &[u8],
1493 output: &mut [u8],
1494 last_block: bool,
1495 ) where
1496 DmaIn: crate::cryp::DmaIn<T>,
1497 DmaOut: crate::cryp::DmaOut<T>,
1498 {
1499 self.load_context(ctx);
1500
1501 let last_block_remainder = input.len() % C::BLOCK_SIZE;
1502
1503 // Perform checks for correctness.
1504 if !ctx.aad_complete && ctx.header_len > 0 {
1505 panic!("Additional associated data must be processed first!");
1506 } else if !ctx.aad_complete {
1507 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1508 {
1509 ctx.aad_complete = true;
1510 T::regs().cr().modify(|w| w.set_crypen(false));
1511 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1512 T::regs().cr().modify(|w| w.fflush());
1513 T::regs().cr().modify(|w| w.set_crypen(true));
1514 }
1515 }
1516 if ctx.last_block_processed {
1517 panic!("The last block has already been processed!");
1518 }
1519 if input.len() > output.len() {
1520 panic!("Output buffer length must match input length.");
1521 }
1522 if !last_block {
1523 if last_block_remainder != 0 {
1524 panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
1525 }
1526 }
1527 if C::REQUIRES_PADDING {
1528 if last_block_remainder != 0 {
1529 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE);
1530 }
1531 }
1532 if last_block {
1533 ctx.last_block_processed = true;
1534 }
1535
1536 // Load data into core, block by block.
1537 let num_full_blocks = input.len() / C::BLOCK_SIZE;
1538 for block in 0..num_full_blocks {
1539 let index = block * C::BLOCK_SIZE;
1540 // Read block out
1541 let read = Self::read_bytes(
1542 &mut self.outdma,
1543 C::BLOCK_SIZE,
1544 &mut output[index..index + C::BLOCK_SIZE],
1545 );
1546 // Write block in
1547 let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]);
1548 embassy_futures::join::join(read, write).await;
1549 }
1550
1551 // Handle the final block, which is incomplete.
1552 if last_block_remainder > 0 {
1553 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1554 let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len);
1555
1556 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1557 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1558 last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
1559 let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut intermediate_data);
1560 let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &last_block);
1561 embassy_futures::join::join(read, write).await;
1562
1563 // Handle the last block depending on mode.
1564 let output_len = output.len();
1565 output[output_len - last_block_remainder..output_len]
1566 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
1567
1568 let mut mask: [u8; 16] = [0; 16];
1569 mask[..last_block_remainder].fill(0xFF);
1570 ctx.cipher
1571 .post_final(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask)
1572 .await;
1573 }
1574
1575 ctx.payload_len += input.len() as u64;
1576
1577 self.store_context(ctx);
1578 }
1579
1580 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] 1284 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1581 /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. 1285 /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC.
1582 /// Called after the all data has been encrypted/decrypted by `payload`. 1286 /// Called after the all data has been encrypted/decrypted by `payload`.
@@ -1623,57 +1327,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1623 tag 1327 tag
1624 } 1328 }
1625 1329
1626 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1627 // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC.
1628 /// Called after the all data has been encrypted/decrypted by `payload`.
1629 pub async fn finish<
1630 'c,
1631 const TAG_SIZE: usize,
1632 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
1633 >(
1634 &mut self,
1635 mut ctx: Context<'c, C>,
1636 ) -> [u8; TAG_SIZE]
1637 where
1638 DmaIn: crate::cryp::DmaIn<T>,
1639 DmaOut: crate::cryp::DmaOut<T>,
1640 {
1641 self.load_context(&mut ctx);
1642
1643 T::regs().cr().modify(|w| w.set_crypen(false));
1644 T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
1645 T::regs().cr().modify(|w| w.set_crypen(true));
1646
1647 let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32;
1648 let headerlen2: u32 = (ctx.header_len * 8) as u32;
1649 let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32;
1650 let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
1651
1652 #[cfg(cryp_v2)]
1653 let footer: [u32; 4] = [
1654 headerlen1.swap_bytes(),
1655 headerlen2.swap_bytes(),
1656 payloadlen1.swap_bytes(),
1657 payloadlen2.swap_bytes(),
1658 ];
1659 #[cfg(any(cryp_v3, cryp_v4))]
1660 let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2];
1661
1662 let write = Self::write_words(&mut self.indma, C::BLOCK_SIZE, &footer);
1663
1664 let mut full_tag: [u8; 16] = [0; 16];
1665 let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut full_tag);
1666
1667 embassy_futures::join::join(read, write).await;
1668
1669 let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
1670 tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
1671
1672 T::regs().cr().modify(|w| w.set_crypen(false));
1673
1674 tag
1675 }
1676
1677 fn load_key(&self, key: &[u8]) { 1330 fn load_key(&self, key: &[u8]) {
1678 // Load the key into the registers. 1331 // Load the key into the registers.
1679 let mut keyidx = 0; 1332 let mut keyidx = 0;
@@ -1774,97 +1427,435 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1774 } 1427 }
1775 } 1428 }
1776 1429
1777 async fn write_bytes(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u8]) 1430 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1778 where 1431 fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) {
1779 DmaIn: crate::cryp::DmaIn<T>, 1432 assert_eq!((blocks.len() * 4) % block_size, 0);
1780 { 1433 let mut byte_counter: usize = 0;
1434 for word in blocks {
1435 T::regs().din().write_value(*word);
1436 byte_counter += 4;
1437 if byte_counter % block_size == 0 {
1438 // Block until input FIFO is empty.
1439 while !T::regs().sr().read().ifem() {}
1440 }
1441 }
1442 }
1443
1444 fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) {
1445 // Block until there is output to read.
1446 while !T::regs().sr().read().ofne() {}
1447 // Ensure input is a multiple of block size.
1448 assert_eq!(blocks.len() % block_size, 0);
1449 // Read block out
1450 let mut index = 0;
1451 let end_index = blocks.len();
1452 while index < end_index {
1453 let out_word: u32 = T::regs().dout().read();
1454 blocks[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1455 index += 4;
1456 }
1457 }
1458}
1459
1460impl<'d, T: Instance> Cryp<'d, T, Async> {
1461 /// Create a new CRYP driver.
1462 pub fn new(
1463 peri: Peri<'d, T>,
1464 indma: Peri<'d, impl DmaIn<T>>,
1465 outdma: Peri<'d, impl DmaOut<T>>,
1466 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1467 ) -> Self {
1468 rcc::enable_and_reset::<T>();
1469 let instance = Self {
1470 _peripheral: peri,
1471 _phantom: PhantomData,
1472 indma: new_dma!(indma),
1473 outdma: new_dma!(outdma),
1474 };
1475
1476 T::Interrupt::unpend();
1477 unsafe { T::Interrupt::enable() };
1478
1479 instance
1480 }
1481
1482 /// Start a new encrypt or decrypt operation for the given cipher.
1483 pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(
1484 &mut self,
1485 cipher: &'c C,
1486 dir: Direction,
1487 ) -> Context<'c, C> {
1488 let mut ctx: Context<'c, C> = Context {
1489 dir,
1490 last_block_processed: false,
1491 cr: 0,
1492 iv: [0; 4],
1493 csgcmccm: [0; 8],
1494 csgcm: [0; 8],
1495 aad_complete: false,
1496 header_len: 0,
1497 payload_len: 0,
1498 cipher: cipher,
1499 phantom_data: PhantomData,
1500 header_processed: false,
1501 aad_buffer: [0; 16],
1502 aad_buffer_len: 0,
1503 };
1504
1505 T::regs().cr().modify(|w| w.set_crypen(false));
1506
1507 let key = ctx.cipher.key();
1508
1509 if key.len() == (128 / 8) {
1510 T::regs().cr().modify(|w| w.set_keysize(0));
1511 } else if key.len() == (192 / 8) {
1512 T::regs().cr().modify(|w| w.set_keysize(1));
1513 } else if key.len() == (256 / 8) {
1514 T::regs().cr().modify(|w| w.set_keysize(2));
1515 }
1516
1517 self.load_key(key);
1518
1519 // Set data type to 8-bit. This will match software implementations.
1520 T::regs().cr().modify(|w| w.set_datatype(2));
1521
1522 ctx.cipher.prepare_key(T::regs());
1523
1524 ctx.cipher.set_algomode(T::regs());
1525
1526 // Set encrypt/decrypt
1527 if dir == Direction::Encrypt {
1528 T::regs().cr().modify(|w| w.set_algodir(false));
1529 } else {
1530 T::regs().cr().modify(|w| w.set_algodir(true));
1531 }
1532
1533 // Load the IV into the registers.
1534 let iv = ctx.cipher.iv();
1535 let mut full_iv: [u8; 16] = [0; 16];
1536 full_iv[0..iv.len()].copy_from_slice(iv);
1537 let mut iv_idx = 0;
1538 let mut iv_word: [u8; 4] = [0; 4];
1539 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1540 iv_idx += 4;
1541 T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word));
1542 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1543 iv_idx += 4;
1544 T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
1545 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1546 iv_idx += 4;
1547 T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
1548 iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
1549 T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
1550
1551 // Flush in/out FIFOs
1552 T::regs().cr().modify(|w| w.fflush());
1553
1554 ctx.cipher.init_phase(T::regs(), self).await;
1555
1556 self.store_context(&mut ctx);
1557
1558 ctx
1559 }
1560
1561 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1562 /// Controls the header phase of cipher processing.
1563 /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC.
1564 /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`.
1565 /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block.
1566 /// When supplying the last block of AAD, `last_aad_block` must be `true`.
1567 pub async fn aad<
1568 'c,
1569 const TAG_SIZE: usize,
1570 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
1571 >(
1572 &mut self,
1573 ctx: &mut Context<'c, C>,
1574 aad: &[u8],
1575 last_aad_block: bool,
1576 ) {
1577 self.load_context(ctx);
1578
1579 // Perform checks for correctness.
1580 if ctx.aad_complete {
1581 panic!("Cannot update AAD after starting payload!")
1582 }
1583
1584 ctx.header_len += aad.len() as u64;
1585
1586 // Header phase
1587 T::regs().cr().modify(|w| w.set_crypen(false));
1588 T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
1589 T::regs().cr().modify(|w| w.set_crypen(true));
1590
1591 // First write the header B1 block if not yet written.
1592 if !ctx.header_processed {
1593 ctx.header_processed = true;
1594 let header = ctx.cipher.get_header_block();
1595 ctx.aad_buffer[0..header.len()].copy_from_slice(header);
1596 ctx.aad_buffer_len += header.len();
1597 }
1598
1599 // Fill the header block to make a full block.
1600 let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len);
1601 ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]);
1602 ctx.aad_buffer_len += len_to_copy;
1603 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1604 let mut aad_len_remaining = aad.len() - len_to_copy;
1605
1606 if ctx.aad_buffer_len < C::BLOCK_SIZE {
1607 // The buffer isn't full and this is the last buffer, so process it as is (already padded).
1608 if last_aad_block {
1609 Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await;
1610 assert_eq!(T::regs().sr().read().ifem(), true);
1611
1612 // Switch to payload phase.
1613 ctx.aad_complete = true;
1614 T::regs().cr().modify(|w| w.set_crypen(false));
1615 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1616 T::regs().cr().modify(|w| w.fflush());
1617 } else {
1618 // Just return because we don't yet have a full block to process.
1619 return;
1620 }
1621 } else {
1622 // Load the full block from the buffer.
1623 Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await;
1624 assert_eq!(T::regs().sr().read().ifem(), true);
1625 }
1626
1627 // Handle a partial block that is passed in.
1628 ctx.aad_buffer_len = 0;
1629 let leftovers = aad_len_remaining % C::BLOCK_SIZE;
1630 ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]);
1631 ctx.aad_buffer_len += leftovers;
1632 ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
1633 aad_len_remaining -= leftovers;
1634 assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0);
1635
1636 // Load full data blocks into core.
1637 let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
1638 let start_index = len_to_copy;
1639 let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks);
1640 Self::write_bytes(
1641 self.indma.as_mut().unwrap(),
1642 C::BLOCK_SIZE,
1643 &aad[start_index..end_index],
1644 )
1645 .await;
1646
1647 if last_aad_block {
1648 if leftovers > 0 {
1649 Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await;
1650 assert_eq!(T::regs().sr().read().ifem(), true);
1651 }
1652 // Switch to payload phase.
1653 ctx.aad_complete = true;
1654 T::regs().cr().modify(|w| w.set_crypen(false));
1655 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1656 T::regs().cr().modify(|w| w.fflush());
1657 }
1658
1659 self.store_context(ctx);
1660 }
1661
1662 /// Performs encryption/decryption on the provided context.
1663 /// The context determines algorithm, mode, and state of the crypto accelerator.
1664 /// When the last piece of data is supplied, `last_block` should be `true`.
1665 /// This function panics under various mismatches of parameters.
1666 /// Output buffer must be at least as long as the input buffer.
1667 /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
1668 /// Padding or ciphertext stealing must be managed by the application for these modes.
1669 /// Data must also be a multiple of block size unless `last_block` is `true`.
1670 pub async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>(
1671 &mut self,
1672 ctx: &mut Context<'c, C>,
1673 input: &[u8],
1674 output: &mut [u8],
1675 last_block: bool,
1676 ) {
1677 self.load_context(ctx);
1678
1679 let last_block_remainder = input.len() % C::BLOCK_SIZE;
1680
1681 // Perform checks for correctness.
1682 if !ctx.aad_complete && ctx.header_len > 0 {
1683 panic!("Additional associated data must be processed first!");
1684 } else if !ctx.aad_complete {
1685 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1686 {
1687 ctx.aad_complete = true;
1688 T::regs().cr().modify(|w| w.set_crypen(false));
1689 T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
1690 T::regs().cr().modify(|w| w.fflush());
1691 T::regs().cr().modify(|w| w.set_crypen(true));
1692 }
1693 }
1694 if ctx.last_block_processed {
1695 panic!("The last block has already been processed!");
1696 }
1697 if input.len() > output.len() {
1698 panic!("Output buffer length must match input length.");
1699 }
1700 if !last_block {
1701 if last_block_remainder != 0 {
1702 panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
1703 }
1704 }
1705 if C::REQUIRES_PADDING {
1706 if last_block_remainder != 0 {
1707 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE);
1708 }
1709 }
1710 if last_block {
1711 ctx.last_block_processed = true;
1712 }
1713
1714 // Load data into core, block by block.
1715 let num_full_blocks = input.len() / C::BLOCK_SIZE;
1716 for block in 0..num_full_blocks {
1717 let index = block * C::BLOCK_SIZE;
1718 // Read block out
1719 let read = Self::read_bytes(
1720 self.outdma.as_mut().unwrap(),
1721 C::BLOCK_SIZE,
1722 &mut output[index..index + C::BLOCK_SIZE],
1723 );
1724 // Write block in
1725 let write = Self::write_bytes(
1726 self.indma.as_mut().unwrap(),
1727 C::BLOCK_SIZE,
1728 &input[index..index + C::BLOCK_SIZE],
1729 );
1730 embassy_futures::join::join(read, write).await;
1731 }
1732
1733 // Handle the final block, which is incomplete.
1734 if last_block_remainder > 0 {
1735 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1736 let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len);
1737
1738 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1739 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1740 last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
1741 let read = Self::read_bytes(self.outdma.as_mut().unwrap(), C::BLOCK_SIZE, &mut intermediate_data);
1742 let write = Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &last_block);
1743 embassy_futures::join::join(read, write).await;
1744
1745 // Handle the last block depending on mode.
1746 let output_len = output.len();
1747 output[output_len - last_block_remainder..output_len]
1748 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
1749
1750 let mut mask: [u8; 16] = [0; 16];
1751 mask[..last_block_remainder].fill(0xFF);
1752 ctx.cipher
1753 .post_final(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask)
1754 .await;
1755 }
1756
1757 ctx.payload_len += input.len() as u64;
1758
1759 self.store_context(ctx);
1760 }
1761
1762 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1763 // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC.
1764 /// Called after the all data has been encrypted/decrypted by `payload`.
1765 pub async fn finish<
1766 'c,
1767 const TAG_SIZE: usize,
1768 C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
1769 >(
1770 &mut self,
1771 mut ctx: Context<'c, C>,
1772 ) -> [u8; TAG_SIZE] {
1773 self.load_context(&mut ctx);
1774
1775 T::regs().cr().modify(|w| w.set_crypen(false));
1776 T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
1777 T::regs().cr().modify(|w| w.set_crypen(true));
1778
1779 let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32;
1780 let headerlen2: u32 = (ctx.header_len * 8) as u32;
1781 let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32;
1782 let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
1783
1784 #[cfg(cryp_v2)]
1785 let footer: [u32; 4] = [
1786 headerlen1.swap_bytes(),
1787 headerlen2.swap_bytes(),
1788 payloadlen1.swap_bytes(),
1789 payloadlen2.swap_bytes(),
1790 ];
1791 #[cfg(any(cryp_v3, cryp_v4))]
1792 let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2];
1793
1794 let write = Self::write_words(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &footer);
1795
1796 let mut full_tag: [u8; 16] = [0; 16];
1797 let read = Self::read_bytes(self.outdma.as_mut().unwrap(), C::BLOCK_SIZE, &mut full_tag);
1798
1799 embassy_futures::join::join(read, write).await;
1800
1801 let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
1802 tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
1803
1804 T::regs().cr().modify(|w| w.set_crypen(false));
1805
1806 tag
1807 }
1808
1809 async fn write_bytes(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &[u8]) {
1781 if blocks.len() == 0 { 1810 if blocks.len() == 0 {
1782 return; 1811 return;
1783 } 1812 }
1784 // Ensure input is a multiple of block size. 1813 // Ensure input is a multiple of block size.
1785 assert_eq!(blocks.len() % block_size, 0); 1814 assert_eq!(blocks.len() % block_size, 0);
1786 // Configure DMA to transfer input to crypto core. 1815 // Configure DMA to transfer input to crypto core.
1787 let dma_request = dma.request(); 1816 let dst_ptr: *mut u32 = T::regs().din().as_ptr();
1788 let dst_ptr = T::regs().din().as_ptr();
1789 let num_words = blocks.len() / 4; 1817 let num_words = blocks.len() / 4;
1790 let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); 1818 let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words);
1791 let options = TransferOptions { 1819 let options = TransferOptions {
1792 #[cfg(not(gpdma))] 1820 #[cfg(not(gpdma))]
1793 priority: crate::dma::Priority::High, 1821 priority: crate::dma::Priority::High,
1794 ..Default::default() 1822 ..Default::default()
1795 }; 1823 };
1796 let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; 1824 let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) };
1797 T::regs().dmacr().modify(|w| w.set_dien(true)); 1825 T::regs().dmacr().modify(|w| w.set_dien(true));
1798 // Wait for the transfer to complete. 1826 // Wait for the transfer to complete.
1799 dma_transfer.await; 1827 dma_transfer.await;
1800 } 1828 }
1801 1829
1802 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] 1830 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1803 fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { 1831 async fn write_words(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &[u32]) {
1804 assert_eq!((blocks.len() * 4) % block_size, 0);
1805 let mut byte_counter: usize = 0;
1806 for word in blocks {
1807 T::regs().din().write_value(*word);
1808 byte_counter += 4;
1809 if byte_counter % block_size == 0 {
1810 // Block until input FIFO is empty.
1811 while !T::regs().sr().read().ifem() {}
1812 }
1813 }
1814 }
1815
1816 #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
1817 async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32])
1818 where
1819 DmaIn: crate::cryp::DmaIn<T>,
1820 {
1821 if blocks.len() == 0 { 1832 if blocks.len() == 0 {
1822 return; 1833 return;
1823 } 1834 }
1824 // Ensure input is a multiple of block size. 1835 // Ensure input is a multiple of block size.
1825 assert_eq!((blocks.len() * 4) % block_size, 0); 1836 assert_eq!((blocks.len() * 4) % block_size, 0);
1826 // Configure DMA to transfer input to crypto core. 1837 // Configure DMA to transfer input to crypto core.
1827 let dma_request = dma.request(); 1838 let dst_ptr: *mut u32 = T::regs().din().as_ptr();
1828 let dst_ptr = T::regs().din().as_ptr();
1829 let num_words = blocks.len(); 1839 let num_words = blocks.len();
1830 let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); 1840 let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words);
1831 let options = TransferOptions { 1841 let options = TransferOptions {
1832 #[cfg(not(gpdma))] 1842 #[cfg(not(gpdma))]
1833 priority: crate::dma::Priority::High, 1843 priority: crate::dma::Priority::High,
1834 ..Default::default() 1844 ..Default::default()
1835 }; 1845 };
1836 let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; 1846 let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) };
1837 T::regs().dmacr().modify(|w| w.set_dien(true)); 1847 T::regs().dmacr().modify(|w| w.set_dien(true));
1838 // Wait for the transfer to complete. 1848 // Wait for the transfer to complete.
1839 dma_transfer.await; 1849 dma_transfer.await;
1840 } 1850 }
1841 1851
1842 fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) { 1852 async fn read_bytes(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &mut [u8]) {
1843 // Block until there is output to read.
1844 while !T::regs().sr().read().ofne() {}
1845 // Ensure input is a multiple of block size.
1846 assert_eq!(blocks.len() % block_size, 0);
1847 // Read block out
1848 let mut index = 0;
1849 let end_index = blocks.len();
1850 while index < end_index {
1851 let out_word: u32 = T::regs().dout().read();
1852 blocks[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
1853 index += 4;
1854 }
1855 }
1856
1857 async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8])
1858 where
1859 DmaOut: crate::cryp::DmaOut<T>,
1860 {
1861 if blocks.len() == 0 { 1853 if blocks.len() == 0 {
1862 return; 1854 return;
1863 } 1855 }
1864 // Ensure input is a multiple of block size. 1856 // Ensure input is a multiple of block size.
1865 assert_eq!(blocks.len() % block_size, 0); 1857 assert_eq!(blocks.len() % block_size, 0);
1866 // Configure DMA to get output from crypto core. 1858 // Configure DMA to get output from crypto core.
1867 let dma_request = dma.request();
1868 let src_ptr = T::regs().dout().as_ptr(); 1859 let src_ptr = T::regs().dout().as_ptr();
1869 let num_words = blocks.len() / 4; 1860 let num_words = blocks.len() / 4;
1870 let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words); 1861 let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words);
@@ -1873,7 +1864,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1873 priority: crate::dma::Priority::VeryHigh, 1864 priority: crate::dma::Priority::VeryHigh,
1874 ..Default::default() 1865 ..Default::default()
1875 }; 1866 };
1876 let dma_transfer = unsafe { Transfer::new_read_raw(dma, dma_request, src_ptr, dst_ptr, options) }; 1867 let dma_transfer = unsafe { dma.read_raw(src_ptr, dst_ptr, options) };
1877 T::regs().dmacr().modify(|w| w.set_doen(true)); 1868 T::regs().dmacr().modify(|w| w.set_doen(true));
1878 // Wait for the transfer to complete. 1869 // Wait for the transfer to complete.
1879 dma_transfer.await; 1870 dma_transfer.await;
@@ -1886,7 +1877,7 @@ trait SealedInstance {
1886 1877
1887/// CRYP instance trait. 1878/// CRYP instance trait.
1888#[allow(private_bounds)] 1879#[allow(private_bounds)]
1889pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 1880pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send {
1890 /// Interrupt for this CRYP instance. 1881 /// Interrupt for this CRYP instance.
1891 type Interrupt: interrupt::typelevel::Interrupt; 1882 type Interrupt: interrupt::typelevel::Interrupt;
1892} 1883}
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 8bba5ded0..30046849b 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -3,15 +3,15 @@
3 3
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5 5
6use embassy_hal_internal::{into_ref, PeripheralRef}; 6use crate::dma::ChannelAndRequest;
7 7use crate::mode::{Async, Blocking, Mode as PeriMode};
8use crate::dma::NoDma;
9#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] 8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
10use crate::pac::dac; 9use crate::pac::dac;
11use crate::rcc::{self, RccPeripheral}; 10use crate::rcc::{self, RccPeripheral};
12use crate::{peripherals, Peripheral}; 11use crate::{peripherals, Peri};
13 12
14mod tsel; 13mod tsel;
14use embassy_hal_internal::PeripheralType;
15pub use tsel::TriggerSel; 15pub use tsel::TriggerSel;
16 16
17/// Operating mode for DAC channel 17/// Operating mode for DAC channel
@@ -100,46 +100,34 @@ pub enum ValueArray<'a> {
100/// 100///
101/// If you want to use both channels, either together or independently, 101/// If you want to use both channels, either together or independently,
102/// create a [`Dac`] first and use it to access each channel. 102/// create a [`Dac`] first and use it to access each channel.
103pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> { 103pub struct DacChannel<'d, T: Instance, C: Channel, M: PeriMode> {
104 phantom: PhantomData<&'d mut T>, 104 phantom: PhantomData<&'d mut (T, C, M)>,
105 #[allow(unused)] 105 #[allow(unused)]
106 dma: PeripheralRef<'d, DMA>, 106 dma: Option<ChannelAndRequest<'d>>,
107} 107}
108 108
109/// DAC channel 1 type alias. 109/// DAC channel 1 type alias.
110pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; 110pub type DacCh1<'d, T, M> = DacChannel<'d, T, Ch1, M>;
111/// DAC channel 2 type alias. 111/// DAC channel 2 type alias.
112pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; 112pub type DacCh2<'d, T, M> = DacChannel<'d, T, Ch2, M>;
113
114impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
115 const IDX: usize = (N - 1) as usize;
116 113
114impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Async> {
117 /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. 115 /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
118 /// 116 ///
119 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument.
120 ///
121 /// The channel is enabled on creation and begin to drive the output pin. 117 /// The channel is enabled on creation and begin to drive the output pin.
122 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will 118 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
123 /// disable the channel; you must re-enable it with `enable()`. 119 /// disable the channel; you must re-enable it with `enable()`.
124 /// 120 ///
125 /// By default, triggering is disabled, but it can be enabled using 121 /// By default, triggering is disabled, but it can be enabled using
126 /// [`DacChannel::set_trigger()`]. 122 /// [`DacChannel::set_trigger()`].
127 pub fn new( 123 pub fn new(peri: Peri<'d, T>, dma: Peri<'d, impl Dma<T, C>>, pin: Peri<'d, impl DacPin<T, C>>) -> Self {
128 _peri: impl Peripheral<P = T> + 'd,
129 dma: impl Peripheral<P = DMA> + 'd,
130 pin: impl Peripheral<P = impl DacPin<T, N> + crate::gpio::Pin> + 'd,
131 ) -> Self {
132 into_ref!(dma, pin);
133 pin.set_as_analog(); 124 pin.set_as_analog();
134 rcc::enable_and_reset::<T>(); 125 Self::new_inner(
135 let mut dac = Self { 126 peri,
136 phantom: PhantomData, 127 new_dma!(dma),
137 dma, 128 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
138 }; 129 Mode::NormalExternalBuffered,
139 #[cfg(any(dac_v5, dac_v6, dac_v7))] 130 )
140 dac.set_hfsel();
141 dac.enable();
142 dac
143 } 131 }
144 132
145 /// Create a new `DacChannel` instance where the external output pin is not used, 133 /// Create a new `DacChannel` instance where the external output pin is not used,
@@ -150,13 +138,97 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
150 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the 138 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
151 /// channel; you must re-enable it with `enable()`. 139 /// channel; you must re-enable it with `enable()`.
152 /// 140 ///
153 /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. 141 /// By default, triggering is disabled, but it can be enabled using
142 /// [`DacChannel::set_trigger()`].
143 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
144 pub fn new_internal(peri: Peri<'d, T>, dma: Peri<'d, impl Dma<T, C>>) -> Self {
145 Self::new_inner(peri, new_dma!(dma), Mode::NormalInternalUnbuffered)
146 }
147
148 /// Write `data` to this channel via DMA.
149 ///
150 /// To prevent delays or glitches when outputing a periodic waveform, the `circular`
151 /// flag can be set. This configures a circular DMA transfer that continually outputs
152 /// `data`. Note that for performance reasons in circular mode the transfer-complete
153 /// interrupt is disabled.
154 #[cfg(not(gpdma))]
155 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) {
156 // Enable DAC and DMA
157 T::regs().cr().modify(|w| {
158 w.set_en(C::IDX, true);
159 w.set_dmaen(C::IDX, true);
160 });
161
162 let dma = self.dma.as_mut().unwrap();
163
164 let tx_options = crate::dma::TransferOptions {
165 circular,
166 half_transfer_ir: false,
167 complete_transfer_ir: !circular,
168 ..Default::default()
169 };
170
171 // Initiate the correct type of DMA transfer depending on what data is passed
172 let tx_f = match data {
173 ValueArray::Bit8(buf) => unsafe { dma.write(buf, T::regs().dhr8r(C::IDX).as_ptr() as *mut u8, tx_options) },
174 ValueArray::Bit12Left(buf) => unsafe {
175 dma.write(buf, T::regs().dhr12l(C::IDX).as_ptr() as *mut u16, tx_options)
176 },
177 ValueArray::Bit12Right(buf) => unsafe {
178 dma.write(buf, T::regs().dhr12r(C::IDX).as_ptr() as *mut u16, tx_options)
179 },
180 };
181
182 tx_f.await;
183
184 T::regs().cr().modify(|w| {
185 w.set_en(C::IDX, false);
186 w.set_dmaen(C::IDX, false);
187 });
188 }
189}
190
191impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Blocking> {
192 /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral.
193 ///
194 /// The channel is enabled on creation and begin to drive the output pin.
195 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
196 /// disable the channel; you must re-enable it with `enable()`.
197 ///
198 /// By default, triggering is disabled, but it can be enabled using
199 /// [`DacChannel::set_trigger()`].
200 pub fn new_blocking(peri: Peri<'d, T>, pin: Peri<'d, impl DacPin<T, C>>) -> Self {
201 pin.set_as_analog();
202 Self::new_inner(
203 peri,
204 None,
205 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
206 Mode::NormalExternalBuffered,
207 )
208 }
209
210 /// Create a new `DacChannel` instance where the external output pin is not used,
211 /// so the DAC can only be used to generate internal signals.
212 /// The GPIO pin is therefore available to be used for other functions.
213 ///
214 /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
215 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
216 /// channel; you must re-enable it with `enable()`.
154 /// 217 ///
155 /// By default, triggering is disabled, but it can be enabled using 218 /// By default, triggering is disabled, but it can be enabled using
156 /// [`DacChannel::set_trigger()`]. 219 /// [`DacChannel::set_trigger()`].
157 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] 220 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
158 pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self { 221 pub fn new_internal_blocking(peri: Peri<'d, T>) -> Self {
159 into_ref!(dma); 222 Self::new_inner(peri, None, Mode::NormalInternalUnbuffered)
223 }
224}
225
226impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> {
227 fn new_inner(
228 _peri: Peri<'d, T>,
229 dma: Option<ChannelAndRequest<'d>>,
230 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode,
231 ) -> Self {
160 rcc::enable_and_reset::<T>(); 232 rcc::enable_and_reset::<T>();
161 let mut dac = Self { 233 let mut dac = Self {
162 phantom: PhantomData, 234 phantom: PhantomData,
@@ -164,7 +236,8 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
164 }; 236 };
165 #[cfg(any(dac_v5, dac_v6, dac_v7))] 237 #[cfg(any(dac_v5, dac_v6, dac_v7))]
166 dac.set_hfsel(); 238 dac.set_hfsel();
167 dac.set_mode(Mode::NormalInternalUnbuffered); 239 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
240 dac.set_mode(mode);
168 dac.enable(); 241 dac.enable();
169 dac 242 dac
170 } 243 }
@@ -173,7 +246,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
173 pub fn set_enable(&mut self, on: bool) { 246 pub fn set_enable(&mut self, on: bool) {
174 critical_section::with(|_| { 247 critical_section::with(|_| {
175 T::regs().cr().modify(|reg| { 248 T::regs().cr().modify(|reg| {
176 reg.set_en(Self::IDX, on); 249 reg.set_en(C::IDX, on);
177 }); 250 });
178 }); 251 });
179 } 252 }
@@ -194,8 +267,8 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
194 pub fn set_trigger(&mut self, source: TriggerSel) { 267 pub fn set_trigger(&mut self, source: TriggerSel) {
195 critical_section::with(|_| { 268 critical_section::with(|_| {
196 T::regs().cr().modify(|reg| { 269 T::regs().cr().modify(|reg| {
197 reg.set_en(Self::IDX, false); 270 reg.set_en(C::IDX, false);
198 reg.set_tsel(Self::IDX, source as u8); 271 reg.set_tsel(C::IDX, source as u8);
199 }); 272 });
200 }); 273 });
201 } 274 }
@@ -204,7 +277,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
204 pub fn set_triggering(&mut self, on: bool) { 277 pub fn set_triggering(&mut self, on: bool) {
205 critical_section::with(|_| { 278 critical_section::with(|_| {
206 T::regs().cr().modify(|reg| { 279 T::regs().cr().modify(|reg| {
207 reg.set_ten(Self::IDX, on); 280 reg.set_ten(C::IDX, on);
208 }); 281 });
209 }); 282 });
210 } 283 }
@@ -212,7 +285,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
212 /// Software trigger this channel. 285 /// Software trigger this channel.
213 pub fn trigger(&mut self) { 286 pub fn trigger(&mut self) {
214 T::regs().swtrigr().write(|reg| { 287 T::regs().swtrigr().write(|reg| {
215 reg.set_swtrig(Self::IDX, true); 288 reg.set_swtrig(C::IDX, true);
216 }); 289 });
217 } 290 }
218 291
@@ -223,10 +296,10 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
223 pub fn set_mode(&mut self, mode: Mode) { 296 pub fn set_mode(&mut self, mode: Mode) {
224 critical_section::with(|_| { 297 critical_section::with(|_| {
225 T::regs().cr().modify(|reg| { 298 T::regs().cr().modify(|reg| {
226 reg.set_en(Self::IDX, false); 299 reg.set_en(C::IDX, false);
227 }); 300 });
228 T::regs().mcr().modify(|reg| { 301 T::regs().mcr().modify(|reg| {
229 reg.set_mode(Self::IDX, mode.mode()); 302 reg.set_mode(C::IDX, mode.mode());
230 }); 303 });
231 }); 304 });
232 } 305 }
@@ -237,15 +310,15 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
237 /// it will be output after the next trigger. 310 /// it will be output after the next trigger.
238 pub fn set(&mut self, value: Value) { 311 pub fn set(&mut self, value: Value) {
239 match value { 312 match value {
240 Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)), 313 Value::Bit8(v) => T::regs().dhr8r(C::IDX).write(|reg| reg.set_dhr(v)),
241 Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)), 314 Value::Bit12Left(v) => T::regs().dhr12l(C::IDX).write(|reg| reg.set_dhr(v)),
242 Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)), 315 Value::Bit12Right(v) => T::regs().dhr12r(C::IDX).write(|reg| reg.set_dhr(v)),
243 } 316 }
244 } 317 }
245 318
246 /// Read the current output value of the DAC. 319 /// Read the current output value of the DAC.
247 pub fn read(&self) -> u16 { 320 pub fn read(&self) -> u16 {
248 T::regs().dor(Self::IDX).read().dor() 321 T::regs().dor(C::IDX).read().dor()
249 } 322 }
250 323
251 /// Set HFSEL as appropriate for the current peripheral clock frequency. 324 /// Set HFSEL as appropriate for the current peripheral clock frequency.
@@ -279,82 +352,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
279 } 352 }
280} 353}
281 354
282macro_rules! impl_dma_methods { 355impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> {
283 ($n:literal, $trait:ident) => {
284 impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA>
285 where
286 DMA: $trait<T>,
287 {
288 /// Write `data` to this channel via DMA.
289 ///
290 /// To prevent delays or glitches when outputing a periodic waveform, the `circular`
291 /// flag can be set. This configures a circular DMA transfer that continually outputs
292 /// `data`. Note that for performance reasons in circular mode the transfer-complete
293 /// interrupt is disabled.
294 #[cfg(not(gpdma))]
295 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) {
296 // Enable DAC and DMA
297 T::regs().cr().modify(|w| {
298 w.set_en(Self::IDX, true);
299 w.set_dmaen(Self::IDX, true);
300 });
301
302 let tx_request = self.dma.request();
303 let dma_channel = &mut self.dma;
304
305 let tx_options = crate::dma::TransferOptions {
306 circular,
307 half_transfer_ir: false,
308 complete_transfer_ir: !circular,
309 ..Default::default()
310 };
311
312 // Initiate the correct type of DMA transfer depending on what data is passed
313 let tx_f = match data {
314 ValueArray::Bit8(buf) => unsafe {
315 crate::dma::Transfer::new_write(
316 dma_channel,
317 tx_request,
318 buf,
319 T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8,
320 tx_options,
321 )
322 },
323 ValueArray::Bit12Left(buf) => unsafe {
324 crate::dma::Transfer::new_write(
325 dma_channel,
326 tx_request,
327 buf,
328 T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16,
329 tx_options,
330 )
331 },
332 ValueArray::Bit12Right(buf) => unsafe {
333 crate::dma::Transfer::new_write(
334 dma_channel,
335 tx_request,
336 buf,
337 T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16,
338 tx_options,
339 )
340 },
341 };
342
343 tx_f.await;
344
345 T::regs().cr().modify(|w| {
346 w.set_en(Self::IDX, false);
347 w.set_dmaen(Self::IDX, false);
348 });
349 }
350 }
351 };
352}
353
354impl_dma_methods!(1, DacDma1);
355impl_dma_methods!(2, DacDma2);
356
357impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
358 fn drop(&mut self) { 356 fn drop(&mut self) {
359 rcc::disable::<T>(); 357 rcc::disable::<T>();
360 } 358 }
@@ -368,14 +366,14 @@ impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
368/// 366///
369/// ```ignore 367/// ```ignore
370/// // Pins may need to be changed for your specific device. 368/// // Pins may need to be changed for your specific device.
371/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split(); 369/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new_blocking(p.DAC1, p.PA4, p.PA5).split();
372/// ``` 370/// ```
373pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> { 371pub struct Dac<'d, T: Instance, M: PeriMode> {
374 ch1: DacChannel<'d, T, 1, DMACh1>, 372 ch1: DacChannel<'d, T, Ch1, M>,
375 ch2: DacChannel<'d, T, 2, DMACh2>, 373 ch2: DacChannel<'d, T, Ch2, M>,
376} 374}
377 375
378impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { 376impl<'d, T: Instance> Dac<'d, T, Async> {
379 /// Create a new `Dac` instance, consuming the underlying DAC peripheral. 377 /// Create a new `Dac` instance, consuming the underlying DAC peripheral.
380 /// 378 ///
381 /// This struct allows you to access both channels of the DAC, where available. You can either 379 /// This struct allows you to access both channels of the DAC, where available. You can either
@@ -389,37 +387,79 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
389 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` 387 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
390 /// method on the underlying channels. 388 /// method on the underlying channels.
391 pub fn new( 389 pub fn new(
392 _peri: impl Peripheral<P = T> + 'd, 390 peri: Peri<'d, T>,
393 dma_ch1: impl Peripheral<P = DMACh1> + 'd, 391 dma_ch1: Peri<'d, impl Dma<T, Ch1>>,
394 dma_ch2: impl Peripheral<P = DMACh2> + 'd, 392 dma_ch2: Peri<'d, impl Dma<T, Ch2>>,
395 pin_ch1: impl Peripheral<P = impl DacPin<T, 1> + crate::gpio::Pin> + 'd, 393 pin_ch1: Peri<'d, impl DacPin<T, Ch1> + crate::gpio::Pin>,
396 pin_ch2: impl Peripheral<P = impl DacPin<T, 2> + crate::gpio::Pin> + 'd, 394 pin_ch2: Peri<'d, impl DacPin<T, Ch2> + crate::gpio::Pin>,
397 ) -> Self { 395 ) -> Self {
398 into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2);
399 pin_ch1.set_as_analog(); 396 pin_ch1.set_as_analog();
400 pin_ch2.set_as_analog(); 397 pin_ch2.set_as_analog();
398 Self::new_inner(
399 peri,
400 new_dma!(dma_ch1),
401 new_dma!(dma_ch2),
402 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
403 Mode::NormalExternalBuffered,
404 )
405 }
401 406
402 // Enable twice to increment the DAC refcount for each channel. 407 /// Create a new `Dac` instance where the external output pins are not used,
403 rcc::enable_and_reset::<T>(); 408 /// so the DAC can only be used to generate internal signals but the GPIO
404 rcc::enable_and_reset::<T>(); 409 /// pins remain available for other functions.
405 410 ///
406 let mut ch1 = DacCh1 { 411 /// This struct allows you to access both channels of the DAC, where available. You can either
407 phantom: PhantomData, 412 /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two
408 dma: dma_ch1, 413 /// channels together.
409 }; 414 ///
410 #[cfg(any(dac_v5, dac_v6, dac_v7))] 415 /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation.
411 ch1.set_hfsel(); 416 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the
412 ch1.enable(); 417 /// channel; you must re-enable them with `enable()`.
413 418 ///
414 let mut ch2 = DacCh2 { 419 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
415 phantom: PhantomData, 420 /// method on the underlying channels.
416 dma: dma_ch2, 421 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
417 }; 422 pub fn new_internal(
418 #[cfg(any(dac_v5, dac_v6, dac_v7))] 423 peri: Peri<'d, T>,
419 ch2.set_hfsel(); 424 dma_ch1: Peri<'d, impl Dma<T, Ch1>>,
420 ch2.enable(); 425 dma_ch2: Peri<'d, impl Dma<T, Ch2>>,
426 ) -> Self {
427 Self::new_inner(
428 peri,
429 new_dma!(dma_ch1),
430 new_dma!(dma_ch2),
431 Mode::NormalInternalUnbuffered,
432 )
433 }
434}
421 435
422 Self { ch1, ch2 } 436impl<'d, T: Instance> Dac<'d, T, Blocking> {
437 /// Create a new `Dac` instance, consuming the underlying DAC peripheral.
438 ///
439 /// This struct allows you to access both channels of the DAC, where available. You can either
440 /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use
441 /// the two channels together.
442 ///
443 /// The channels are enabled on creation and begin to drive their output pins.
444 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
445 /// disable the channel; you must re-enable them with `enable()`.
446 ///
447 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
448 /// method on the underlying channels.
449 pub fn new_blocking(
450 peri: Peri<'d, T>,
451 pin_ch1: Peri<'d, impl DacPin<T, Ch1> + crate::gpio::Pin>,
452 pin_ch2: Peri<'d, impl DacPin<T, Ch2> + crate::gpio::Pin>,
453 ) -> Self {
454 pin_ch1.set_as_analog();
455 pin_ch2.set_as_analog();
456 Self::new_inner(
457 peri,
458 None,
459 None,
460 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
461 Mode::NormalExternalBuffered,
462 )
423 } 463 }
424 464
425 /// Create a new `Dac` instance where the external output pins are not used, 465 /// Create a new `Dac` instance where the external output pins are not used,
@@ -437,12 +477,18 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
437 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` 477 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
438 /// method on the underlying channels. 478 /// method on the underlying channels.
439 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] 479 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
440 pub fn new_internal( 480 pub fn new_internal(peri: Peri<'d, T>) -> Self {
441 _peri: impl Peripheral<P = T> + 'd, 481 Self::new_inner(peri, None, None, Mode::NormalInternalUnbuffered)
442 dma_ch1: impl Peripheral<P = DMACh1> + 'd, 482 }
443 dma_ch2: impl Peripheral<P = DMACh2> + 'd, 483}
484
485impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> {
486 fn new_inner(
487 _peri: Peri<'d, T>,
488 dma_ch1: Option<ChannelAndRequest<'d>>,
489 dma_ch2: Option<ChannelAndRequest<'d>>,
490 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode,
444 ) -> Self { 491 ) -> Self {
445 into_ref!(dma_ch1, dma_ch2);
446 // Enable twice to increment the DAC refcount for each channel. 492 // Enable twice to increment the DAC refcount for each channel.
447 rcc::enable_and_reset::<T>(); 493 rcc::enable_and_reset::<T>();
448 rcc::enable_and_reset::<T>(); 494 rcc::enable_and_reset::<T>();
@@ -453,7 +499,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
453 }; 499 };
454 #[cfg(any(dac_v5, dac_v6, dac_v7))] 500 #[cfg(any(dac_v5, dac_v6, dac_v7))]
455 ch1.set_hfsel(); 501 ch1.set_hfsel();
456 ch1.set_mode(Mode::NormalInternalUnbuffered); 502 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
503 ch1.set_mode(mode);
457 ch1.enable(); 504 ch1.enable();
458 505
459 let mut ch2 = DacCh2 { 506 let mut ch2 = DacCh2 {
@@ -462,7 +509,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
462 }; 509 };
463 #[cfg(any(dac_v5, dac_v6, dac_v7))] 510 #[cfg(any(dac_v5, dac_v6, dac_v7))]
464 ch2.set_hfsel(); 511 ch2.set_hfsel();
465 ch2.set_mode(Mode::NormalInternalUnbuffered); 512 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
513 ch2.set_mode(mode);
466 ch2.enable(); 514 ch2.enable();
467 515
468 Self { ch1, ch2 } 516 Self { ch1, ch2 }
@@ -471,17 +519,17 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
471 /// Split this `Dac` into separate channels. 519 /// Split this `Dac` into separate channels.
472 /// 520 ///
473 /// You can access and move the channels around separately after splitting. 521 /// You can access and move the channels around separately after splitting.
474 pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) { 522 pub fn split(self) -> (DacCh1<'d, T, M>, DacCh2<'d, T, M>) {
475 (self.ch1, self.ch2) 523 (self.ch1, self.ch2)
476 } 524 }
477 525
478 /// Temporarily access channel 1. 526 /// Temporarily access channel 1.
479 pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> { 527 pub fn ch1(&mut self) -> &mut DacCh1<'d, T, M> {
480 &mut self.ch1 528 &mut self.ch1
481 } 529 }
482 530
483 /// Temporarily access channel 2. 531 /// Temporarily access channel 2.
484 pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> { 532 pub fn ch2(&mut self) -> &mut DacCh2<'d, T, M> {
485 &mut self.ch2 533 &mut self.ch2
486 } 534 }
487 535
@@ -513,12 +561,31 @@ trait SealedInstance {
513 561
514/// DAC instance. 562/// DAC instance.
515#[allow(private_bounds)] 563#[allow(private_bounds)]
516pub trait Instance: SealedInstance + RccPeripheral + 'static {} 564pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {}
517dma_trait!(DacDma1, Instance); 565
518dma_trait!(DacDma2, Instance); 566/// Channel 1 marker type.
567pub enum Ch1 {}
568/// Channel 2 marker type.
569pub enum Ch2 {}
570
571trait SealedChannel {
572 const IDX: usize;
573}
574/// DAC channel trait.
575#[allow(private_bounds)]
576pub trait Channel: SealedChannel {}
577
578impl SealedChannel for Ch1 {
579 const IDX: usize = 0;
580}
581impl SealedChannel for Ch2 {
582 const IDX: usize = 1;
583}
584impl Channel for Ch1 {}
585impl Channel for Ch2 {}
519 586
520/// Marks a pin that can be used with the DAC 587dma_trait!(Dma, Instance, Channel);
521pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} 588pin_trait!(DacPin, Instance, Channel);
522 589
523foreach_peripheral!( 590foreach_peripheral!(
524 (dac, $inst:ident) => { 591 (dac, $inst:ident) => {
@@ -531,9 +598,3 @@ foreach_peripheral!(
531 impl crate::dac::Instance for peripherals::$inst {} 598 impl crate::dac::Instance for peripherals::$inst {}
532 }; 599 };
533); 600);
534
535macro_rules! impl_dac_pin {
536 ($inst:ident, $pin:ident, $ch:expr) => {
537 impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
538 };
539}
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 4ba4e824e..d05faee21 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -3,13 +3,13 @@ use core::future::poll_fn;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_internal::{into_ref, PeripheralRef}; 6use embassy_hal_internal::PeripheralType;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use crate::dma::Transfer; 9use crate::dma::Transfer;
10use crate::gpio::{AfType, Pull}; 10use crate::gpio::{AfType, Pull};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, rcc, Peripheral}; 12use crate::{interrupt, rcc, Peri};
13 13
14/// Interrupt handler. 14/// Interrupt handler.
15pub struct InterruptHandler<T: Instance> { 15pub struct InterruptHandler<T: Instance> {
@@ -106,8 +106,7 @@ impl Default for Config {
106 106
107macro_rules! config_pins { 107macro_rules! config_pins {
108 ($($pin:ident),*) => { 108 ($($pin:ident),*) => {
109 into_ref!($($pin),*); 109 critical_section::with(|_| {
110 critical_section::with(|_| {
111 $( 110 $(
112 $pin.set_as_af($pin.af_num(), AfType::input(Pull::None)); 111 $pin.set_as_af($pin.af_num(), AfType::input(Pull::None));
113 )* 112 )*
@@ -117,8 +116,8 @@ macro_rules! config_pins {
117 116
118/// DCMI driver. 117/// DCMI driver.
119pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> { 118pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> {
120 inner: PeripheralRef<'d, T>, 119 inner: Peri<'d, T>,
121 dma: PeripheralRef<'d, Dma>, 120 dma: Peri<'d, Dma>,
122} 121}
123 122
124impl<'d, T, Dma> Dcmi<'d, T, Dma> 123impl<'d, T, Dma> Dcmi<'d, T, Dma>
@@ -128,23 +127,22 @@ where
128{ 127{
129 /// Create a new DCMI driver with 8 data bits. 128 /// Create a new DCMI driver with 8 data bits.
130 pub fn new_8bit( 129 pub fn new_8bit(
131 peri: impl Peripheral<P = T> + 'd, 130 peri: Peri<'d, T>,
132 dma: impl Peripheral<P = Dma> + 'd, 131 dma: Peri<'d, Dma>,
133 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 132 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
134 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 133 d0: Peri<'d, impl D0Pin<T>>,
135 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 134 d1: Peri<'d, impl D1Pin<T>>,
136 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 135 d2: Peri<'d, impl D2Pin<T>>,
137 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 136 d3: Peri<'d, impl D3Pin<T>>,
138 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 137 d4: Peri<'d, impl D4Pin<T>>,
139 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 138 d5: Peri<'d, impl D5Pin<T>>,
140 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 139 d6: Peri<'d, impl D6Pin<T>>,
141 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 140 d7: Peri<'d, impl D7Pin<T>>,
142 v_sync: impl Peripheral<P = impl VSyncPin<T>> + 'd, 141 v_sync: Peri<'d, impl VSyncPin<T>>,
143 h_sync: impl Peripheral<P = impl HSyncPin<T>> + 'd, 142 h_sync: Peri<'d, impl HSyncPin<T>>,
144 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 143 pixclk: Peri<'d, impl PixClkPin<T>>,
145 config: Config, 144 config: Config,
146 ) -> Self { 145 ) -> Self {
147 into_ref!(peri, dma);
148 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7); 146 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7);
149 config_pins!(v_sync, h_sync, pixclk); 147 config_pins!(v_sync, h_sync, pixclk);
150 148
@@ -153,25 +151,24 @@ where
153 151
154 /// Create a new DCMI driver with 10 data bits. 152 /// Create a new DCMI driver with 10 data bits.
155 pub fn new_10bit( 153 pub fn new_10bit(
156 peri: impl Peripheral<P = T> + 'd, 154 peri: Peri<'d, T>,
157 dma: impl Peripheral<P = Dma> + 'd, 155 dma: Peri<'d, Dma>,
158 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 156 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
159 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 157 d0: Peri<'d, impl D0Pin<T>>,
160 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 158 d1: Peri<'d, impl D1Pin<T>>,
161 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 159 d2: Peri<'d, impl D2Pin<T>>,
162 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 160 d3: Peri<'d, impl D3Pin<T>>,
163 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 161 d4: Peri<'d, impl D4Pin<T>>,
164 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 162 d5: Peri<'d, impl D5Pin<T>>,
165 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 163 d6: Peri<'d, impl D6Pin<T>>,
166 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 164 d7: Peri<'d, impl D7Pin<T>>,
167 d8: impl Peripheral<P = impl D8Pin<T>> + 'd, 165 d8: Peri<'d, impl D8Pin<T>>,
168 d9: impl Peripheral<P = impl D9Pin<T>> + 'd, 166 d9: Peri<'d, impl D9Pin<T>>,
169 v_sync: impl Peripheral<P = impl VSyncPin<T>> + 'd, 167 v_sync: Peri<'d, impl VSyncPin<T>>,
170 h_sync: impl Peripheral<P = impl HSyncPin<T>> + 'd, 168 h_sync: Peri<'d, impl HSyncPin<T>>,
171 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 169 pixclk: Peri<'d, impl PixClkPin<T>>,
172 config: Config, 170 config: Config,
173 ) -> Self { 171 ) -> Self {
174 into_ref!(peri, dma);
175 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); 172 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9);
176 config_pins!(v_sync, h_sync, pixclk); 173 config_pins!(v_sync, h_sync, pixclk);
177 174
@@ -180,27 +177,26 @@ where
180 177
181 /// Create a new DCMI driver with 12 data bits. 178 /// Create a new DCMI driver with 12 data bits.
182 pub fn new_12bit( 179 pub fn new_12bit(
183 peri: impl Peripheral<P = T> + 'd, 180 peri: Peri<'d, T>,
184 dma: impl Peripheral<P = Dma> + 'd, 181 dma: Peri<'d, Dma>,
185 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 182 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
186 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 183 d0: Peri<'d, impl D0Pin<T>>,
187 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 184 d1: Peri<'d, impl D1Pin<T>>,
188 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 185 d2: Peri<'d, impl D2Pin<T>>,
189 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 186 d3: Peri<'d, impl D3Pin<T>>,
190 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 187 d4: Peri<'d, impl D4Pin<T>>,
191 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 188 d5: Peri<'d, impl D5Pin<T>>,
192 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 189 d6: Peri<'d, impl D6Pin<T>>,
193 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 190 d7: Peri<'d, impl D7Pin<T>>,
194 d8: impl Peripheral<P = impl D8Pin<T>> + 'd, 191 d8: Peri<'d, impl D8Pin<T>>,
195 d9: impl Peripheral<P = impl D9Pin<T>> + 'd, 192 d9: Peri<'d, impl D9Pin<T>>,
196 d10: impl Peripheral<P = impl D10Pin<T>> + 'd, 193 d10: Peri<'d, impl D10Pin<T>>,
197 d11: impl Peripheral<P = impl D11Pin<T>> + 'd, 194 d11: Peri<'d, impl D11Pin<T>>,
198 v_sync: impl Peripheral<P = impl VSyncPin<T>> + 'd, 195 v_sync: Peri<'d, impl VSyncPin<T>>,
199 h_sync: impl Peripheral<P = impl HSyncPin<T>> + 'd, 196 h_sync: Peri<'d, impl HSyncPin<T>>,
200 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 197 pixclk: Peri<'d, impl PixClkPin<T>>,
201 config: Config, 198 config: Config,
202 ) -> Self { 199 ) -> Self {
203 into_ref!(peri, dma);
204 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); 200 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
205 config_pins!(v_sync, h_sync, pixclk); 201 config_pins!(v_sync, h_sync, pixclk);
206 202
@@ -209,29 +205,28 @@ where
209 205
210 /// Create a new DCMI driver with 14 data bits. 206 /// Create a new DCMI driver with 14 data bits.
211 pub fn new_14bit( 207 pub fn new_14bit(
212 peri: impl Peripheral<P = T> + 'd, 208 peri: Peri<'d, T>,
213 dma: impl Peripheral<P = Dma> + 'd, 209 dma: Peri<'d, Dma>,
214 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 210 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
215 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 211 d0: Peri<'d, impl D0Pin<T>>,
216 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 212 d1: Peri<'d, impl D1Pin<T>>,
217 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 213 d2: Peri<'d, impl D2Pin<T>>,
218 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 214 d3: Peri<'d, impl D3Pin<T>>,
219 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 215 d4: Peri<'d, impl D4Pin<T>>,
220 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 216 d5: Peri<'d, impl D5Pin<T>>,
221 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 217 d6: Peri<'d, impl D6Pin<T>>,
222 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 218 d7: Peri<'d, impl D7Pin<T>>,
223 d8: impl Peripheral<P = impl D8Pin<T>> + 'd, 219 d8: Peri<'d, impl D8Pin<T>>,
224 d9: impl Peripheral<P = impl D9Pin<T>> + 'd, 220 d9: Peri<'d, impl D9Pin<T>>,
225 d10: impl Peripheral<P = impl D10Pin<T>> + 'd, 221 d10: Peri<'d, impl D10Pin<T>>,
226 d11: impl Peripheral<P = impl D11Pin<T>> + 'd, 222 d11: Peri<'d, impl D11Pin<T>>,
227 d12: impl Peripheral<P = impl D12Pin<T>> + 'd, 223 d12: Peri<'d, impl D12Pin<T>>,
228 d13: impl Peripheral<P = impl D13Pin<T>> + 'd, 224 d13: Peri<'d, impl D13Pin<T>>,
229 v_sync: impl Peripheral<P = impl VSyncPin<T>> + 'd, 225 v_sync: Peri<'d, impl VSyncPin<T>>,
230 h_sync: impl Peripheral<P = impl HSyncPin<T>> + 'd, 226 h_sync: Peri<'d, impl HSyncPin<T>>,
231 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 227 pixclk: Peri<'d, impl PixClkPin<T>>,
232 config: Config, 228 config: Config,
233 ) -> Self { 229 ) -> Self {
234 into_ref!(peri, dma);
235 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); 230 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13);
236 config_pins!(v_sync, h_sync, pixclk); 231 config_pins!(v_sync, h_sync, pixclk);
237 232
@@ -240,21 +235,20 @@ where
240 235
241 /// Create a new DCMI driver with 8 data bits, with embedded synchronization. 236 /// Create a new DCMI driver with 8 data bits, with embedded synchronization.
242 pub fn new_es_8bit( 237 pub fn new_es_8bit(
243 peri: impl Peripheral<P = T> + 'd, 238 peri: Peri<'d, T>,
244 dma: impl Peripheral<P = Dma> + 'd, 239 dma: Peri<'d, Dma>,
245 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 240 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
246 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 241 d0: Peri<'d, impl D0Pin<T>>,
247 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 242 d1: Peri<'d, impl D1Pin<T>>,
248 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 243 d2: Peri<'d, impl D2Pin<T>>,
249 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 244 d3: Peri<'d, impl D3Pin<T>>,
250 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 245 d4: Peri<'d, impl D4Pin<T>>,
251 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 246 d5: Peri<'d, impl D5Pin<T>>,
252 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 247 d6: Peri<'d, impl D6Pin<T>>,
253 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 248 d7: Peri<'d, impl D7Pin<T>>,
254 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 249 pixclk: Peri<'d, impl PixClkPin<T>>,
255 config: Config, 250 config: Config,
256 ) -> Self { 251 ) -> Self {
257 into_ref!(peri, dma);
258 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7); 252 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7);
259 config_pins!(pixclk); 253 config_pins!(pixclk);
260 254
@@ -263,23 +257,22 @@ where
263 257
264 /// Create a new DCMI driver with 10 data bits, with embedded synchronization. 258 /// Create a new DCMI driver with 10 data bits, with embedded synchronization.
265 pub fn new_es_10bit( 259 pub fn new_es_10bit(
266 peri: impl Peripheral<P = T> + 'd, 260 peri: Peri<'d, T>,
267 dma: impl Peripheral<P = Dma> + 'd, 261 dma: Peri<'d, Dma>,
268 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 262 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
269 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 263 d0: Peri<'d, impl D0Pin<T>>,
270 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 264 d1: Peri<'d, impl D1Pin<T>>,
271 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 265 d2: Peri<'d, impl D2Pin<T>>,
272 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 266 d3: Peri<'d, impl D3Pin<T>>,
273 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 267 d4: Peri<'d, impl D4Pin<T>>,
274 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 268 d5: Peri<'d, impl D5Pin<T>>,
275 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 269 d6: Peri<'d, impl D6Pin<T>>,
276 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 270 d7: Peri<'d, impl D7Pin<T>>,
277 d8: impl Peripheral<P = impl D8Pin<T>> + 'd, 271 d8: Peri<'d, impl D8Pin<T>>,
278 d9: impl Peripheral<P = impl D9Pin<T>> + 'd, 272 d9: Peri<'d, impl D9Pin<T>>,
279 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 273 pixclk: Peri<'d, impl PixClkPin<T>>,
280 config: Config, 274 config: Config,
281 ) -> Self { 275 ) -> Self {
282 into_ref!(peri, dma);
283 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); 276 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9);
284 config_pins!(pixclk); 277 config_pins!(pixclk);
285 278
@@ -288,25 +281,24 @@ where
288 281
289 /// Create a new DCMI driver with 12 data bits, with embedded synchronization. 282 /// Create a new DCMI driver with 12 data bits, with embedded synchronization.
290 pub fn new_es_12bit( 283 pub fn new_es_12bit(
291 peri: impl Peripheral<P = T> + 'd, 284 peri: Peri<'d, T>,
292 dma: impl Peripheral<P = Dma> + 'd, 285 dma: Peri<'d, Dma>,
293 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 286 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
294 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 287 d0: Peri<'d, impl D0Pin<T>>,
295 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 288 d1: Peri<'d, impl D1Pin<T>>,
296 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 289 d2: Peri<'d, impl D2Pin<T>>,
297 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 290 d3: Peri<'d, impl D3Pin<T>>,
298 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 291 d4: Peri<'d, impl D4Pin<T>>,
299 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 292 d5: Peri<'d, impl D5Pin<T>>,
300 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 293 d6: Peri<'d, impl D6Pin<T>>,
301 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 294 d7: Peri<'d, impl D7Pin<T>>,
302 d8: impl Peripheral<P = impl D8Pin<T>> + 'd, 295 d8: Peri<'d, impl D8Pin<T>>,
303 d9: impl Peripheral<P = impl D9Pin<T>> + 'd, 296 d9: Peri<'d, impl D9Pin<T>>,
304 d10: impl Peripheral<P = impl D10Pin<T>> + 'd, 297 d10: Peri<'d, impl D10Pin<T>>,
305 d11: impl Peripheral<P = impl D11Pin<T>> + 'd, 298 d11: Peri<'d, impl D11Pin<T>>,
306 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 299 pixclk: Peri<'d, impl PixClkPin<T>>,
307 config: Config, 300 config: Config,
308 ) -> Self { 301 ) -> Self {
309 into_ref!(peri, dma);
310 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); 302 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
311 config_pins!(pixclk); 303 config_pins!(pixclk);
312 304
@@ -315,27 +307,26 @@ where
315 307
316 /// Create a new DCMI driver with 14 data bits, with embedded synchronization. 308 /// Create a new DCMI driver with 14 data bits, with embedded synchronization.
317 pub fn new_es_14bit( 309 pub fn new_es_14bit(
318 peri: impl Peripheral<P = T> + 'd, 310 peri: Peri<'d, T>,
319 dma: impl Peripheral<P = Dma> + 'd, 311 dma: Peri<'d, Dma>,
320 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 312 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
321 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 313 d0: Peri<'d, impl D0Pin<T>>,
322 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 314 d1: Peri<'d, impl D1Pin<T>>,
323 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 315 d2: Peri<'d, impl D2Pin<T>>,
324 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 316 d3: Peri<'d, impl D3Pin<T>>,
325 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 317 d4: Peri<'d, impl D4Pin<T>>,
326 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 318 d5: Peri<'d, impl D5Pin<T>>,
327 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 319 d6: Peri<'d, impl D6Pin<T>>,
328 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 320 d7: Peri<'d, impl D7Pin<T>>,
329 d8: impl Peripheral<P = impl D8Pin<T>> + 'd, 321 d8: Peri<'d, impl D8Pin<T>>,
330 d9: impl Peripheral<P = impl D9Pin<T>> + 'd, 322 d9: Peri<'d, impl D9Pin<T>>,
331 d10: impl Peripheral<P = impl D10Pin<T>> + 'd, 323 d10: Peri<'d, impl D10Pin<T>>,
332 d11: impl Peripheral<P = impl D11Pin<T>> + 'd, 324 d11: Peri<'d, impl D11Pin<T>>,
333 d12: impl Peripheral<P = impl D12Pin<T>> + 'd, 325 d12: Peri<'d, impl D12Pin<T>>,
334 d13: impl Peripheral<P = impl D13Pin<T>> + 'd, 326 d13: Peri<'d, impl D13Pin<T>>,
335 pixclk: impl Peripheral<P = impl PixClkPin<T>> + 'd, 327 pixclk: Peri<'d, impl PixClkPin<T>>,
336 config: Config, 328 config: Config,
337 ) -> Self { 329 ) -> Self {
338 into_ref!(peri, dma);
339 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); 330 config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13);
340 config_pins!(pixclk); 331 config_pins!(pixclk);
341 332
@@ -343,8 +334,8 @@ where
343 } 334 }
344 335
345 fn new_inner( 336 fn new_inner(
346 peri: PeripheralRef<'d, T>, 337 peri: Peri<'d, T>,
347 dma: PeripheralRef<'d, Dma>, 338 dma: Peri<'d, Dma>,
348 config: Config, 339 config: Config,
349 use_embedded_synchronization: bool, 340 use_embedded_synchronization: bool,
350 edm: u8, 341 edm: u8,
@@ -396,7 +387,7 @@ where
396 let r = self.inner.regs(); 387 let r = self.inner.regs();
397 let src = r.dr().as_ptr() as *mut u32; 388 let src = r.dr().as_ptr() as *mut u32;
398 let request = self.dma.request(); 389 let request = self.dma.request();
399 let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; 390 let dma_read = unsafe { Transfer::new_read(self.dma.reborrow(), request, src, buffer, Default::default()) };
400 391
401 Self::clear_interrupt_flags(); 392 Self::clear_interrupt_flags();
402 Self::enable_irqs(); 393 Self::enable_irqs();
@@ -435,7 +426,7 @@ trait SealedInstance: crate::rcc::RccPeripheral {
435 426
436/// DCMI instance. 427/// DCMI instance.
437#[allow(private_bounds)] 428#[allow(private_bounds)]
438pub trait Instance: SealedInstance + 'static { 429pub trait Instance: SealedInstance + PeripheralType + 'static {
439 /// Interrupt for this instance. 430 /// Interrupt for this instance.
440 type Interrupt: interrupt::typelevel::Interrupt; 431 type Interrupt: interrupt::typelevel::Interrupt;
441} 432}
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index 8a6aa53a0..7dbbe7b72 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -3,10 +3,10 @@ use core::pin::Pin;
3use core::sync::atomic::{fence, AtomicUsize, Ordering}; 3use core::sync::atomic::{fence, AtomicUsize, Ordering};
4use core::task::{Context, Poll, Waker}; 4use core::task::{Context, Poll, Waker};
5 5
6use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 6use embassy_hal_internal::Peri;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 9use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
10use super::word::{Word, WordSize}; 10use super::word::{Word, WordSize};
11use super::{AnyChannel, Channel, Dir, Request, STATE}; 11use super::{AnyChannel, Channel, Dir, Request, STATE};
12use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
@@ -15,6 +15,8 @@ use crate::{interrupt, pac};
15pub(crate) struct ChannelInfo { 15pub(crate) struct ChannelInfo {
16 pub(crate) dma: DmaInfo, 16 pub(crate) dma: DmaInfo,
17 pub(crate) num: usize, 17 pub(crate) num: usize,
18 #[cfg(feature = "_dual-core")]
19 pub(crate) irq: pac::Interrupt,
18 #[cfg(dmamux)] 20 #[cfg(dmamux)]
19 pub(crate) dmamux: super::DmamuxInfo, 21 pub(crate) dmamux: super::DmamuxInfo,
20} 22}
@@ -98,7 +100,7 @@ impl From<Priority> for pac::dma::vals::Pl {
98 Priority::Low => pac::dma::vals::Pl::LOW, 100 Priority::Low => pac::dma::vals::Pl::LOW,
99 Priority::Medium => pac::dma::vals::Pl::MEDIUM, 101 Priority::Medium => pac::dma::vals::Pl::MEDIUM,
100 Priority::High => pac::dma::vals::Pl::HIGH, 102 Priority::High => pac::dma::vals::Pl::HIGH,
101 Priority::VeryHigh => pac::dma::vals::Pl::VERYHIGH, 103 Priority::VeryHigh => pac::dma::vals::Pl::VERY_HIGH,
102 } 104 }
103 } 105 }
104} 106}
@@ -110,7 +112,7 @@ impl From<Priority> for pac::bdma::vals::Pl {
110 Priority::Low => pac::bdma::vals::Pl::LOW, 112 Priority::Low => pac::bdma::vals::Pl::LOW,
111 Priority::Medium => pac::bdma::vals::Pl::MEDIUM, 113 Priority::Medium => pac::bdma::vals::Pl::MEDIUM,
112 Priority::High => pac::bdma::vals::Pl::HIGH, 114 Priority::High => pac::bdma::vals::Pl::HIGH,
113 Priority::VeryHigh => pac::bdma::vals::Pl::VERYHIGH, 115 Priority::VeryHigh => pac::bdma::vals::Pl::VERY_HIGH,
114 } 116 }
115 } 117 }
116} 118}
@@ -136,8 +138,8 @@ mod dma_only {
136 impl From<Dir> for vals::Dir { 138 impl From<Dir> for vals::Dir {
137 fn from(raw: Dir) -> Self { 139 fn from(raw: Dir) -> Self {
138 match raw { 140 match raw {
139 Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL, 141 Dir::MemoryToPeripheral => Self::MEMORY_TO_PERIPHERAL,
140 Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY, 142 Dir::PeripheralToMemory => Self::PERIPHERAL_TO_MEMORY,
141 } 143 }
142 } 144 }
143 } 145 }
@@ -205,7 +207,7 @@ mod dma_only {
205 match value { 207 match value {
206 FifoThreshold::Quarter => vals::Fth::QUARTER, 208 FifoThreshold::Quarter => vals::Fth::QUARTER,
207 FifoThreshold::Half => vals::Fth::HALF, 209 FifoThreshold::Half => vals::Fth::HALF,
208 FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS, 210 FifoThreshold::ThreeQuarters => vals::Fth::THREE_QUARTERS,
209 FifoThreshold::Full => vals::Fth::FULL, 211 FifoThreshold::Full => vals::Fth::FULL,
210 } 212 }
211 } 213 }
@@ -231,8 +233,8 @@ mod bdma_only {
231 impl From<Dir> for vals::Dir { 233 impl From<Dir> for vals::Dir {
232 fn from(raw: Dir) -> Self { 234 fn from(raw: Dir) -> Self {
233 match raw { 235 match raw {
234 Dir::MemoryToPeripheral => Self::FROMMEMORY, 236 Dir::MemoryToPeripheral => Self::FROM_MEMORY,
235 Dir::PeripheralToMemory => Self::FROMPERIPHERAL, 237 Dir::PeripheralToMemory => Self::FROM_PERIPHERAL,
236 } 238 }
237 } 239 }
238 } 240 }
@@ -259,10 +261,12 @@ pub(crate) unsafe fn init(
259 foreach_interrupt! { 261 foreach_interrupt! {
260 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { 262 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
261 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority); 263 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority);
264 #[cfg(not(feature = "_dual-core"))]
262 crate::interrupt::typelevel::$irq::enable(); 265 crate::interrupt::typelevel::$irq::enable();
263 }; 266 };
264 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { 267 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
265 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority); 268 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority);
269 #[cfg(not(feature = "_dual-core"))]
266 crate::interrupt::typelevel::$irq::enable(); 270 crate::interrupt::typelevel::$irq::enable();
267 }; 271 };
268 } 272 }
@@ -295,7 +299,6 @@ impl AnyChannel {
295 } else { 299 } else {
296 return; 300 return;
297 } 301 }
298
299 state.waker.wake(); 302 state.waker.wake();
300 } 303 }
301 #[cfg(bdma)] 304 #[cfg(bdma)]
@@ -337,10 +340,16 @@ impl AnyChannel {
337 mem_addr: *mut u32, 340 mem_addr: *mut u32,
338 mem_len: usize, 341 mem_len: usize,
339 incr_mem: bool, 342 incr_mem: bool,
340 data_size: WordSize, 343 mem_size: WordSize,
344 peripheral_size: WordSize,
341 options: TransferOptions, 345 options: TransferOptions,
342 ) { 346 ) {
343 let info = self.info(); 347 let info = self.info();
348 #[cfg(feature = "_dual-core")]
349 {
350 use embassy_hal_internal::interrupt::InterruptExt as _;
351 info.irq.enable();
352 }
344 353
345 #[cfg(dmamux)] 354 #[cfg(dmamux)]
346 super::dmamux::configure_dmamux(&info.dmamux, _request); 355 super::dmamux::configure_dmamux(&info.dmamux, _request);
@@ -350,11 +359,13 @@ impl AnyChannel {
350 match self.info().dma { 359 match self.info().dma {
351 #[cfg(dma)] 360 #[cfg(dma)]
352 DmaInfo::Dma(r) => { 361 DmaInfo::Dma(r) => {
362 let state: &ChannelState = &STATE[self.id as usize];
353 let ch = r.st(info.num); 363 let ch = r.st(info.num);
354 364
355 // "Preceding reads and writes cannot be moved past subsequent writes." 365 // "Preceding reads and writes cannot be moved past subsequent writes."
356 fence(Ordering::SeqCst); 366 fence(Ordering::SeqCst);
357 367
368 state.complete_count.store(0, Ordering::Release);
358 self.clear_irqs(); 369 self.clear_irqs();
359 370
360 ch.par().write_value(peri_addr as u32); 371 ch.par().write_value(peri_addr as u32);
@@ -372,8 +383,8 @@ impl AnyChannel {
372 }); 383 });
373 ch.cr().write(|w| { 384 ch.cr().write(|w| {
374 w.set_dir(dir.into()); 385 w.set_dir(dir.into());
375 w.set_msize(data_size.into()); 386 w.set_msize(mem_size.into());
376 w.set_psize(data_size.into()); 387 w.set_psize(peripheral_size.into());
377 w.set_pl(options.priority.into()); 388 w.set_pl(options.priority.into());
378 w.set_minc(incr_mem); 389 w.set_minc(incr_mem);
379 w.set_pinc(false); 390 w.set_pinc(false);
@@ -406,8 +417,8 @@ impl AnyChannel {
406 ch.mar().write_value(mem_addr as u32); 417 ch.mar().write_value(mem_addr as u32);
407 ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); 418 ch.ndtr().write(|w| w.set_ndt(mem_len as u16));
408 ch.cr().write(|w| { 419 ch.cr().write(|w| {
409 w.set_psize(data_size.into()); 420 w.set_psize(peripheral_size.into());
410 w.set_msize(data_size.into()); 421 w.set_msize(mem_size.into());
411 w.set_minc(incr_mem); 422 w.set_minc(incr_mem);
412 w.set_dir(dir.into()); 423 w.set_dir(dir.into());
413 w.set_teie(true); 424 w.set_teie(true);
@@ -484,6 +495,26 @@ impl AnyChannel {
484 } 495 }
485 } 496 }
486 497
498 fn request_pause(&self) {
499 let info = self.info();
500 match self.info().dma {
501 #[cfg(dma)]
502 DmaInfo::Dma(r) => {
503 // Disable the channel without overwriting the existing configuration
504 r.st(info.num).cr().modify(|w| {
505 w.set_en(false);
506 });
507 }
508 #[cfg(bdma)]
509 DmaInfo::Bdma(r) => {
510 // Disable the channel without overwriting the existing configuration
511 r.ch(info.num).cr().modify(|w| {
512 w.set_en(false);
513 });
514 }
515 }
516 }
517
487 fn is_running(&self) -> bool { 518 fn is_running(&self) -> bool {
488 let info = self.info(); 519 let info = self.info();
489 match self.info().dma { 520 match self.info().dma {
@@ -540,13 +571,13 @@ impl AnyChannel {
540/// DMA transfer. 571/// DMA transfer.
541#[must_use = "futures do nothing unless you `.await` or poll them"] 572#[must_use = "futures do nothing unless you `.await` or poll them"]
542pub struct Transfer<'a> { 573pub struct Transfer<'a> {
543 channel: PeripheralRef<'a, AnyChannel>, 574 channel: Peri<'a, AnyChannel>,
544} 575}
545 576
546impl<'a> Transfer<'a> { 577impl<'a> Transfer<'a> {
547 /// Create a new read DMA transfer (peripheral to memory). 578 /// Create a new read DMA transfer (peripheral to memory).
548 pub unsafe fn new_read<W: Word>( 579 pub unsafe fn new_read<W: Word>(
549 channel: impl Peripheral<P = impl Channel> + 'a, 580 channel: Peri<'a, impl Channel>,
550 request: Request, 581 request: Request,
551 peri_addr: *mut W, 582 peri_addr: *mut W,
552 buf: &'a mut [W], 583 buf: &'a mut [W],
@@ -557,16 +588,14 @@ impl<'a> Transfer<'a> {
557 588
558 /// Create a new read DMA transfer (peripheral to memory), using raw pointers. 589 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
559 pub unsafe fn new_read_raw<W: Word>( 590 pub unsafe fn new_read_raw<W: Word>(
560 channel: impl Peripheral<P = impl Channel> + 'a, 591 channel: Peri<'a, impl Channel>,
561 request: Request, 592 request: Request,
562 peri_addr: *mut W, 593 peri_addr: *mut W,
563 buf: *mut [W], 594 buf: *mut [W],
564 options: TransferOptions, 595 options: TransferOptions,
565 ) -> Self { 596 ) -> Self {
566 into_ref!(channel);
567
568 Self::new_inner( 597 Self::new_inner(
569 channel.map_into(), 598 channel.into(),
570 request, 599 request,
571 Dir::PeripheralToMemory, 600 Dir::PeripheralToMemory,
572 peri_addr as *const u32, 601 peri_addr as *const u32,
@@ -574,57 +603,55 @@ impl<'a> Transfer<'a> {
574 buf.len(), 603 buf.len(),
575 true, 604 true,
576 W::size(), 605 W::size(),
606 W::size(),
577 options, 607 options,
578 ) 608 )
579 } 609 }
580 610
581 /// Create a new write DMA transfer (memory to peripheral). 611 /// Create a new write DMA transfer (memory to peripheral).
582 pub unsafe fn new_write<W: Word>( 612 pub unsafe fn new_write<MW: Word, PW: Word>(
583 channel: impl Peripheral<P = impl Channel> + 'a, 613 channel: Peri<'a, impl Channel>,
584 request: Request, 614 request: Request,
585 buf: &'a [W], 615 buf: &'a [MW],
586 peri_addr: *mut W, 616 peri_addr: *mut PW,
587 options: TransferOptions, 617 options: TransferOptions,
588 ) -> Self { 618 ) -> Self {
589 Self::new_write_raw(channel, request, buf, peri_addr, options) 619 Self::new_write_raw(channel, request, buf, peri_addr, options)
590 } 620 }
591 621
592 /// Create a new write DMA transfer (memory to peripheral), using raw pointers. 622 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
593 pub unsafe fn new_write_raw<W: Word>( 623 pub unsafe fn new_write_raw<MW: Word, PW: Word>(
594 channel: impl Peripheral<P = impl Channel> + 'a, 624 channel: Peri<'a, impl Channel>,
595 request: Request, 625 request: Request,
596 buf: *const [W], 626 buf: *const [MW],
597 peri_addr: *mut W, 627 peri_addr: *mut PW,
598 options: TransferOptions, 628 options: TransferOptions,
599 ) -> Self { 629 ) -> Self {
600 into_ref!(channel);
601
602 Self::new_inner( 630 Self::new_inner(
603 channel.map_into(), 631 channel.into(),
604 request, 632 request,
605 Dir::MemoryToPeripheral, 633 Dir::MemoryToPeripheral,
606 peri_addr as *const u32, 634 peri_addr as *const u32,
607 buf as *const W as *mut u32, 635 buf as *const MW as *mut u32,
608 buf.len(), 636 buf.len(),
609 true, 637 true,
610 W::size(), 638 MW::size(),
639 PW::size(),
611 options, 640 options,
612 ) 641 )
613 } 642 }
614 643
615 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. 644 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
616 pub unsafe fn new_write_repeated<W: Word>( 645 pub unsafe fn new_write_repeated<W: Word>(
617 channel: impl Peripheral<P = impl Channel> + 'a, 646 channel: Peri<'a, impl Channel>,
618 request: Request, 647 request: Request,
619 repeated: &'a W, 648 repeated: &'a W,
620 count: usize, 649 count: usize,
621 peri_addr: *mut W, 650 peri_addr: *mut W,
622 options: TransferOptions, 651 options: TransferOptions,
623 ) -> Self { 652 ) -> Self {
624 into_ref!(channel);
625
626 Self::new_inner( 653 Self::new_inner(
627 channel.map_into(), 654 channel.into(),
628 request, 655 request,
629 Dir::MemoryToPeripheral, 656 Dir::MemoryToPeripheral,
630 peri_addr as *const u32, 657 peri_addr as *const u32,
@@ -632,12 +659,13 @@ impl<'a> Transfer<'a> {
632 count, 659 count,
633 false, 660 false,
634 W::size(), 661 W::size(),
662 W::size(),
635 options, 663 options,
636 ) 664 )
637 } 665 }
638 666
639 unsafe fn new_inner( 667 unsafe fn new_inner(
640 channel: PeripheralRef<'a, AnyChannel>, 668 channel: Peri<'a, AnyChannel>,
641 _request: Request, 669 _request: Request,
642 dir: Dir, 670 dir: Dir,
643 peri_addr: *const u32, 671 peri_addr: *const u32,
@@ -645,25 +673,43 @@ impl<'a> Transfer<'a> {
645 mem_len: usize, 673 mem_len: usize,
646 incr_mem: bool, 674 incr_mem: bool,
647 data_size: WordSize, 675 data_size: WordSize,
676 peripheral_size: WordSize,
648 options: TransferOptions, 677 options: TransferOptions,
649 ) -> Self { 678 ) -> Self {
650 assert!(mem_len > 0 && mem_len <= 0xFFFF); 679 assert!(mem_len > 0 && mem_len <= 0xFFFF);
651 680
652 channel.configure( 681 channel.configure(
653 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, data_size, options, 682 _request,
683 dir,
684 peri_addr,
685 mem_addr,
686 mem_len,
687 incr_mem,
688 data_size,
689 peripheral_size,
690 options,
654 ); 691 );
655 channel.start(); 692 channel.start();
656
657 Self { channel } 693 Self { channel }
658 } 694 }
659 695
660 /// Request the transfer to stop. 696 /// Request the transfer to stop.
697 /// The configuration for this channel will **not be preserved**. If you need to restart the transfer
698 /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead.
661 /// 699 ///
662 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. 700 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
663 pub fn request_stop(&mut self) { 701 pub fn request_stop(&mut self) {
664 self.channel.request_stop() 702 self.channel.request_stop()
665 } 703 }
666 704
705 /// Request the transfer to pause, keeping the existing configuration for this channel.
706 /// To restart the transfer, call [`start`](Self::start) again.
707 ///
708 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
709 pub fn request_pause(&mut self) {
710 self.channel.request_pause()
711 }
712
667 /// Return whether this transfer is still running. 713 /// Return whether this transfer is still running.
668 /// 714 ///
669 /// If this returns `false`, it can be because either the transfer finished, or 715 /// If this returns `false`, it can be because either the transfer finished, or
@@ -717,17 +763,13 @@ impl<'a> Future for Transfer<'a> {
717 763
718// ============================== 764// ==============================
719 765
720struct DmaCtrlImpl<'a>(PeripheralRef<'a, AnyChannel>); 766struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>);
721 767
722impl<'a> DmaCtrl for DmaCtrlImpl<'a> { 768impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
723 fn get_remaining_transfers(&self) -> usize { 769 fn get_remaining_transfers(&self) -> usize {
724 self.0.get_remaining_transfers() as _ 770 self.0.get_remaining_transfers() as _
725 } 771 }
726 772
727 fn get_complete_count(&self) -> usize {
728 STATE[self.0.id as usize].complete_count.load(Ordering::Acquire)
729 }
730
731 fn reset_complete_count(&mut self) -> usize { 773 fn reset_complete_count(&mut self) -> usize {
732 let state = &STATE[self.0.id as usize]; 774 let state = &STATE[self.0.id as usize];
733 #[cfg(not(armv6m))] 775 #[cfg(not(armv6m))]
@@ -747,27 +789,27 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
747 789
748/// Ringbuffer for receiving data using DMA circular mode. 790/// Ringbuffer for receiving data using DMA circular mode.
749pub struct ReadableRingBuffer<'a, W: Word> { 791pub struct ReadableRingBuffer<'a, W: Word> {
750 channel: PeripheralRef<'a, AnyChannel>, 792 channel: Peri<'a, AnyChannel>,
751 ringbuf: ReadableDmaRingBuffer<'a, W>, 793 ringbuf: ReadableDmaRingBuffer<'a, W>,
752} 794}
753 795
754impl<'a, W: Word> ReadableRingBuffer<'a, W> { 796impl<'a, W: Word> ReadableRingBuffer<'a, W> {
755 /// Create a new ring buffer. 797 /// Create a new ring buffer.
756 pub unsafe fn new( 798 pub unsafe fn new(
757 channel: impl Peripheral<P = impl Channel> + 'a, 799 channel: Peri<'a, impl Channel>,
758 _request: Request, 800 _request: Request,
759 peri_addr: *mut W, 801 peri_addr: *mut W,
760 buffer: &'a mut [W], 802 buffer: &'a mut [W],
761 mut options: TransferOptions, 803 mut options: TransferOptions,
762 ) -> Self { 804 ) -> Self {
763 into_ref!(channel); 805 let channel: Peri<'a, AnyChannel> = channel.into();
764 let channel: PeripheralRef<'a, AnyChannel> = channel.map_into();
765 806
766 let buffer_ptr = buffer.as_mut_ptr(); 807 let buffer_ptr = buffer.as_mut_ptr();
767 let len = buffer.len(); 808 let len = buffer.len();
768 let dir = Dir::PeripheralToMemory; 809 let dir = Dir::PeripheralToMemory;
769 let data_size = W::size(); 810 let data_size = W::size();
770 811
812 options.half_transfer_ir = true;
771 options.complete_transfer_ir = true; 813 options.complete_transfer_ir = true;
772 options.circular = true; 814 options.circular = true;
773 815
@@ -779,6 +821,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
779 len, 821 len,
780 true, 822 true,
781 data_size, 823 data_size,
824 data_size,
782 options, 825 options,
783 ); 826 );
784 827
@@ -792,27 +835,27 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
792 /// 835 ///
793 /// You must call this after creating it for it to work. 836 /// You must call this after creating it for it to work.
794 pub fn start(&mut self) { 837 pub fn start(&mut self) {
795 self.channel.start() 838 self.channel.start();
796 } 839 }
797 840
798 /// Clear all data in the ring buffer. 841 /// Clear all data in the ring buffer.
799 pub fn clear(&mut self) { 842 pub fn clear(&mut self) {
800 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 843 self.ringbuf.reset(&mut DmaCtrlImpl(self.channel.reborrow()));
801 } 844 }
802 845
803 /// Read elements from the ring buffer 846 /// Read elements from the ring buffer
804 /// Return a tuple of the length read and the length remaining in the buffer 847 /// Return a tuple of the length read and the length remaining in the buffer
805 /// If not all of the elements were read, then there will be some elements in the buffer remaining 848 /// If not all of the elements were read, then there will be some elements in the buffer remaining
806 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read 849 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
807 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 850 /// Error is returned if the portion to be read was overwritten by the DMA controller.
808 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 851 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), Error> {
809 self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) 852 self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
810 } 853 }
811 854
812 /// Read an exact number of elements from the ringbuffer. 855 /// Read an exact number of elements from the ringbuffer.
813 /// 856 ///
814 /// Returns the remaining number of elements available for immediate reading. 857 /// Returns the remaining number of elements available for immediate reading.
815 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 858 /// Error is returned if the portion to be read was overwritten by the DMA controller.
816 /// 859 ///
817 /// Async/Wake Behavior: 860 /// Async/Wake Behavior:
818 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, 861 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
@@ -820,12 +863,17 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
820 /// ring buffer was created with a buffer of size 'N': 863 /// ring buffer was created with a buffer of size 'N':
821 /// - 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. 864 /// - 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.
822 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. 865 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
823 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { 866 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, Error> {
824 self.ringbuf 867 self.ringbuf
825 .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) 868 .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
826 .await 869 .await
827 } 870 }
828 871
872 /// The current length of the ringbuffer
873 pub fn len(&mut self) -> Result<usize, Error> {
874 Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?)
875 }
876
829 /// The capacity of the ringbuffer 877 /// The capacity of the ringbuffer
830 pub const fn capacity(&self) -> usize { 878 pub const fn capacity(&self) -> usize {
831 self.ringbuf.cap() 879 self.ringbuf.cap()
@@ -836,13 +884,23 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
836 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 884 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
837 } 885 }
838 886
839 /// Request DMA to stop. 887 /// Request the DMA to stop.
888 /// The configuration for this channel will **not be preserved**. If you need to restart the transfer
889 /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead.
840 /// 890 ///
841 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. 891 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
842 pub fn request_stop(&mut self) { 892 pub fn request_stop(&mut self) {
843 self.channel.request_stop() 893 self.channel.request_stop()
844 } 894 }
845 895
896 /// Request the transfer to pause, keeping the existing configuration for this channel.
897 /// To restart the transfer, call [`start`](Self::start) again.
898 ///
899 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
900 pub fn request_pause(&mut self) {
901 self.channel.request_pause()
902 }
903
846 /// Return whether DMA is still running. 904 /// Return whether DMA is still running.
847 /// 905 ///
848 /// If this returns `false`, it can be because either the transfer finished, or 906 /// If this returns `false`, it can be because either the transfer finished, or
@@ -883,21 +941,20 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
883 941
884/// Ringbuffer for writing data using DMA circular mode. 942/// Ringbuffer for writing data using DMA circular mode.
885pub struct WritableRingBuffer<'a, W: Word> { 943pub struct WritableRingBuffer<'a, W: Word> {
886 channel: PeripheralRef<'a, AnyChannel>, 944 channel: Peri<'a, AnyChannel>,
887 ringbuf: WritableDmaRingBuffer<'a, W>, 945 ringbuf: WritableDmaRingBuffer<'a, W>,
888} 946}
889 947
890impl<'a, W: Word> WritableRingBuffer<'a, W> { 948impl<'a, W: Word> WritableRingBuffer<'a, W> {
891 /// Create a new ring buffer. 949 /// Create a new ring buffer.
892 pub unsafe fn new( 950 pub unsafe fn new(
893 channel: impl Peripheral<P = impl Channel> + 'a, 951 channel: Peri<'a, impl Channel>,
894 _request: Request, 952 _request: Request,
895 peri_addr: *mut W, 953 peri_addr: *mut W,
896 buffer: &'a mut [W], 954 buffer: &'a mut [W],
897 mut options: TransferOptions, 955 mut options: TransferOptions,
898 ) -> Self { 956 ) -> Self {
899 into_ref!(channel); 957 let channel: Peri<'a, AnyChannel> = channel.into();
900 let channel: PeripheralRef<'a, AnyChannel> = channel.map_into();
901 958
902 let len = buffer.len(); 959 let len = buffer.len();
903 let dir = Dir::MemoryToPeripheral; 960 let dir = Dir::MemoryToPeripheral;
@@ -916,6 +973,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
916 len, 973 len,
917 true, 974 true,
918 data_size, 975 data_size,
976 data_size,
919 options, 977 options,
920 ); 978 );
921 979
@@ -929,34 +987,45 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
929 /// 987 ///
930 /// You must call this after creating it for it to work. 988 /// You must call this after creating it for it to work.
931 pub fn start(&mut self) { 989 pub fn start(&mut self) {
932 self.channel.start() 990 self.channel.start();
933 } 991 }
934 992
935 /// Clear all data in the ring buffer. 993 /// Clear all data in the ring buffer.
936 pub fn clear(&mut self) { 994 pub fn clear(&mut self) {
937 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 995 self.ringbuf.reset(&mut DmaCtrlImpl(self.channel.reborrow()));
938 } 996 }
939 997
940 /// Write elements directly to the raw buffer. 998 /// Write elements directly to the raw buffer.
941 /// This can be used to fill the buffer before starting the DMA transfer. 999 /// This can be used to fill the buffer before starting the DMA transfer.
942 #[allow(dead_code)] 1000 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
943 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
944 self.ringbuf.write_immediate(buf) 1001 self.ringbuf.write_immediate(buf)
945 } 1002 }
946 1003
947 /// Write elements from the ring buffer 1004 /// Write elements from the ring buffer
948 /// Return a tuple of the length written and the length remaining in the buffer 1005 /// Return a tuple of the length written and the length remaining in the buffer
949 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { 1006 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
950 self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) 1007 self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
951 } 1008 }
952 1009
953 /// Write an exact number of elements to the ringbuffer. 1010 /// Write an exact number of elements to the ringbuffer.
954 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { 1011 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> {
955 self.ringbuf 1012 self.ringbuf
956 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) 1013 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
957 .await 1014 .await
958 } 1015 }
959 1016
1017 /// Wait for any ring buffer write error.
1018 pub async fn wait_write_error(&mut self) -> Result<usize, Error> {
1019 self.ringbuf
1020 .wait_write_error(&mut DmaCtrlImpl(self.channel.reborrow()))
1021 .await
1022 }
1023
1024 /// The current length of the ringbuffer
1025 pub fn len(&mut self) -> Result<usize, Error> {
1026 Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?)
1027 }
1028
960 /// The capacity of the ringbuffer 1029 /// The capacity of the ringbuffer
961 pub const fn capacity(&self) -> usize { 1030 pub const fn capacity(&self) -> usize {
962 self.ringbuf.cap() 1031 self.ringbuf.cap()
@@ -967,13 +1036,23 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
967 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 1036 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
968 } 1037 }
969 1038
970 /// Request DMA to stop. 1039 /// Request the DMA to stop.
1040 /// The configuration for this channel will **not be preserved**. If you need to restart the transfer
1041 /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead.
971 /// 1042 ///
972 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. 1043 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
973 pub fn request_stop(&mut self) { 1044 pub fn request_stop(&mut self) {
974 self.channel.request_stop() 1045 self.channel.request_stop()
975 } 1046 }
976 1047
1048 /// Request the transfer to pause, keeping the existing configuration for this channel.
1049 /// To restart the transfer, call [`start`](Self::start) again.
1050 ///
1051 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
1052 pub fn request_pause(&mut self) {
1053 self.channel.request_pause()
1054 }
1055
977 /// Return whether DMA is still running. 1056 /// Return whether DMA is still running.
978 /// 1057 ///
979 /// If this returns `false`, it can be because either the transfer finished, or 1058 /// If this returns `false`, it can be because either the transfer finished, or
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index 13d5d15be..ade70fb55 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -5,7 +5,7 @@ use core::pin::Pin;
5use core::sync::atomic::{fence, Ordering}; 5use core::sync::atomic::{fence, Ordering};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 8use embassy_hal_internal::Peri;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use super::word::{Word, WordSize}; 11use super::word::{Word, WordSize};
@@ -18,6 +18,8 @@ use crate::pac::gpdma::vals;
18pub(crate) struct ChannelInfo { 18pub(crate) struct ChannelInfo {
19 pub(crate) dma: pac::gpdma::Gpdma, 19 pub(crate) dma: pac::gpdma::Gpdma,
20 pub(crate) num: usize, 20 pub(crate) num: usize,
21 #[cfg(feature = "_dual-core")]
22 pub(crate) irq: pac::Interrupt,
21} 23}
22 24
23/// GPDMA transfer options. 25/// GPDMA transfer options.
@@ -36,7 +38,7 @@ impl From<WordSize> for vals::Dw {
36 fn from(raw: WordSize) -> Self { 38 fn from(raw: WordSize) -> Self {
37 match raw { 39 match raw {
38 WordSize::OneByte => Self::BYTE, 40 WordSize::OneByte => Self::BYTE,
39 WordSize::TwoBytes => Self::HALFWORD, 41 WordSize::TwoBytes => Self::HALF_WORD,
40 WordSize::FourBytes => Self::WORD, 42 WordSize::FourBytes => Self::WORD,
41 } 43 }
42 } 44 }
@@ -57,6 +59,7 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: P
57 foreach_interrupt! { 59 foreach_interrupt! {
58 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { 60 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
59 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); 61 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
62 #[cfg(not(feature = "_dual-core"))]
60 crate::interrupt::typelevel::$irq::enable(); 63 crate::interrupt::typelevel::$irq::enable();
61 }; 64 };
62 } 65 }
@@ -67,6 +70,12 @@ impl AnyChannel {
67 /// Safety: Must be called with a matching set of parameters for a valid dma channel 70 /// Safety: Must be called with a matching set of parameters for a valid dma channel
68 pub(crate) unsafe fn on_irq(&self) { 71 pub(crate) unsafe fn on_irq(&self) {
69 let info = self.info(); 72 let info = self.info();
73 #[cfg(feature = "_dual-core")]
74 {
75 use embassy_hal_internal::interrupt::InterruptExt as _;
76 info.irq.enable();
77 }
78
70 let state = &STATE[self.id as usize]; 79 let state = &STATE[self.id as usize];
71 80
72 let ch = info.dma.ch(info.num); 81 let ch = info.dma.ch(info.num);
@@ -100,13 +109,13 @@ impl AnyChannel {
100/// DMA transfer. 109/// DMA transfer.
101#[must_use = "futures do nothing unless you `.await` or poll them"] 110#[must_use = "futures do nothing unless you `.await` or poll them"]
102pub struct Transfer<'a> { 111pub struct Transfer<'a> {
103 channel: PeripheralRef<'a, AnyChannel>, 112 channel: Peri<'a, AnyChannel>,
104} 113}
105 114
106impl<'a> Transfer<'a> { 115impl<'a> Transfer<'a> {
107 /// Create a new read DMA transfer (peripheral to memory). 116 /// Create a new read DMA transfer (peripheral to memory).
108 pub unsafe fn new_read<W: Word>( 117 pub unsafe fn new_read<W: Word>(
109 channel: impl Peripheral<P = impl Channel> + 'a, 118 channel: Peri<'a, impl Channel>,
110 request: Request, 119 request: Request,
111 peri_addr: *mut W, 120 peri_addr: *mut W,
112 buf: &'a mut [W], 121 buf: &'a mut [W],
@@ -117,16 +126,14 @@ impl<'a> Transfer<'a> {
117 126
118 /// Create a new read DMA transfer (peripheral to memory), using raw pointers. 127 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
119 pub unsafe fn new_read_raw<W: Word>( 128 pub unsafe fn new_read_raw<W: Word>(
120 channel: impl Peripheral<P = impl Channel> + 'a, 129 channel: Peri<'a, impl Channel>,
121 request: Request, 130 request: Request,
122 peri_addr: *mut W, 131 peri_addr: *mut W,
123 buf: *mut [W], 132 buf: *mut [W],
124 options: TransferOptions, 133 options: TransferOptions,
125 ) -> Self { 134 ) -> Self {
126 into_ref!(channel);
127
128 Self::new_inner( 135 Self::new_inner(
129 channel.map_into(), 136 channel.into(),
130 request, 137 request,
131 Dir::PeripheralToMemory, 138 Dir::PeripheralToMemory,
132 peri_addr as *const u32, 139 peri_addr as *const u32,
@@ -134,70 +141,69 @@ impl<'a> Transfer<'a> {
134 buf.len(), 141 buf.len(),
135 true, 142 true,
136 W::size(), 143 W::size(),
144 W::size(),
137 options, 145 options,
138 ) 146 )
139 } 147 }
140 148
141 /// Create a new write DMA transfer (memory to peripheral). 149 /// Create a new write DMA transfer (memory to peripheral).
142 pub unsafe fn new_write<W: Word>( 150 pub unsafe fn new_write<MW: Word, PW: Word>(
143 channel: impl Peripheral<P = impl Channel> + 'a, 151 channel: Peri<'a, impl Channel>,
144 request: Request, 152 request: Request,
145 buf: &'a [W], 153 buf: &'a [MW],
146 peri_addr: *mut W, 154 peri_addr: *mut PW,
147 options: TransferOptions, 155 options: TransferOptions,
148 ) -> Self { 156 ) -> Self {
149 Self::new_write_raw(channel, request, buf, peri_addr, options) 157 Self::new_write_raw(channel, request, buf, peri_addr, options)
150 } 158 }
151 159
152 /// Create a new write DMA transfer (memory to peripheral), using raw pointers. 160 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
153 pub unsafe fn new_write_raw<W: Word>( 161 pub unsafe fn new_write_raw<MW: Word, PW: Word>(
154 channel: impl Peripheral<P = impl Channel> + 'a, 162 channel: Peri<'a, impl Channel>,
155 request: Request, 163 request: Request,
156 buf: *const [W], 164 buf: *const [MW],
157 peri_addr: *mut W, 165 peri_addr: *mut PW,
158 options: TransferOptions, 166 options: TransferOptions,
159 ) -> Self { 167 ) -> Self {
160 into_ref!(channel);
161
162 Self::new_inner( 168 Self::new_inner(
163 channel.map_into(), 169 channel.into(),
164 request, 170 request,
165 Dir::MemoryToPeripheral, 171 Dir::MemoryToPeripheral,
166 peri_addr as *const u32, 172 peri_addr as *const u32,
167 buf as *const W as *mut u32, 173 buf as *const MW as *mut u32,
168 buf.len(), 174 buf.len(),
169 true, 175 true,
170 W::size(), 176 MW::size(),
177 PW::size(),
171 options, 178 options,
172 ) 179 )
173 } 180 }
174 181
175 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. 182 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
176 pub unsafe fn new_write_repeated<W: Word>( 183 pub unsafe fn new_write_repeated<MW: Word, PW: Word>(
177 channel: impl Peripheral<P = impl Channel> + 'a, 184 channel: Peri<'a, impl Channel>,
178 request: Request, 185 request: Request,
179 repeated: &'a W, 186 repeated: &'a MW,
180 count: usize, 187 count: usize,
181 peri_addr: *mut W, 188 peri_addr: *mut PW,
182 options: TransferOptions, 189 options: TransferOptions,
183 ) -> Self { 190 ) -> Self {
184 into_ref!(channel);
185
186 Self::new_inner( 191 Self::new_inner(
187 channel.map_into(), 192 channel.into(),
188 request, 193 request,
189 Dir::MemoryToPeripheral, 194 Dir::MemoryToPeripheral,
190 peri_addr as *const u32, 195 peri_addr as *const u32,
191 repeated as *const W as *mut u32, 196 repeated as *const MW as *mut u32,
192 count, 197 count,
193 false, 198 false,
194 W::size(), 199 MW::size(),
200 PW::size(),
195 options, 201 options,
196 ) 202 )
197 } 203 }
198 204
199 unsafe fn new_inner( 205 unsafe fn new_inner(
200 channel: PeripheralRef<'a, AnyChannel>, 206 channel: Peri<'a, AnyChannel>,
201 request: Request, 207 request: Request,
202 dir: Dir, 208 dir: Dir,
203 peri_addr: *const u32, 209 peri_addr: *const u32,
@@ -205,9 +211,13 @@ impl<'a> Transfer<'a> {
205 mem_len: usize, 211 mem_len: usize,
206 incr_mem: bool, 212 incr_mem: bool,
207 data_size: WordSize, 213 data_size: WordSize,
214 dst_size: WordSize,
208 _options: TransferOptions, 215 _options: TransferOptions,
209 ) -> Self { 216 ) -> Self {
210 assert!(mem_len > 0 && mem_len <= 0xFFFF); 217 // BNDT is specified as bytes, not as number of transfers.
218 let Ok(bndt) = (mem_len * data_size.bytes()).try_into() else {
219 panic!("DMA transfers may not be larger than 65535 bytes.");
220 };
211 221
212 let info = channel.info(); 222 let info = channel.info();
213 let ch = info.dma.ch(info.num); 223 let ch = info.dma.ch(info.num);
@@ -217,29 +227,24 @@ impl<'a> Transfer<'a> {
217 227
218 let this = Self { channel }; 228 let this = Self { channel };
219 229
220 #[cfg(dmamux)]
221 super::dmamux::configure_dmamux(&*this.channel, request);
222
223 ch.cr().write(|w| w.set_reset(true)); 230 ch.cr().write(|w| w.set_reset(true));
224 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs 231 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs
225 ch.llr().write(|_| {}); // no linked list 232 ch.llr().write(|_| {}); // no linked list
226 ch.tr1().write(|w| { 233 ch.tr1().write(|w| {
227 w.set_sdw(data_size.into()); 234 w.set_sdw(data_size.into());
228 w.set_ddw(data_size.into()); 235 w.set_ddw(dst_size.into());
229 w.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem); 236 w.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem);
230 w.set_dinc(dir == Dir::PeripheralToMemory && incr_mem); 237 w.set_dinc(dir == Dir::PeripheralToMemory && incr_mem);
231 }); 238 });
232 ch.tr2().write(|w| { 239 ch.tr2().write(|w| {
233 w.set_dreq(match dir { 240 w.set_dreq(match dir {
234 Dir::MemoryToPeripheral => vals::Dreq::DESTINATIONPERIPHERAL, 241 Dir::MemoryToPeripheral => vals::Dreq::DESTINATION_PERIPHERAL,
235 Dir::PeripheralToMemory => vals::Dreq::SOURCEPERIPHERAL, 242 Dir::PeripheralToMemory => vals::Dreq::SOURCE_PERIPHERAL,
236 }); 243 });
237 w.set_reqsel(request); 244 w.set_reqsel(request);
238 }); 245 });
239 ch.br1().write(|w| { 246 ch.tr3().write(|_| {}); // no address offsets.
240 // BNDT is specified as bytes, not as number of transfers. 247 ch.br1().write(|w| w.set_bndt(bndt));
241 w.set_bndt((mem_len * data_size.bytes()) as u16)
242 });
243 248
244 match dir { 249 match dir {
245 Dir::MemoryToPeripheral => { 250 Dir::MemoryToPeripheral => {
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 66c4aa53c..d3b070a6d 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -22,7 +22,7 @@ pub(crate) use util::*;
22pub(crate) mod ringbuffer; 22pub(crate) mod ringbuffer;
23pub mod word; 23pub mod word;
24 24
25use embassy_hal_internal::{impl_peripheral, Peripheral}; 25use embassy_hal_internal::{impl_peripheral, PeripheralType};
26 26
27use crate::interrupt; 27use crate::interrupt;
28 28
@@ -51,17 +51,7 @@ pub(crate) trait ChannelInterrupt {
51 51
52/// DMA channel. 52/// DMA channel.
53#[allow(private_bounds)] 53#[allow(private_bounds)]
54pub trait Channel: SealedChannel + Peripheral<P = Self> + Into<AnyChannel> + 'static { 54pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {}
55 /// Type-erase (degrade) this pin into an `AnyChannel`.
56 ///
57 /// This converts DMA channel singletons (`DMA1_CH3`, `DMA2_CH1`, ...), which
58 /// are all different types, into the same type. It is useful for
59 /// creating arrays of channels, or avoiding generics.
60 #[inline]
61 fn degrade(self) -> AnyChannel {
62 AnyChannel { id: self.id() }
63 }
64}
65 55
66macro_rules! dma_channel_impl { 56macro_rules! dma_channel_impl {
67 ($channel_peri:ident, $index:expr) => { 57 ($channel_peri:ident, $index:expr) => {
@@ -79,8 +69,10 @@ macro_rules! dma_channel_impl {
79 impl crate::dma::Channel for crate::peripherals::$channel_peri {} 69 impl crate::dma::Channel for crate::peripherals::$channel_peri {}
80 70
81 impl From<crate::peripherals::$channel_peri> for crate::dma::AnyChannel { 71 impl From<crate::peripherals::$channel_peri> for crate::dma::AnyChannel {
82 fn from(x: crate::peripherals::$channel_peri) -> Self { 72 fn from(val: crate::peripherals::$channel_peri) -> Self {
83 crate::dma::Channel::degrade(x) 73 Self {
74 id: crate::dma::SealedChannel::id(&val),
75 }
84 } 76 }
85 } 77 }
86 }; 78 };
@@ -108,17 +100,6 @@ impl Channel for AnyChannel {}
108const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len(); 100const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len();
109static STATE: [ChannelState; CHANNEL_COUNT] = [ChannelState::NEW; CHANNEL_COUNT]; 101static STATE: [ChannelState; CHANNEL_COUNT] = [ChannelState::NEW; CHANNEL_COUNT];
110 102
111/// "No DMA" placeholder.
112///
113/// You may pass this in place of a real DMA channel when creating a driver
114/// to indicate it should not use DMA.
115///
116/// This often causes async functionality to not be available on the instance,
117/// leaving only blocking functionality.
118pub struct NoDma;
119
120impl_peripheral!(NoDma);
121
122// safety: must be called only once at startup 103// safety: must be called only once at startup
123pub(crate) unsafe fn init( 104pub(crate) unsafe fn init(
124 cs: critical_section::CriticalSection, 105 cs: critical_section::CriticalSection,
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs
deleted file mode 100644
index 23f1d67d5..000000000
--- a/embassy-stm32/src/dma/ringbuffer.rs
+++ /dev/null
@@ -1,668 +0,0 @@
1#![cfg_attr(gpdma, allow(unused))]
2
3use core::future::poll_fn;
4use core::ops::Range;
5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::{Poll, Waker};
7
8use super::word::Word;
9
10/// A "read-only" ring-buffer to be used together with the DMA controller which
11/// writes in a circular way, "uncontrolled" to the buffer.
12///
13/// A snapshot of the ring buffer state can be attained by setting the `ndtr` field
14/// to the current register value. `ndtr` describes the current position of the DMA
15/// write.
16///
17/// # Buffer layout
18///
19/// ```text
20/// Without wraparound: With wraparound:
21///
22/// + buf +--- NDTR ---+ + buf +---------- NDTR ----------+
23/// | | | | | |
24/// v v v v v v
25/// +-----------------------------------------+ +-----------------------------------------+
26/// |oooooooooooXXXXXXXXXXXXXXXXoooooooooooooo| |XXXXXXXXXXXXXooooooooooooXXXXXXXXXXXXXXXX|
27/// +-----------------------------------------+ +-----------------------------------------+
28/// ^ ^ ^ ^ ^ ^
29/// | | | | | |
30/// +- start --+ | +- end ------+ |
31/// | | | |
32/// +- end --------------------+ +- start ----------------+
33/// ```
34pub struct ReadableDmaRingBuffer<'a, W: Word> {
35 pub(crate) dma_buf: &'a mut [W],
36 start: usize,
37}
38
39#[derive(Debug, PartialEq)]
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
41pub struct OverrunError;
42
43pub trait DmaCtrl {
44 /// Get the NDTR register value, i.e. the space left in the underlying
45 /// buffer until the dma writer wraps.
46 fn get_remaining_transfers(&self) -> usize;
47
48 /// Get the transfer completed counter.
49 /// This counter is incremented by the dma controller when NDTR is reloaded,
50 /// i.e. when the writing wraps.
51 fn get_complete_count(&self) -> usize;
52
53 /// Reset the transfer completed counter to 0 and return the value just prior to the reset.
54 fn reset_complete_count(&mut self) -> usize;
55
56 /// Set the waker for a running poll_fn
57 fn set_waker(&mut self, waker: &Waker);
58}
59
60impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
61 pub fn new(dma_buf: &'a mut [W]) -> Self {
62 Self { dma_buf, start: 0 }
63 }
64
65 /// Reset the ring buffer to its initial state
66 pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
67 self.start = 0;
68 dma.reset_complete_count();
69 }
70
71 /// The capacity of the ringbuffer
72 pub const fn cap(&self) -> usize {
73 self.dma_buf.len()
74 }
75
76 /// The current position of the ringbuffer
77 fn pos(&self, dma: &mut impl DmaCtrl) -> usize {
78 self.cap() - dma.get_remaining_transfers()
79 }
80
81 /// Read an exact number of elements from the ringbuffer.
82 ///
83 /// Returns the remaining number of elements available for immediate reading.
84 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
85 ///
86 /// Async/Wake Behavior:
87 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
88 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
89 /// ring buffer was created with a buffer of size 'N':
90 /// - 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.
91 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
92 pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result<usize, OverrunError> {
93 let mut read_data = 0;
94 let buffer_len = buffer.len();
95
96 poll_fn(|cx| {
97 dma.set_waker(cx.waker());
98
99 compiler_fence(Ordering::SeqCst);
100
101 match self.read(dma, &mut buffer[read_data..buffer_len]) {
102 Ok((len, remaining)) => {
103 read_data += len;
104 if read_data == buffer_len {
105 Poll::Ready(Ok(remaining))
106 } else {
107 Poll::Pending
108 }
109 }
110 Err(e) => Poll::Ready(Err(e)),
111 }
112 })
113 .await
114 }
115
116 /// Read elements from the ring buffer
117 /// Return a tuple of the length read and the length remaining in the buffer
118 /// If not all of the elements were read, then there will be some elements in the buffer remaining
119 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
120 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
121 pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
122 /*
123 This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check
124 after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed
125 to fire in the same clock cycle that a register is read, so checking get_complete_count early does
126 not yield relevant information.
127
128 Therefore, the only variable we really need to know is ndtr. If the dma has overrun by more than a full
129 buffer, we will do a bit more work than we have to, but algorithms should not be optimized for error
130 conditions.
131
132 After we've done our work, we confirm that we haven't overrun more than a full buffer, and also that
133 the dma has not overrun within the data we could have copied. We check the data we could have copied
134 rather than the data we actually copied because it costs nothing and confirms an error condition
135 earlier.
136 */
137 let end = self.pos(dma);
138 if self.start == end && dma.get_complete_count() == 0 {
139 // No elements are available in the buffer
140 Ok((0, self.cap()))
141 } else if self.start < end {
142 // The available, unread portion in the ring buffer DOES NOT wrap
143 // Copy out the elements from the dma buffer
144 let len = self.copy_to(buf, self.start..end);
145
146 compiler_fence(Ordering::SeqCst);
147
148 /*
149 first, check if the dma has wrapped at all if it's after end
150 or more than once if it's before start
151
152 this is in a critical section to try to reduce mushy behavior.
153 it's not ideal but it's the best we can do
154
155 then, get the current position of of the dma write and check
156 if it's inside data we could have copied
157 */
158 let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count()));
159 if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 {
160 Err(OverrunError)
161 } else {
162 self.start = (self.start + len) % self.cap();
163
164 Ok((len, self.cap() - self.start))
165 }
166 } else if self.start + buf.len() < self.cap() {
167 // The available, unread portion in the ring buffer DOES wrap
168 // The DMA writer has wrapped since we last read and is currently
169 // writing (or the next byte added will be) in the beginning of the ring buffer.
170
171 // The provided read buffer is not large enough to include all elements from the tail of the dma buffer.
172
173 // Copy out from the dma buffer
174 let len = self.copy_to(buf, self.start..self.cap());
175
176 compiler_fence(Ordering::SeqCst);
177
178 /*
179 first, check if the dma has wrapped around more than once
180
181 then, get the current position of of the dma write and check
182 if it's inside data we could have copied
183 */
184 let pos = self.pos(dma);
185 if pos > self.start || pos < end || dma.get_complete_count() > 1 {
186 Err(OverrunError)
187 } else {
188 self.start = (self.start + len) % self.cap();
189
190 Ok((len, self.start + end))
191 }
192 } else {
193 // The available, unread portion in the ring buffer DOES wrap
194 // The DMA writer has wrapped since we last read and is currently
195 // writing (or the next byte added will be) in the beginning of the ring buffer.
196
197 // The provided read buffer is large enough to include all elements from the tail of the dma buffer,
198 // so the next read will not have any unread tail elements in the ring buffer.
199
200 // Copy out from the dma buffer
201 let tail = self.copy_to(buf, self.start..self.cap());
202 let head = self.copy_to(&mut buf[tail..], 0..end);
203
204 compiler_fence(Ordering::SeqCst);
205
206 /*
207 first, check if the dma has wrapped around more than once
208
209 then, get the current position of of the dma write and check
210 if it's inside data we could have copied
211 */
212 let pos = self.pos(dma);
213 if pos > self.start || pos < end || dma.reset_complete_count() > 1 {
214 Err(OverrunError)
215 } else {
216 self.start = head;
217 Ok((tail + head, self.cap() - self.start))
218 }
219 }
220 }
221 /// Copy from the dma buffer at `data_range` into `buf`
222 fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize {
223 // Limit the number of elements that can be copied
224 let length = usize::min(data_range.len(), buf.len());
225
226 // Copy from dma buffer into read buffer
227 // We need to do it like this instead of a simple copy_from_slice() because
228 // reading from a part of memory that may be simultaneously written to is unsafe
229 unsafe {
230 let dma_buf = self.dma_buf.as_ptr();
231
232 for i in 0..length {
233 buf[i] = core::ptr::read_volatile(dma_buf.offset((data_range.start + i) as isize));
234 }
235 }
236
237 length
238 }
239}
240
241pub struct WritableDmaRingBuffer<'a, W: Word> {
242 pub(crate) dma_buf: &'a mut [W],
243 end: usize,
244}
245
246impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
247 pub fn new(dma_buf: &'a mut [W]) -> Self {
248 Self { dma_buf, end: 0 }
249 }
250
251 /// Reset the ring buffer to its initial state
252 pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
253 self.end = 0;
254 dma.reset_complete_count();
255 }
256
257 /// The capacity of the ringbuffer
258 pub const fn cap(&self) -> usize {
259 self.dma_buf.len()
260 }
261
262 /// The current position of the ringbuffer
263 fn pos(&self, dma: &mut impl DmaCtrl) -> usize {
264 self.cap() - dma.get_remaining_transfers()
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
278 /// Write an exact number of elements to the ringbuffer.
279 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> {
280 let mut written_data = 0;
281 let buffer_len = buffer.len();
282
283 poll_fn(|cx| {
284 dma.set_waker(cx.waker());
285
286 compiler_fence(Ordering::SeqCst);
287
288 match self.write(dma, &buffer[written_data..buffer_len]) {
289 Ok((len, remaining)) => {
290 written_data += len;
291 if written_data == buffer_len {
292 Poll::Ready(Ok(remaining))
293 } else {
294 Poll::Pending
295 }
296 }
297 Err(e) => Poll::Ready(Err(e)),
298 }
299 })
300 .await
301 }
302
303 /// Write elements from the ring buffer
304 /// Return a tuple of the length written and the capacity remaining to be written in the buffer
305 pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
306 let start = self.pos(dma);
307 if start > self.end {
308 // The occupied portion in the ring buffer DOES wrap
309 let len = self.copy_from(buf, self.end..start);
310
311 compiler_fence(Ordering::SeqCst);
312
313 // Confirm that the DMA is not inside data we could have written
314 let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count()));
315 if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 {
316 Err(OverrunError)
317 } else {
318 self.end = (self.end + len) % self.cap();
319
320 Ok((len, self.cap() - (start - self.end)))
321 }
322 } else if start == self.end && dma.get_complete_count() == 0 {
323 Ok((0, 0))
324 } else if start <= self.end && self.end + buf.len() < self.cap() {
325 // The occupied portion in the ring buffer DOES NOT wrap
326 // and copying elements into the buffer WILL NOT cause it to
327
328 // Copy into the dma buffer
329 let len = self.copy_from(buf, self.end..self.cap());
330
331 compiler_fence(Ordering::SeqCst);
332
333 // Confirm that the DMA is not inside data we could have written
334 let pos = self.pos(dma);
335 if pos > self.end || pos < start || dma.get_complete_count() > 1 {
336 Err(OverrunError)
337 } else {
338 self.end = (self.end + len) % self.cap();
339
340 Ok((len, self.cap() - (self.end - start)))
341 }
342 } else {
343 // The occupied portion in the ring buffer DOES NOT wrap
344 // and copying elements into the buffer WILL cause it to
345
346 let tail = self.copy_from(buf, self.end..self.cap());
347 let head = self.copy_from(&buf[tail..], 0..start);
348
349 compiler_fence(Ordering::SeqCst);
350
351 // Confirm that the DMA is not inside data we could have written
352 let pos = self.pos(dma);
353 if pos > self.end || pos < start || dma.reset_complete_count() > 1 {
354 Err(OverrunError)
355 } else {
356 self.end = head;
357
358 Ok((tail + head, self.cap() - (start - self.end)))
359 }
360 }
361 }
362 /// Copy into the dma buffer at `data_range` from `buf`
363 fn copy_from(&mut self, buf: &[W], data_range: Range<usize>) -> usize {
364 // Limit the number of elements that can be copied
365 let length = usize::min(data_range.len(), buf.len());
366
367 // Copy into dma buffer from read buffer
368 // We need to do it like this instead of a simple copy_from_slice() because
369 // reading from a part of memory that may be simultaneously written to is unsafe
370 unsafe {
371 let dma_buf = self.dma_buf.as_mut_ptr();
372
373 for i in 0..length {
374 core::ptr::write_volatile(dma_buf.offset((data_range.start + i) as isize), buf[i]);
375 }
376 }
377
378 length
379 }
380}
381#[cfg(test)]
382mod tests {
383 use core::array;
384 use std::{cell, vec};
385
386 use super::*;
387
388 #[allow(dead_code)]
389 #[derive(PartialEq, Debug)]
390 enum TestCircularTransferRequest {
391 GetCompleteCount(usize),
392 ResetCompleteCount(usize),
393 PositionRequest(usize),
394 }
395
396 struct TestCircularTransfer {
397 len: usize,
398 requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>,
399 }
400
401 impl DmaCtrl for TestCircularTransfer {
402 fn get_remaining_transfers(&self) -> usize {
403 match self.requests.borrow_mut().pop().unwrap() {
404 TestCircularTransferRequest::PositionRequest(pos) => {
405 let len = self.len;
406
407 assert!(len >= pos);
408
409 len - pos
410 }
411 _ => unreachable!(),
412 }
413 }
414
415 fn get_complete_count(&self) -> usize {
416 match self.requests.borrow_mut().pop().unwrap() {
417 TestCircularTransferRequest::GetCompleteCount(complete_count) => complete_count,
418 _ => unreachable!(),
419 }
420 }
421
422 fn reset_complete_count(&mut self) -> usize {
423 match self.requests.get_mut().pop().unwrap() {
424 TestCircularTransferRequest::ResetCompleteCount(complete_count) => complete_count,
425 _ => unreachable!(),
426 }
427 }
428
429 fn set_waker(&mut self, waker: &Waker) {}
430 }
431
432 impl TestCircularTransfer {
433 pub fn new(len: usize) -> Self {
434 Self {
435 requests: cell::RefCell::new(vec![]),
436 len,
437 }
438 }
439
440 pub fn setup(&self, mut requests: vec::Vec<TestCircularTransferRequest>) {
441 requests.reverse();
442 self.requests.replace(requests);
443 }
444 }
445
446 #[test]
447 fn empty_and_read_not_started() {
448 let mut dma_buf = [0u8; 16];
449 let ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
450
451 assert_eq!(0, ringbuf.start);
452 }
453
454 #[test]
455 fn can_read() {
456 let mut dma = TestCircularTransfer::new(16);
457
458 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
459 let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
460
461 assert_eq!(0, ringbuf.start);
462 assert_eq!(16, ringbuf.cap());
463
464 dma.setup(vec![
465 TestCircularTransferRequest::PositionRequest(8),
466 TestCircularTransferRequest::PositionRequest(10),
467 TestCircularTransferRequest::GetCompleteCount(0),
468 ]);
469 let mut buf = [0; 2];
470 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
471 assert_eq!([0, 1], buf);
472 assert_eq!(2, ringbuf.start);
473
474 dma.setup(vec![
475 TestCircularTransferRequest::PositionRequest(10),
476 TestCircularTransferRequest::PositionRequest(12),
477 TestCircularTransferRequest::GetCompleteCount(0),
478 ]);
479 let mut buf = [0; 2];
480 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
481 assert_eq!([2, 3], buf);
482 assert_eq!(4, ringbuf.start);
483
484 dma.setup(vec![
485 TestCircularTransferRequest::PositionRequest(12),
486 TestCircularTransferRequest::PositionRequest(14),
487 TestCircularTransferRequest::GetCompleteCount(0),
488 ]);
489 let mut buf = [0; 8];
490 assert_eq!(8, ringbuf.read(&mut dma, &mut buf).unwrap().0);
491 assert_eq!([4, 5, 6, 7, 8, 9], buf[..6]);
492 assert_eq!(12, ringbuf.start);
493 }
494
495 #[test]
496 fn can_read_with_wrap() {
497 let mut dma = TestCircularTransfer::new(16);
498
499 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
500 let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
501
502 assert_eq!(0, ringbuf.start);
503 assert_eq!(16, ringbuf.cap());
504
505 /*
506 Read to close to the end of the buffer
507 */
508 dma.setup(vec![
509 TestCircularTransferRequest::PositionRequest(14),
510 TestCircularTransferRequest::PositionRequest(16),
511 TestCircularTransferRequest::GetCompleteCount(0),
512 ]);
513 let mut buf = [0; 14];
514 assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0);
515 assert_eq!(14, ringbuf.start);
516
517 /*
518 Now, read around the buffer
519 */
520 dma.setup(vec![
521 TestCircularTransferRequest::PositionRequest(6),
522 TestCircularTransferRequest::PositionRequest(8),
523 TestCircularTransferRequest::ResetCompleteCount(1),
524 ]);
525 let mut buf = [0; 6];
526 assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0);
527 assert_eq!(4, ringbuf.start);
528 }
529
530 #[test]
531 fn can_read_when_dma_writer_is_wrapped_and_read_does_not_wrap() {
532 let mut dma = TestCircularTransfer::new(16);
533
534 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
535 let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
536
537 assert_eq!(0, ringbuf.start);
538 assert_eq!(16, ringbuf.cap());
539
540 /*
541 Read to close to the end of the buffer
542 */
543 dma.setup(vec![
544 TestCircularTransferRequest::PositionRequest(14),
545 TestCircularTransferRequest::PositionRequest(16),
546 TestCircularTransferRequest::GetCompleteCount(0),
547 ]);
548 let mut buf = [0; 14];
549 assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0);
550 assert_eq!(14, ringbuf.start);
551
552 /*
553 Now, read to the end of the buffer
554 */
555 dma.setup(vec![
556 TestCircularTransferRequest::PositionRequest(6),
557 TestCircularTransferRequest::PositionRequest(8),
558 TestCircularTransferRequest::ResetCompleteCount(1),
559 ]);
560 let mut buf = [0; 2];
561 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
562 assert_eq!(0, ringbuf.start);
563 }
564
565 #[test]
566 fn can_read_when_dma_writer_wraps_once_with_same_ndtr() {
567 let mut dma = TestCircularTransfer::new(16);
568
569 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
570 let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
571
572 assert_eq!(0, ringbuf.start);
573 assert_eq!(16, ringbuf.cap());
574
575 /*
576 Read to about the middle of the buffer
577 */
578 dma.setup(vec![
579 TestCircularTransferRequest::PositionRequest(6),
580 TestCircularTransferRequest::PositionRequest(6),
581 TestCircularTransferRequest::GetCompleteCount(0),
582 ]);
583 let mut buf = [0; 6];
584 assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0);
585 assert_eq!(6, ringbuf.start);
586
587 /*
588 Now, wrap the DMA controller around
589 */
590 dma.setup(vec![
591 TestCircularTransferRequest::PositionRequest(6),
592 TestCircularTransferRequest::GetCompleteCount(1),
593 TestCircularTransferRequest::PositionRequest(6),
594 TestCircularTransferRequest::GetCompleteCount(1),
595 ]);
596 let mut buf = [0; 6];
597 assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0);
598 assert_eq!(12, ringbuf.start);
599 }
600
601 #[test]
602 fn cannot_read_when_dma_writer_overwrites_during_not_wrapping_read() {
603 let mut dma = TestCircularTransfer::new(16);
604
605 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
606 let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
607
608 assert_eq!(0, ringbuf.start);
609 assert_eq!(16, ringbuf.cap());
610
611 /*
612 Read a few bytes
613 */
614 dma.setup(vec![
615 TestCircularTransferRequest::PositionRequest(2),
616 TestCircularTransferRequest::PositionRequest(2),
617 TestCircularTransferRequest::GetCompleteCount(0),
618 ]);
619 let mut buf = [0; 6];
620 assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0);
621 assert_eq!(2, ringbuf.start);
622
623 /*
624 Now, overtake the reader
625 */
626 dma.setup(vec![
627 TestCircularTransferRequest::PositionRequest(4),
628 TestCircularTransferRequest::PositionRequest(6),
629 TestCircularTransferRequest::GetCompleteCount(1),
630 ]);
631 let mut buf = [0; 6];
632 assert_eq!(OverrunError, ringbuf.read(&mut dma, &mut buf).unwrap_err());
633 }
634
635 #[test]
636 fn cannot_read_when_dma_writer_overwrites_during_wrapping_read() {
637 let mut dma = TestCircularTransfer::new(16);
638
639 let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15
640 let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
641
642 assert_eq!(0, ringbuf.start);
643 assert_eq!(16, ringbuf.cap());
644
645 /*
646 Read to close to the end of the buffer
647 */
648 dma.setup(vec![
649 TestCircularTransferRequest::PositionRequest(14),
650 TestCircularTransferRequest::PositionRequest(16),
651 TestCircularTransferRequest::GetCompleteCount(0),
652 ]);
653 let mut buf = [0; 14];
654 assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0);
655 assert_eq!(14, ringbuf.start);
656
657 /*
658 Now, overtake the reader
659 */
660 dma.setup(vec![
661 TestCircularTransferRequest::PositionRequest(8),
662 TestCircularTransferRequest::PositionRequest(10),
663 TestCircularTransferRequest::ResetCompleteCount(2),
664 ]);
665 let mut buf = [0; 6];
666 assert_eq!(OverrunError, ringbuf.read(&mut dma, &mut buf).unwrap_err());
667 }
668}
diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs
new file mode 100644
index 000000000..44ea497fe
--- /dev/null
+++ b/embassy-stm32/src/dma/ringbuffer/mod.rs
@@ -0,0 +1,333 @@
1#![cfg_attr(gpdma, allow(unused))]
2
3use core::future::poll_fn;
4use core::task::{Poll, Waker};
5
6use crate::dma::word::Word;
7
8pub trait DmaCtrl {
9 /// Get the NDTR register value, i.e. the space left in the underlying
10 /// buffer until the dma writer wraps.
11 fn get_remaining_transfers(&self) -> usize;
12
13 /// Reset the transfer completed counter to 0 and return the value just prior to the reset.
14 fn reset_complete_count(&mut self) -> usize;
15
16 /// Set the waker for a running poll_fn
17 fn set_waker(&mut self, waker: &Waker);
18}
19
20#[derive(Debug, PartialEq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub enum Error {
23 Overrun,
24 /// the newly read DMA positions don't make sense compared to the previous
25 /// ones. This can usually only occur due to wrong Driver implementation, if
26 /// the driver author (or the user using raw metapac code) directly resets
27 /// the channel for instance.
28 DmaUnsynced,
29}
30
31#[derive(Debug, Clone, Copy, Default)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33struct DmaIndex {
34 complete_count: usize,
35 pos: usize,
36}
37
38impl DmaIndex {
39 fn reset(&mut self) {
40 self.pos = 0;
41 self.complete_count = 0;
42 }
43
44 fn as_index(&self, cap: usize, offset: usize) -> usize {
45 (self.pos + offset) % cap
46 }
47
48 fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) {
49 // Important!
50 // The ordering of the first two lines matters!
51 // If changed, the code will detect a wrong +capacity
52 // jump at wrap-around.
53 let count_diff = dma.reset_complete_count();
54 let pos = cap - dma.get_remaining_transfers();
55 self.pos = if pos < self.pos && count_diff == 0 {
56 cap - 1
57 } else {
58 pos
59 };
60
61 self.complete_count += count_diff;
62 }
63
64 fn advance(&mut self, cap: usize, steps: usize) {
65 let next = self.pos + steps;
66 self.complete_count += next / cap;
67 self.pos = next % cap;
68 }
69
70 fn normalize(lhs: &mut DmaIndex, rhs: &mut DmaIndex) {
71 let min_count = lhs.complete_count.min(rhs.complete_count);
72 lhs.complete_count -= min_count;
73 rhs.complete_count -= min_count;
74 }
75
76 fn diff(&self, cap: usize, rhs: &DmaIndex) -> isize {
77 (self.complete_count * cap + self.pos) as isize - (rhs.complete_count * cap + rhs.pos) as isize
78 }
79}
80
81pub struct ReadableDmaRingBuffer<'a, W: Word> {
82 dma_buf: &'a mut [W],
83 write_index: DmaIndex,
84 read_index: DmaIndex,
85}
86
87impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
88 /// Construct an empty buffer.
89 pub fn new(dma_buf: &'a mut [W]) -> Self {
90 Self {
91 dma_buf,
92 write_index: Default::default(),
93 read_index: Default::default(),
94 }
95 }
96
97 /// Reset the ring buffer to its initial state.
98 pub fn reset(&mut self, dma: &mut impl DmaCtrl) {
99 dma.reset_complete_count();
100 self.write_index.reset();
101 self.write_index.dma_sync(self.cap(), dma);
102 self.read_index = self.write_index;
103 }
104
105 /// Get the full ringbuffer capacity.
106 pub const fn cap(&self) -> usize {
107 self.dma_buf.len()
108 }
109
110 /// Get the available readable dma samples.
111 pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result<usize, Error> {
112 self.write_index.dma_sync(self.cap(), dma);
113 DmaIndex::normalize(&mut self.write_index, &mut self.read_index);
114
115 let diff = self.write_index.diff(self.cap(), &self.read_index);
116
117 if diff < 0 {
118 Err(Error::DmaUnsynced)
119 } else if diff > self.cap() as isize {
120 Err(Error::Overrun)
121 } else {
122 Ok(diff as usize)
123 }
124 }
125
126 /// Read elements from the ring buffer.
127 ///
128 /// Return a tuple of the length read and the length remaining in the buffer
129 /// If not all of the elements were read, then there will be some elements in the buffer remaining
130 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
131 /// Error is returned if the portion to be read was overwritten by the DMA controller,
132 /// in which case the rinbuffer will automatically reset itself.
133 pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), Error> {
134 self.read_raw(dma, buf).inspect_err(|_e| {
135 self.reset(dma);
136 })
137 }
138
139 /// Read an exact number of elements from the ringbuffer.
140 ///
141 /// Returns the remaining number of elements available for immediate reading.
142 /// Error is returned if the portion to be read was overwritten by the DMA controller.
143 ///
144 /// Async/Wake Behavior:
145 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
146 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
147 /// ring buffer was created with a buffer of size 'N':
148 /// - 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.
149 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
150 pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result<usize, Error> {
151 let mut read_data = 0;
152 let buffer_len = buffer.len();
153
154 poll_fn(|cx| {
155 dma.set_waker(cx.waker());
156
157 match self.read(dma, &mut buffer[read_data..buffer_len]) {
158 Ok((len, remaining)) => {
159 read_data += len;
160 if read_data == buffer_len {
161 Poll::Ready(Ok(remaining))
162 } else {
163 Poll::Pending
164 }
165 }
166 Err(e) => Poll::Ready(Err(e)),
167 }
168 })
169 .await
170 }
171
172 fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), Error> {
173 let readable = self.len(dma)?.min(buf.len());
174 for i in 0..readable {
175 buf[i] = self.read_buf(i);
176 }
177 let available = self.len(dma)?;
178 self.read_index.advance(self.cap(), readable);
179 Ok((readable, available - readable))
180 }
181
182 fn read_buf(&self, offset: usize) -> W {
183 unsafe {
184 core::ptr::read_volatile(
185 self.dma_buf
186 .as_ptr()
187 .offset(self.read_index.as_index(self.cap(), offset) as isize),
188 )
189 }
190 }
191}
192
193pub struct WritableDmaRingBuffer<'a, W: Word> {
194 dma_buf: &'a mut [W],
195 read_index: DmaIndex,
196 write_index: DmaIndex,
197}
198
199impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
200 /// Construct a ringbuffer filled with the given buffer data.
201 pub fn new(dma_buf: &'a mut [W]) -> Self {
202 let len = dma_buf.len();
203 Self {
204 dma_buf,
205 read_index: Default::default(),
206 write_index: DmaIndex {
207 complete_count: 0,
208 pos: len,
209 },
210 }
211 }
212
213 /// Reset the ring buffer to its initial state. The buffer after the reset will be full.
214 pub fn reset(&mut self, dma: &mut impl DmaCtrl) {
215 dma.reset_complete_count();
216 self.read_index.reset();
217 self.read_index.dma_sync(self.cap(), dma);
218 self.write_index = self.read_index;
219 self.write_index.advance(self.cap(), self.cap());
220 }
221
222 /// Get the remaining writable dma samples.
223 pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result<usize, Error> {
224 self.read_index.dma_sync(self.cap(), dma);
225 DmaIndex::normalize(&mut self.read_index, &mut self.write_index);
226
227 let diff = self.write_index.diff(self.cap(), &self.read_index);
228
229 if diff < 0 {
230 Err(Error::Overrun)
231 } else if diff > self.cap() as isize {
232 Err(Error::DmaUnsynced)
233 } else {
234 Ok(self.cap().saturating_sub(diff as usize))
235 }
236 }
237
238 /// Get the full ringbuffer capacity.
239 pub const fn cap(&self) -> usize {
240 self.dma_buf.len()
241 }
242
243 /// Append data to the ring buffer.
244 /// Returns a tuple of the data written and the remaining write capacity in the buffer.
245 /// Error is returned if the portion to be written was previously read by the DMA controller.
246 /// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of
247 /// leeway between the write index and the DMA.
248 pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), Error> {
249 self.write_raw(dma, buf).inspect_err(|_e| {
250 self.reset(dma);
251 })
252 }
253
254 /// Write elements directly to the buffer.
255 ///
256 /// Subsequent writes will overwrite the content of the buffer, so it is not useful to call this more than once.
257 /// Data is aligned towards the end of the buffer.
258 ///
259 /// In case of success, returns the written length, and the empty space in front of the written block.
260 /// Fails if the data to write exceeds the buffer capacity.
261 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
262 if buf.len() > self.cap() {
263 return Err(Error::Overrun);
264 }
265
266 let start = self.cap() - buf.len();
267 for (i, data) in buf.iter().enumerate() {
268 self.write_buf(start + i, *data)
269 }
270 let written = buf.len().min(self.cap());
271 Ok((written, self.cap() - written))
272 }
273
274 /// Wait for any ring buffer write error.
275 pub async fn wait_write_error(&mut self, dma: &mut impl DmaCtrl) -> Result<usize, Error> {
276 poll_fn(|cx| {
277 dma.set_waker(cx.waker());
278
279 match self.len(dma) {
280 Ok(_) => Poll::Pending,
281 Err(e) => Poll::Ready(Err(e)),
282 }
283 })
284 .await
285 }
286
287 /// Write an exact number of elements to the ringbuffer.
288 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, Error> {
289 let mut written_data = 0;
290 let buffer_len = buffer.len();
291
292 poll_fn(|cx| {
293 dma.set_waker(cx.waker());
294
295 match self.write(dma, &buffer[written_data..buffer_len]) {
296 Ok((len, remaining)) => {
297 written_data += len;
298 if written_data == buffer_len {
299 Poll::Ready(Ok(remaining))
300 } else {
301 Poll::Pending
302 }
303 }
304 Err(e) => Poll::Ready(Err(e)),
305 }
306 })
307 .await
308 }
309
310 fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), Error> {
311 let writable = self.len(dma)?.min(buf.len());
312 for i in 0..writable {
313 self.write_buf(i, buf[i]);
314 }
315 let available = self.len(dma)?;
316 self.write_index.advance(self.cap(), writable);
317 Ok((writable, available - writable))
318 }
319
320 fn write_buf(&mut self, offset: usize, value: W) {
321 unsafe {
322 core::ptr::write_volatile(
323 self.dma_buf
324 .as_mut_ptr()
325 .offset(self.write_index.as_index(self.cap(), offset) as isize),
326 value,
327 )
328 }
329 }
330}
331
332#[cfg(test)]
333mod tests;
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs
new file mode 100644
index 000000000..6fabedb83
--- /dev/null
+++ b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs
@@ -0,0 +1,90 @@
1use std::{cell, vec};
2
3use super::*;
4
5#[allow(unused)]
6#[derive(PartialEq, Debug)]
7enum TestCircularTransferRequest {
8 ResetCompleteCount(usize),
9 PositionRequest(usize),
10}
11
12#[allow(unused)]
13struct TestCircularTransfer {
14 len: usize,
15 requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>,
16}
17
18impl DmaCtrl for TestCircularTransfer {
19 fn get_remaining_transfers(&self) -> usize {
20 match self.requests.borrow_mut().pop().unwrap() {
21 TestCircularTransferRequest::PositionRequest(pos) => {
22 let len = self.len;
23
24 assert!(len >= pos);
25
26 len - pos
27 }
28 _ => unreachable!(),
29 }
30 }
31
32 fn reset_complete_count(&mut self) -> usize {
33 match self.requests.get_mut().pop().unwrap() {
34 TestCircularTransferRequest::ResetCompleteCount(complete_count) => complete_count,
35 _ => unreachable!(),
36 }
37 }
38
39 fn set_waker(&mut self, _waker: &Waker) {}
40}
41
42impl TestCircularTransfer {
43 #[allow(unused)]
44 pub fn new(len: usize) -> Self {
45 Self {
46 requests: cell::RefCell::new(vec![]),
47 len,
48 }
49 }
50
51 #[allow(unused)]
52 pub fn setup(&self, mut requests: vec::Vec<TestCircularTransferRequest>) {
53 requests.reverse();
54 self.requests.replace(requests);
55 }
56}
57
58const CAP: usize = 16;
59
60#[test]
61fn dma_index_as_index_returns_index_mod_cap_by_default() {
62 let index = DmaIndex::default();
63 assert_eq!(index.as_index(CAP, 0), 0);
64 assert_eq!(index.as_index(CAP, 1), 1);
65 assert_eq!(index.as_index(CAP, 2), 2);
66 assert_eq!(index.as_index(CAP, 3), 3);
67 assert_eq!(index.as_index(CAP, 4), 4);
68 assert_eq!(index.as_index(CAP, CAP), 0);
69 assert_eq!(index.as_index(CAP, CAP + 1), 1);
70}
71
72#[test]
73fn dma_index_advancing_increases_as_index() {
74 let mut index = DmaIndex::default();
75 assert_eq!(index.as_index(CAP, 0), 0);
76 index.advance(CAP, 1);
77 assert_eq!(index.as_index(CAP, 0), 1);
78 index.advance(CAP, 1);
79 assert_eq!(index.as_index(CAP, 0), 2);
80 index.advance(CAP, 1);
81 assert_eq!(index.as_index(CAP, 0), 3);
82 index.advance(CAP, 1);
83 assert_eq!(index.as_index(CAP, 0), 4);
84 index.advance(CAP, CAP - 4);
85 assert_eq!(index.as_index(CAP, 0), 0);
86 index.advance(CAP, 1);
87 assert_eq!(index.as_index(CAP, 0), 1);
88}
89
90mod prop_test;
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
new file mode 100644
index 000000000..661fb1728
--- /dev/null
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
@@ -0,0 +1,50 @@
1use std::task::Waker;
2
3use proptest::prop_oneof;
4use proptest::strategy::{self, BoxedStrategy, Strategy as _};
5use proptest_state_machine::{prop_state_machine, ReferenceStateMachine, StateMachineTest};
6
7use super::*;
8
9const CAP: usize = 128;
10
11#[derive(Debug, Default)]
12struct DmaMock {
13 pos: usize,
14 wraps: usize,
15}
16
17impl DmaMock {
18 pub fn advance(&mut self, steps: usize) {
19 let next = self.pos + steps;
20 self.pos = next % CAP;
21 self.wraps += next / CAP;
22 }
23}
24
25impl DmaCtrl for DmaMock {
26 fn get_remaining_transfers(&self) -> usize {
27 CAP - self.pos
28 }
29
30 fn reset_complete_count(&mut self) -> usize {
31 core::mem::replace(&mut self.wraps, 0)
32 }
33
34 fn set_waker(&mut self, _waker: &Waker) {}
35}
36
37#[derive(Debug, Clone)]
38enum Status {
39 Available(usize),
40 Failed,
41}
42
43impl Status {
44 pub fn new(capacity: usize) -> Self {
45 Self::Available(capacity)
46 }
47}
48
49mod reader;
50mod writer;
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs
new file mode 100644
index 000000000..4f3957a68
--- /dev/null
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs
@@ -0,0 +1,123 @@
1use core::fmt::Debug;
2
3use super::*;
4
5#[derive(Debug, Clone)]
6enum ReaderTransition {
7 Write(usize),
8 Reset,
9 ReadUpTo(usize),
10}
11
12struct ReaderSM;
13
14impl ReferenceStateMachine for ReaderSM {
15 type State = Status;
16 type Transition = ReaderTransition;
17
18 fn init_state() -> BoxedStrategy<Self::State> {
19 strategy::Just(Status::new(0)).boxed()
20 }
21
22 fn transitions(_state: &Self::State) -> BoxedStrategy<Self::Transition> {
23 prop_oneof![
24 (1..50_usize).prop_map(ReaderTransition::Write),
25 (1..50_usize).prop_map(ReaderTransition::ReadUpTo),
26 strategy::Just(ReaderTransition::Reset),
27 ]
28 .boxed()
29 }
30
31 fn apply(status: Self::State, transition: &Self::Transition) -> Self::State {
32 match (status, transition) {
33 (_, ReaderTransition::Reset) => Status::Available(0),
34 (Status::Available(x), ReaderTransition::Write(y)) => {
35 if x + y > CAP {
36 Status::Failed
37 } else {
38 Status::Available(x + y)
39 }
40 }
41 (Status::Failed, ReaderTransition::Write(_)) => Status::Failed,
42 (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)),
43 (Status::Failed, ReaderTransition::ReadUpTo(_)) => Status::Available(0),
44 }
45 }
46}
47
48struct ReaderSut {
49 status: Status,
50 buffer: *mut [u8],
51 producer: DmaMock,
52 consumer: ReadableDmaRingBuffer<'static, u8>,
53}
54
55impl Debug for ReaderSut {
56 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
57 <DmaMock as Debug>::fmt(&self.producer, f)
58 }
59}
60
61struct ReaderTest;
62
63impl StateMachineTest for ReaderTest {
64 type SystemUnderTest = ReaderSut;
65 type Reference = ReaderSM;
66
67 fn init_test(ref_status: &<Self::Reference as ReferenceStateMachine>::State) -> Self::SystemUnderTest {
68 let buffer = Box::into_raw(Box::new([0; CAP]));
69 ReaderSut {
70 status: ref_status.clone(),
71 buffer,
72 producer: DmaMock::default(),
73 consumer: ReadableDmaRingBuffer::new(unsafe { &mut *buffer }),
74 }
75 }
76
77 fn teardown(state: Self::SystemUnderTest) {
78 unsafe {
79 let _ = Box::from_raw(state.buffer);
80 };
81 }
82
83 fn apply(
84 mut sut: Self::SystemUnderTest,
85 ref_state: &<Self::Reference as ReferenceStateMachine>::State,
86 transition: <Self::Reference as ReferenceStateMachine>::Transition,
87 ) -> Self::SystemUnderTest {
88 match transition {
89 ReaderTransition::Write(x) => sut.producer.advance(x),
90 ReaderTransition::Reset => {
91 sut.consumer.reset(&mut sut.producer);
92 }
93 ReaderTransition::ReadUpTo(x) => {
94 let status = sut.status;
95 let ReaderSut {
96 ref mut producer,
97 ref mut consumer,
98 ..
99 } = sut;
100 let mut buf = vec![0; x];
101 let res = consumer.read(producer, &mut buf);
102 match status {
103 Status::Available(n) => {
104 let readable = x.min(n);
105
106 assert_eq!(res.unwrap().0, readable);
107 }
108 Status::Failed => assert!(res.is_err()),
109 }
110 }
111 }
112
113 ReaderSut {
114 status: ref_state.clone(),
115 ..sut
116 }
117 }
118}
119
120prop_state_machine! {
121 #[test]
122 fn reader_state_test(sequential 1..20 => ReaderTest);
123}
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs
new file mode 100644
index 000000000..15433c0ee
--- /dev/null
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs
@@ -0,0 +1,122 @@
1use core::fmt::Debug;
2
3use super::*;
4
5#[derive(Debug, Clone)]
6enum WriterTransition {
7 Read(usize),
8 WriteUpTo(usize),
9 Reset,
10}
11
12struct WriterSM;
13
14impl ReferenceStateMachine for WriterSM {
15 type State = Status;
16 type Transition = WriterTransition;
17
18 fn init_state() -> BoxedStrategy<Self::State> {
19 strategy::Just(Status::new(CAP)).boxed()
20 }
21
22 fn transitions(_state: &Self::State) -> BoxedStrategy<Self::Transition> {
23 prop_oneof![
24 (1..50_usize).prop_map(WriterTransition::Read),
25 (1..50_usize).prop_map(WriterTransition::WriteUpTo),
26 strategy::Just(WriterTransition::Reset),
27 ]
28 .boxed()
29 }
30
31 fn apply(status: Self::State, transition: &Self::Transition) -> Self::State {
32 match (status, transition) {
33 (_, WriterTransition::Reset) => Status::Available(CAP),
34 (Status::Available(x), WriterTransition::Read(y)) => {
35 if x < *y {
36 Status::Failed
37 } else {
38 Status::Available(x - y)
39 }
40 }
41 (Status::Failed, WriterTransition::Read(_)) => Status::Failed,
42 (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)),
43 (Status::Failed, WriterTransition::WriteUpTo(_)) => Status::Available(CAP),
44 }
45 }
46}
47
48struct WriterSut {
49 status: Status,
50 buffer: *mut [u8],
51 producer: WritableDmaRingBuffer<'static, u8>,
52 consumer: DmaMock,
53}
54
55impl Debug for WriterSut {
56 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
57 <DmaMock as Debug>::fmt(&self.consumer, f)
58 }
59}
60
61struct WriterTest;
62
63impl StateMachineTest for WriterTest {
64 type SystemUnderTest = WriterSut;
65 type Reference = WriterSM;
66
67 fn init_test(ref_status: &<Self::Reference as ReferenceStateMachine>::State) -> Self::SystemUnderTest {
68 let buffer = Box::into_raw(Box::new([0; CAP]));
69 WriterSut {
70 status: ref_status.clone(),
71 buffer,
72 producer: WritableDmaRingBuffer::new(unsafe { &mut *buffer }),
73 consumer: DmaMock::default(),
74 }
75 }
76
77 fn teardown(state: Self::SystemUnderTest) {
78 unsafe {
79 let _ = Box::from_raw(state.buffer);
80 };
81 }
82
83 fn apply(
84 mut sut: Self::SystemUnderTest,
85 ref_status: &<Self::Reference as ReferenceStateMachine>::State,
86 transition: <Self::Reference as ReferenceStateMachine>::Transition,
87 ) -> Self::SystemUnderTest {
88 match transition {
89 WriterTransition::Read(x) => sut.consumer.advance(x),
90 WriterTransition::Reset => {
91 sut.producer.reset(&mut sut.consumer);
92 }
93 WriterTransition::WriteUpTo(x) => {
94 let status = sut.status;
95 let WriterSut {
96 ref mut producer,
97 ref mut consumer,
98 ..
99 } = sut;
100 let mut buf = vec![0; x];
101 let res = producer.write(consumer, &mut buf);
102 match status {
103 Status::Available(n) => {
104 let writable = x.min(CAP - n.min(CAP));
105 assert_eq!(res.unwrap().0, writable);
106 }
107 Status::Failed => assert!(res.is_err()),
108 }
109 }
110 }
111
112 WriterSut {
113 status: ref_status.clone(),
114 ..sut
115 }
116 }
117}
118
119prop_state_machine! {
120 #[test]
121 fn writer_state_test(sequential 1..20 => WriterTest);
122}
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
index 5aaca57c9..8bf89e2fe 100644
--- a/embassy-stm32/src/dma/util.rs
+++ b/embassy-stm32/src/dma/util.rs
@@ -1,13 +1,12 @@
1use embassy_hal_internal::PeripheralRef;
2
3use super::word::Word; 1use super::word::Word;
4use super::{AnyChannel, Request, Transfer, TransferOptions}; 2use super::{AnyChannel, Request, Transfer, TransferOptions};
3use crate::Peri;
5 4
6/// Convenience wrapper, contains a channel and a request number. 5/// Convenience wrapper, contains a channel and a request number.
7/// 6///
8/// Commonly used in peripheral drivers that own DMA channels. 7/// Commonly used in peripheral drivers that own DMA channels.
9pub(crate) struct ChannelAndRequest<'d> { 8pub(crate) struct ChannelAndRequest<'d> {
10 pub channel: PeripheralRef<'d, AnyChannel>, 9 pub channel: Peri<'d, AnyChannel>,
11 pub request: Request, 10 pub request: Request,
12} 11}
13 12
@@ -18,7 +17,7 @@ impl<'d> ChannelAndRequest<'d> {
18 buf: &'a mut [W], 17 buf: &'a mut [W],
19 options: TransferOptions, 18 options: TransferOptions,
20 ) -> Transfer<'a> { 19 ) -> Transfer<'a> {
21 Transfer::new_read(&mut self.channel, self.request, peri_addr, buf, options) 20 Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options)
22 } 21 }
23 22
24 pub unsafe fn read_raw<'a, W: Word>( 23 pub unsafe fn read_raw<'a, W: Word>(
@@ -27,7 +26,7 @@ impl<'d> ChannelAndRequest<'d> {
27 buf: *mut [W], 26 buf: *mut [W],
28 options: TransferOptions, 27 options: TransferOptions,
29 ) -> Transfer<'a> { 28 ) -> Transfer<'a> {
30 Transfer::new_read_raw(&mut self.channel, self.request, peri_addr, buf, options) 29 Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options)
31 } 30 }
32 31
33 pub unsafe fn write<'a, W: Word>( 32 pub unsafe fn write<'a, W: Word>(
@@ -36,16 +35,16 @@ impl<'d> ChannelAndRequest<'d> {
36 peri_addr: *mut W, 35 peri_addr: *mut W,
37 options: TransferOptions, 36 options: TransferOptions,
38 ) -> Transfer<'a> { 37 ) -> Transfer<'a> {
39 Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options) 38 Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options)
40 } 39 }
41 40
42 pub unsafe fn write_raw<'a, W: Word>( 41 pub unsafe fn write_raw<'a, MW: Word, PW: Word>(
43 &'a mut self, 42 &'a mut self,
44 buf: *const [W], 43 buf: *const [MW],
45 peri_addr: *mut W, 44 peri_addr: *mut PW,
46 options: TransferOptions, 45 options: TransferOptions,
47 ) -> Transfer<'a> { 46 ) -> Transfer<'a> {
48 Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options) 47 Transfer::new_write_raw(self.channel.reborrow(), self.request, buf, peri_addr, options)
49 } 48 }
50 49
51 #[allow(dead_code)] 50 #[allow(dead_code)]
@@ -56,6 +55,13 @@ impl<'d> ChannelAndRequest<'d> {
56 peri_addr: *mut W, 55 peri_addr: *mut W,
57 options: TransferOptions, 56 options: TransferOptions,
58 ) -> Transfer<'a> { 57 ) -> Transfer<'a> {
59 Transfer::new_write_repeated(&mut self.channel, self.request, repeated, count, peri_addr, options) 58 Transfer::new_write_repeated(
59 self.channel.reborrow(),
60 self.request,
61 repeated,
62 count,
63 peri_addr,
64 options,
65 )
60 } 66 }
61} 67}
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index 77c3d95c3..e97ccd9d0 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -2,12 +2,12 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::PeripheralType;
6 6
7//use crate::gpio::{AnyPin, SealedPin}; 7//use crate::gpio::{AnyPin, SealedPin};
8use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9use crate::rcc::{self, RccPeripheral}; 9use crate::rcc::{self, RccPeripheral};
10use crate::{peripherals, Peripheral}; 10use crate::{peripherals, Peri};
11 11
12/// Performs a busy-wait delay for a specified number of microseconds. 12/// Performs a busy-wait delay for a specified number of microseconds.
13pub fn blocking_delay_ms(ms: u32) { 13pub fn blocking_delay_ms(ms: u32) {
@@ -69,14 +69,12 @@ impl From<PacketType> for u8 {
69/// DSIHOST driver. 69/// DSIHOST driver.
70pub struct DsiHost<'d, T: Instance> { 70pub struct DsiHost<'d, T: Instance> {
71 _peri: PhantomData<&'d mut T>, 71 _peri: PhantomData<&'d mut T>,
72 _te: PeripheralRef<'d, AnyPin>, 72 _te: Peri<'d, AnyPin>,
73} 73}
74 74
75impl<'d, T: Instance> DsiHost<'d, T> { 75impl<'d, T: Instance> DsiHost<'d, T> {
76 /// Note: Full-Duplex modes are not supported at this time 76 /// Note: Full-Duplex modes are not supported at this time
77 pub fn new(_peri: impl Peripheral<P = T> + 'd, te: impl Peripheral<P = impl TePin<T>> + 'd) -> Self { 77 pub fn new(_peri: Peri<'d, T>, te: Peri<'d, impl TePin<T>>) -> Self {
78 into_ref!(te);
79
80 rcc::enable_and_reset::<T>(); 78 rcc::enable_and_reset::<T>();
81 79
82 // Set Tearing Enable pin according to CubeMx example 80 // Set Tearing Enable pin according to CubeMx example
@@ -88,7 +86,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
88 */ 86 */
89 Self { 87 Self {
90 _peri: PhantomData, 88 _peri: PhantomData,
91 _te: te.map_into(), 89 _te: te.into(),
92 } 90 }
93 } 91 }
94 92
@@ -412,7 +410,7 @@ trait SealedInstance: crate::rcc::SealedRccPeripheral {
412 410
413/// DSI instance trait. 411/// DSI instance trait.
414#[allow(private_bounds)] 412#[allow(private_bounds)]
415pub trait Instance: SealedInstance + RccPeripheral + 'static {} 413pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {}
416 414
417pin_trait!(TePin, Instance); 415pin_trait!(TePin, Instance);
418 416
diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs
new file mode 100644
index 000000000..1f39c8db5
--- /dev/null
+++ b/embassy-stm32/src/dts/mod.rs
@@ -0,0 +1,238 @@
1//! Digital Temperature Sensor (DTS)
2
3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll;
6
7use embassy_hal_internal::Peri;
8use embassy_sync::waitqueue::AtomicWaker;
9
10use crate::interrupt::InterruptExt;
11use crate::peripherals::DTS;
12use crate::time::Hertz;
13use crate::{interrupt, pac, rcc};
14
15mod tsel;
16pub use tsel::TriggerSel;
17
18#[allow(missing_docs)]
19#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub enum SampleTime {
22 ClockCycles1 = 1,
23 ClockCycles2 = 2,
24 ClockCycles3 = 3,
25 ClockCycles4 = 4,
26 ClockCycles5 = 5,
27 ClockCycles6 = 6,
28 ClockCycles7 = 7,
29 ClockCycles8 = 8,
30 ClockCycles9 = 9,
31 ClockCycles10 = 10,
32 ClockCycles11 = 11,
33 ClockCycles12 = 12,
34 ClockCycles13 = 13,
35 ClockCycles14 = 14,
36 ClockCycles15 = 15,
37}
38
39#[non_exhaustive]
40#[derive(Clone, Copy, PartialEq, Eq, Debug)]
41/// Config
42pub struct Config {
43 /// Sample time
44 pub sample_time: SampleTime,
45 /// Trigger selection
46 pub trigger: TriggerSel,
47}
48
49impl Default for Config {
50 fn default() -> Self {
51 Self {
52 sample_time: SampleTime::ClockCycles1,
53 trigger: TriggerSel::Software,
54 }
55 }
56}
57
58/// The read-only factory calibration values used for converting a
59/// measurement to a temperature.
60#[derive(Clone, Debug)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62pub struct FactoryCalibration {
63 /// The calibration temperature in degrees Celsius.
64 pub t0: u8,
65 /// The frequency at the calibration temperature.
66 pub fmt0: Hertz,
67 /// The ramp coefficient in Hertz per degree Celsius.
68 pub ramp_coeff: u16,
69}
70
71const MAX_DTS_CLK_FREQ: Hertz = Hertz::mhz(1);
72
73/// Digital temperature sensor driver.
74pub struct Dts<'d> {
75 _peri: Peri<'d, DTS>,
76}
77
78static WAKER: AtomicWaker = AtomicWaker::new();
79
80impl<'d> Dts<'d> {
81 /// Create a new temperature sensor driver.
82 pub fn new(
83 _peri: Peri<'d, DTS>,
84 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::DTS, InterruptHandler> + 'd,
85 config: Config,
86 ) -> Self {
87 rcc::enable_and_reset::<DTS>();
88
89 let prescaler = rcc::frequency::<DTS>() / MAX_DTS_CLK_FREQ;
90
91 if prescaler > 127 {
92 panic!("DTS PCLK frequency must be less than 127 MHz.");
93 }
94
95 Self::regs().cfgr1().modify(|w| {
96 w.set_refclk_sel(false);
97 w.set_hsref_clk_div(prescaler as u8);
98 w.set_q_meas_opt(false);
99 // Software trigger
100 w.set_intrig_sel(0);
101 w.set_smp_time(config.sample_time as u8);
102 w.set_intrig_sel(config.trigger as u8);
103 w.set_start(true);
104 w.set_en(true);
105 });
106
107 interrupt::DTS.unpend();
108 unsafe { interrupt::DTS.enable() };
109
110 Self { _peri }
111 }
112
113 /// Reconfigure the driver.
114 pub fn set_config(&mut self, config: &Config) {
115 Self::regs().cfgr1().modify(|w| {
116 w.set_smp_time(config.sample_time as u8);
117 w.set_intrig_sel(config.trigger as u8);
118 });
119 }
120
121 /// Get the read-only factory calibration values used for converting a
122 /// measurement to a temperature.
123 pub fn factory_calibration() -> FactoryCalibration {
124 let t0valr1 = Self::regs().t0valr1().read();
125 let t0 = match t0valr1.t0() {
126 0 => 30,
127 1 => 130,
128 _ => unimplemented!(),
129 };
130 let fmt0 = Hertz::hz(t0valr1.fmt0() as u32 * 100);
131
132 let ramp_coeff = Self::regs().rampvalr().read().ramp_coeff();
133
134 FactoryCalibration { t0, fmt0, ramp_coeff }
135 }
136
137 /// Perform an asynchronous temperature measurement. The returned future can
138 /// be awaited to obtain the measurement.
139 ///
140 /// The future returned waits for the next measurement to complete.
141 ///
142 /// # Example
143 ///
144 /// ```no_run
145 /// use embassy_stm32::{bind_interrupts, dts};
146 /// use embassy_stm32::dts::Dts;
147 ///
148 /// bind_interrupts!(struct Irqs {
149 /// DTS => temp::InterruptHandler;
150 /// });
151 ///
152 /// # async {
153 /// # let p: embassy_stm32::Peripherals = todo!();
154 /// let mut dts = Dts::new(p.DTS, Irqs, Default::default());
155 /// let v: u16 = dts.read().await;
156 /// # };
157 /// ```
158 pub async fn read(&mut self) -> u16 {
159 let r = Self::regs();
160
161 r.itenr().modify(|w| w.set_iteen(true));
162
163 poll_fn(|cx| {
164 WAKER.register(cx.waker());
165 if r.itenr().read().iteen() {
166 Poll::Pending
167 } else {
168 Poll::Ready(r.dr().read().mfreq())
169 }
170 })
171 .await
172 }
173
174 /// Returns the last measurement made, if any.
175 ///
176 /// There is no guarantee that the measurement is recent or that a
177 /// measurement has ever completed.
178 pub fn read_immediate(&mut self) -> u16 {
179 Self::regs().dr().read().mfreq()
180 }
181
182 fn regs() -> pac::dts::Dts {
183 pac::DTS
184 }
185}
186
187impl<'d> Drop for Dts<'d> {
188 fn drop(&mut self) {
189 Self::regs().cfgr1().modify(|w| w.set_en(false));
190 rcc::disable::<DTS>();
191 }
192}
193
194/// Interrupt handler.
195pub struct InterruptHandler {
196 _private: (),
197}
198
199impl interrupt::typelevel::Handler<interrupt::typelevel::DTS> for InterruptHandler {
200 unsafe fn on_interrupt() {
201 let r = pac::DTS;
202 let (sr, itenr) = (r.sr().read(), r.itenr().read());
203
204 if (itenr.iteen() && sr.itef()) || (itenr.aiteen() && sr.aitef()) {
205 r.itenr().modify(|w| {
206 w.set_iteen(false);
207 w.set_aiteen(false);
208 });
209 r.icifr().modify(|w| {
210 w.set_citef(true);
211 w.set_caitef(true);
212 });
213 } else if (itenr.itlen() && sr.itlf()) || (itenr.aitlen() && sr.aitlf()) {
214 r.itenr().modify(|w| {
215 w.set_itlen(false);
216 w.set_aitlen(false);
217 });
218 r.icifr().modify(|w| {
219 w.set_citlf(true);
220 w.set_caitlf(true);
221 });
222 } else if (itenr.ithen() && sr.ithf()) || (itenr.aithen() && sr.aithf()) {
223 r.itenr().modify(|w| {
224 w.set_ithen(false);
225 w.set_aithen(false);
226 });
227 r.icifr().modify(|w| {
228 w.set_cithf(true);
229 w.set_caithf(true);
230 });
231 } else {
232 return;
233 }
234
235 compiler_fence(Ordering::SeqCst);
236 WAKER.wake();
237 }
238}
diff --git a/embassy-stm32/src/dts/tsel.rs b/embassy-stm32/src/dts/tsel.rs
new file mode 100644
index 000000000..99eab6dd8
--- /dev/null
+++ b/embassy-stm32/src/dts/tsel.rs
@@ -0,0 +1,51 @@
1/// Trigger selection for H5
2#[cfg(stm32h5)]
3#[derive(Debug, Copy, Clone, Eq, PartialEq)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5pub enum TriggerSel {
6 /// Software triggering. Performs continuous measurements.
7 Software = 0,
8 /// LPTIM1 CH1
9 Lptim1 = 1,
10 /// LPTIM2 CH1
11 Lptim2 = 2,
12 /// LPTIM3 CH1
13 #[cfg(not(stm32h503))]
14 Lptim3 = 3,
15 /// EXTI13
16 Exti13 = 4,
17}
18
19/// Trigger selection for H7, except for H7R and H7S
20#[cfg(stm32h7)]
21#[derive(Debug, Copy, Clone, Eq, PartialEq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23pub enum TriggerSel {
24 /// Software triggering. Performs continuous measurements.
25 Software = 0,
26 /// LPTIM1 OUT
27 Lptim1 = 1,
28 /// LPTIM2 OUT
29 Lptim2 = 2,
30 /// LPTIM3 OUT
31 Lptim3 = 3,
32 /// EXTI13
33 Exti13 = 4,
34}
35
36/// Trigger selection for H7R and H7S
37#[cfg(stm32h7rs)]
38#[derive(Debug, Copy, Clone, Eq, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum TriggerSel {
41 /// Software triggering. Performs continuous measurements.
42 Software = 0,
43 /// LPTIM4 OUT
44 Lptim4 = 1,
45 /// LPTIM2 CH1
46 Lptim2 = 2,
47 /// LPTIM3 CH1
48 Lptim3 = 3,
49 /// EXTI13
50 Exti13 = 4,
51}
diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_phy.rs
index 3b43051f4..774beef80 100644
--- a/embassy-stm32/src/eth/generic_smi.rs
+++ b/embassy-stm32/src/eth/generic_phy.rs
@@ -7,7 +7,7 @@ use embassy_time::{Duration, Timer};
7#[cfg(feature = "time")] 7#[cfg(feature = "time")]
8use futures_util::FutureExt; 8use futures_util::FutureExt;
9 9
10use super::{StationManagement, PHY}; 10use super::{Phy, StationManagement};
11 11
12#[allow(dead_code)] 12#[allow(dead_code)]
13mod phy_consts { 13mod phy_consts {
@@ -43,25 +43,71 @@ mod phy_consts {
43use self::phy_consts::*; 43use self::phy_consts::*;
44 44
45/// Generic SMI Ethernet PHY implementation 45/// Generic SMI Ethernet PHY implementation
46pub struct GenericSMI { 46pub struct GenericPhy {
47 phy_addr: u8, 47 phy_addr: u8,
48 #[cfg(feature = "time")] 48 #[cfg(feature = "time")]
49 poll_interval: Duration, 49 poll_interval: Duration,
50} 50}
51 51
52impl GenericSMI { 52impl GenericPhy {
53 /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication 53 /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication
54 ///
55 /// # Panics
56 /// `phy_addr` must be in range `0..32`
54 pub fn new(phy_addr: u8) -> Self { 57 pub fn new(phy_addr: u8) -> Self {
58 assert!(phy_addr < 32);
55 Self { 59 Self {
56 phy_addr, 60 phy_addr,
57 #[cfg(feature = "time")] 61 #[cfg(feature = "time")]
58 poll_interval: Duration::from_millis(500), 62 poll_interval: Duration::from_millis(500),
59 } 63 }
60 } 64 }
65
66 /// Construct the PHY. Try to probe all addresses from 0 to 31 during initialization
67 ///
68 /// # Panics
69 /// Initialization panics if PHY didn't respond on any address
70 pub fn new_auto() -> Self {
71 Self {
72 phy_addr: 0xFF,
73 #[cfg(feature = "time")]
74 poll_interval: Duration::from_millis(500),
75 }
76 }
61} 77}
62 78
63unsafe impl PHY for GenericSMI { 79// TODO: Factor out to shared functionality
80fn blocking_delay_us(us: u32) {
81 #[cfg(feature = "time")]
82 embassy_time::block_for(Duration::from_micros(us as u64));
83 #[cfg(not(feature = "time"))]
84 {
85 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
86 let us = us as u64;
87 let cycles = freq * us / 1_000_000;
88 cortex_m::asm::delay(cycles as u32);
89 }
90}
91
92impl Phy for GenericPhy {
64 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) { 93 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
94 // Detect SMI address
95 if self.phy_addr == 0xFF {
96 for addr in 0..32 {
97 sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
98 for _ in 0..10 {
99 if sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET {
100 trace!("Found ETH PHY on address {}", addr);
101 self.phy_addr = addr;
102 return;
103 }
104 // Give PHY a total of 100ms to respond
105 blocking_delay_us(10000);
106 }
107 }
108 panic!("PHY did not respond");
109 }
110
65 sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); 111 sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
66 while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} 112 while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
67 } 113 }
@@ -102,7 +148,7 @@ unsafe impl PHY for GenericSMI {
102} 148}
103 149
104/// Public functions for the PHY 150/// Public functions for the PHY
105impl GenericSMI { 151impl GenericPhy {
106 /// Set the SMI polling interval. 152 /// Set the SMI polling interval.
107 #[cfg(feature = "time")] 153 #[cfg(feature = "time")]
108 pub fn set_poll_interval(&mut self, poll_interval: Duration) { 154 pub fn set_poll_interval(&mut self, poll_interval: Duration) {
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index bfe8a60d6..97d7b4347 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -4,15 +4,17 @@
4#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] 4#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
5#[cfg_attr(eth_v2, path = "v2/mod.rs")] 5#[cfg_attr(eth_v2, path = "v2/mod.rs")]
6mod _version; 6mod _version;
7pub mod generic_smi; 7mod generic_phy;
8 8
9use core::mem::MaybeUninit; 9use core::mem::MaybeUninit;
10use core::task::Context; 10use core::task::Context;
11 11
12use embassy_hal_internal::PeripheralType;
12use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; 13use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
13use embassy_sync::waitqueue::AtomicWaker; 14use embassy_sync::waitqueue::AtomicWaker;
14 15
15pub use self::_version::{InterruptHandler, *}; 16pub use self::_version::{InterruptHandler, *};
17pub use self::generic_phy::*;
16use crate::rcc::RccPeripheral; 18use crate::rcc::RccPeripheral;
17 19
18#[allow(unused)] 20#[allow(unused)]
@@ -42,11 +44,9 @@ pub struct PacketQueue<const TX: usize, const RX: usize> {
42impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { 44impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
43 /// Create a new packet queue. 45 /// Create a new packet queue.
44 pub const fn new() -> Self { 46 pub const fn new() -> Self {
45 const NEW_TDES: TDes = TDes::new();
46 const NEW_RDES: RDes = RDes::new();
47 Self { 47 Self {
48 tx_desc: [NEW_TDES; TX], 48 tx_desc: [const { TDes::new() }; TX],
49 rx_desc: [NEW_RDES; RX], 49 rx_desc: [const { RDes::new() }; RX],
50 tx_buf: [Packet([0; TX_BUFFER_SIZE]); TX], 50 tx_buf: [Packet([0; TX_BUFFER_SIZE]); TX],
51 rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX], 51 rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX],
52 } 52 }
@@ -73,9 +73,15 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
73 73
74static WAKER: AtomicWaker = AtomicWaker::new(); 74static WAKER: AtomicWaker = AtomicWaker::new();
75 75
76impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> { 76impl<'d, T: Instance, P: Phy> embassy_net_driver::Driver for Ethernet<'d, T, P> {
77 type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; 77 type RxToken<'a>
78 type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; 78 = RxToken<'a, 'd>
79 where
80 Self: 'a;
81 type TxToken<'a>
82 = TxToken<'a, 'd>
83 where
84 Self: 'a;
79 85
80 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 86 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
81 WAKER.register(cx.waker()); 87 WAKER.register(cx.waker());
@@ -152,23 +158,15 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
152} 158}
153 159
154/// Station Management Interface (SMI) on an ethernet PHY 160/// Station Management Interface (SMI) on an ethernet PHY
155/// 161pub trait StationManagement {
156/// # Safety
157///
158/// The methods cannot move out of self
159pub unsafe trait StationManagement {
160 /// Read a register over SMI. 162 /// Read a register over SMI.
161 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16; 163 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
162 /// Write a register over SMI. 164 /// Write a register over SMI.
163 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16); 165 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
164} 166}
165 167
166/// Traits for an Ethernet PHY 168/// Trait for an Ethernet PHY
167/// 169pub trait Phy {
168/// # Safety
169///
170/// The methods cannot move S
171pub unsafe trait PHY {
172 /// Reset PHY and wait for it to come out of reset. 170 /// Reset PHY and wait for it to come out of reset.
173 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S); 171 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S);
174 /// PHY initialisation. 172 /// PHY initialisation.
@@ -177,13 +175,32 @@ pub unsafe trait PHY {
177 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool; 175 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool;
178} 176}
179 177
178impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
179 /// Directly expose the SMI interface used by the Ethernet driver.
180 ///
181 /// This can be used to for example configure special PHY registers for compliance testing.
182 pub fn station_management(&mut self) -> &mut impl StationManagement {
183 &mut self.station_management
184 }
185
186 /// Access the user-supplied `Phy`.
187 pub fn phy(&self) -> &P {
188 &self.phy
189 }
190
191 /// Mutably access the user-supplied `Phy`.
192 pub fn phy_mut(&mut self) -> &mut P {
193 &mut self.phy
194 }
195}
196
180trait SealedInstance { 197trait SealedInstance {
181 fn regs() -> crate::pac::eth::Eth; 198 fn regs() -> crate::pac::eth::Eth;
182} 199}
183 200
184/// Ethernet instance. 201/// Ethernet instance.
185#[allow(private_bounds)] 202#[allow(private_bounds)]
186pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} 203pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {}
187 204
188impl SealedInstance for crate::peripherals::ETH { 205impl SealedInstance for crate::peripherals::ETH {
189 fn regs() -> crate::pac::eth::Eth { 206 fn regs() -> crate::pac::eth::Eth {
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index cce75ece7..01e321bce 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -6,7 +6,7 @@ mod tx_desc;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{fence, Ordering}; 7use core::sync::atomic::{fence, Ordering};
8 8
9use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::Peri;
10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; 10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
11 11
12pub(crate) use self::rx_desc::{RDes, RDesRing}; 12pub(crate) use self::rx_desc::{RDes, RDesRing};
@@ -15,6 +15,7 @@ use super::*;
15#[cfg(eth_v1a)] 15#[cfg(eth_v1a)]
16use crate::gpio::Pull; 16use crate::gpio::Pull;
17use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 17use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
18use crate::interrupt;
18use crate::interrupt::InterruptExt; 19use crate::interrupt::InterruptExt;
19#[cfg(eth_v1a)] 20#[cfg(eth_v1a)]
20use crate::pac::AFIO; 21use crate::pac::AFIO;
@@ -22,7 +23,6 @@ use crate::pac::AFIO;
22use crate::pac::SYSCFG; 23use crate::pac::SYSCFG;
23use crate::pac::{ETH, RCC}; 24use crate::pac::{ETH, RCC};
24use crate::rcc::SealedRccPeripheral; 25use crate::rcc::SealedRccPeripheral;
25use crate::{interrupt, Peripheral};
26 26
27/// Interrupt handler. 27/// Interrupt handler.
28pub struct InterruptHandler {} 28pub struct InterruptHandler {}
@@ -46,17 +46,23 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
46} 46}
47 47
48/// Ethernet driver. 48/// Ethernet driver.
49pub struct Ethernet<'d, T: Instance, P: PHY> { 49pub struct Ethernet<'d, T: Instance, P: Phy> {
50 _peri: PeripheralRef<'d, T>, 50 _peri: Peri<'d, T>,
51 pub(crate) tx: TDesRing<'d>, 51 pub(crate) tx: TDesRing<'d>,
52 pub(crate) rx: RDesRing<'d>, 52 pub(crate) rx: RDesRing<'d>,
53 53
54 pins: [PeripheralRef<'d, AnyPin>; 9], 54 pins: Pins<'d>,
55 pub(crate) phy: P, 55 pub(crate) phy: P,
56 pub(crate) station_management: EthernetStationManagement<T>, 56 pub(crate) station_management: EthernetStationManagement<T>,
57 pub(crate) mac_addr: [u8; 6], 57 pub(crate) mac_addr: [u8; 6],
58} 58}
59 59
60/// Pins of ethernet driver.
61enum Pins<'d> {
62 Rmii([Peri<'d, AnyPin>; 9]),
63 Mii([Peri<'d, AnyPin>; 14]),
64}
65
60#[cfg(eth_v1a)] 66#[cfg(eth_v1a)]
61macro_rules! config_in_pins { 67macro_rules! config_in_pins {
62 ($($pin:ident),*) => { 68 ($($pin:ident),*) => {
@@ -91,26 +97,24 @@ macro_rules! config_pins {
91 }; 97 };
92} 98}
93 99
94impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { 100impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
95 /// safety: the returned instance is not leak-safe 101 /// safety: the returned instance is not leak-safe
96 pub fn new<const TX: usize, const RX: usize>( 102 pub fn new<const TX: usize, const RX: usize>(
97 queue: &'d mut PacketQueue<TX, RX>, 103 queue: &'d mut PacketQueue<TX, RX>,
98 peri: impl Peripheral<P = T> + 'd, 104 peri: Peri<'d, T>,
99 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
100 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 106 ref_clk: Peri<'d, impl RefClkPin<T>>,
101 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 107 mdio: Peri<'d, impl MDIOPin<T>>,
102 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 108 mdc: Peri<'d, impl MDCPin<T>>,
103 crs: impl Peripheral<P = impl CRSPin<T>> + 'd, 109 crs: Peri<'d, impl CRSPin<T>>,
104 rx_d0: impl Peripheral<P = impl RXD0Pin<T>> + 'd, 110 rx_d0: Peri<'d, impl RXD0Pin<T>>,
105 rx_d1: impl Peripheral<P = impl RXD1Pin<T>> + 'd, 111 rx_d1: Peri<'d, impl RXD1Pin<T>>,
106 tx_d0: impl Peripheral<P = impl TXD0Pin<T>> + 'd, 112 tx_d0: Peri<'d, impl TXD0Pin<T>>,
107 tx_d1: impl Peripheral<P = impl TXD1Pin<T>> + 'd, 113 tx_d1: Peri<'d, impl TXD1Pin<T>>,
108 tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd, 114 tx_en: Peri<'d, impl TXEnPin<T>>,
109 phy: P, 115 phy: P,
110 mac_addr: [u8; 6], 116 mac_addr: [u8; 6],
111 ) -> Self { 117 ) -> Self {
112 into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
113
114 // Enable the necessary Clocks 118 // Enable the necessary Clocks
115 #[cfg(eth_v1a)] 119 #[cfg(eth_v1a)]
116 critical_section::with(|_| { 120 critical_section::with(|_| {
@@ -148,6 +152,29 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
148 #[cfg(any(eth_v1b, eth_v1c))] 152 #[cfg(any(eth_v1b, eth_v1c))]
149 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 153 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
150 154
155 let pins = Pins::Rmii([
156 ref_clk.into(),
157 mdio.into(),
158 mdc.into(),
159 crs.into(),
160 rx_d0.into(),
161 rx_d1.into(),
162 tx_d0.into(),
163 tx_d1.into(),
164 tx_en.into(),
165 ]);
166
167 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
168 }
169
170 fn new_inner<const TX: usize, const RX: usize>(
171 queue: &'d mut PacketQueue<TX, RX>,
172 peri: Peri<'d, T>,
173 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
174 pins: Pins<'d>,
175 phy: P,
176 mac_addr: [u8; 6],
177 ) -> Self {
151 let dma = T::regs().ethernet_dma(); 178 let dma = T::regs().ethernet_dma();
152 let mac = T::regs().ethernet_mac(); 179 let mac = T::regs().ethernet_mac();
153 180
@@ -159,8 +186,13 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
159 w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times 186 w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times
160 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping 187 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
161 w.set_fes(Fes::FES100); // fast ethernet speed 188 w.set_fes(Fes::FES100); // fast ethernet speed
162 w.set_dm(Dm::FULLDUPLEX); // full duplex 189 w.set_dm(Dm::FULL_DUPLEX); // full duplex
163 // TODO: Carrier sense ? ECRSFD 190 // TODO: Carrier sense ? ECRSFD
191 });
192
193 // Set the mac to pass all multicast packets
194 mac.macffr().modify(|w| {
195 w.set_pam(true);
164 }); 196 });
165 197
166 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, 198 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
@@ -181,8 +213,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
181 213
182 // Transfer and Forward, Receive and Forward 214 // Transfer and Forward, Receive and Forward
183 dma.dmaomr().modify(|w| { 215 dma.dmaomr().modify(|w| {
184 w.set_tsf(Tsf::STOREFORWARD); 216 w.set_tsf(Tsf::STORE_FORWARD);
185 w.set_rsf(Rsf::STOREFORWARD); 217 w.set_rsf(Rsf::STORE_FORWARD);
186 }); 218 });
187 219
188 dma.dmabmr().modify(|w| { 220 dma.dmabmr().modify(|w| {
@@ -207,18 +239,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
207 } 239 }
208 }; 240 };
209 241
210 let pins = [
211 ref_clk.map_into(),
212 mdio.map_into(),
213 mdc.map_into(),
214 crs.map_into(),
215 rx_d0.map_into(),
216 rx_d1.map_into(),
217 tx_d0.map_into(),
218 tx_d1.map_into(),
219 tx_en.map_into(),
220 ];
221
222 let mut this = Self { 242 let mut this = Self {
223 _peri: peri, 243 _peri: peri,
224 pins, 244 pins,
@@ -264,15 +284,96 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
264 284
265 this 285 this
266 } 286 }
287
288 /// Create a new MII ethernet driver using 14 pins.
289 pub fn new_mii<const TX: usize, const RX: usize>(
290 queue: &'d mut PacketQueue<TX, RX>,
291 peri: Peri<'d, T>,
292 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
293 rx_clk: Peri<'d, impl RXClkPin<T>>,
294 tx_clk: Peri<'d, impl TXClkPin<T>>,
295 mdio: Peri<'d, impl MDIOPin<T>>,
296 mdc: Peri<'d, impl MDCPin<T>>,
297 rxdv: Peri<'d, impl RXDVPin<T>>,
298 rx_d0: Peri<'d, impl RXD0Pin<T>>,
299 rx_d1: Peri<'d, impl RXD1Pin<T>>,
300 rx_d2: Peri<'d, impl RXD2Pin<T>>,
301 rx_d3: Peri<'d, impl RXD3Pin<T>>,
302 tx_d0: Peri<'d, impl TXD0Pin<T>>,
303 tx_d1: Peri<'d, impl TXD1Pin<T>>,
304 tx_d2: Peri<'d, impl TXD2Pin<T>>,
305 tx_d3: Peri<'d, impl TXD3Pin<T>>,
306 tx_en: Peri<'d, impl TXEnPin<T>>,
307 phy: P,
308 mac_addr: [u8; 6],
309 ) -> Self {
310 // TODO: Handle optional signals like CRS, MII_COL, RX_ER?
311
312 // Enable the necessary Clocks
313 #[cfg(eth_v1a)]
314 critical_section::with(|_| {
315 RCC.apb2enr().modify(|w| w.set_afioen(true));
316
317 // Select MII (Media Independent Interface)
318 // Must be done prior to enabling peripheral clock
319 AFIO.mapr().modify(|w| w.set_mii_rmii_sel(false));
320
321 RCC.ahbenr().modify(|w| {
322 w.set_ethen(true);
323 w.set_ethtxen(true);
324 w.set_ethrxen(true);
325 });
326 });
327
328 #[cfg(any(eth_v1b, eth_v1c))]
329 critical_section::with(|_| {
330 RCC.ahb1enr().modify(|w| {
331 w.set_ethen(true);
332 w.set_ethtxen(true);
333 w.set_ethrxen(true);
334 });
335
336 // MII (Media Independent Interface)
337 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(false));
338 });
339
340 #[cfg(eth_v1a)]
341 {
342 config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv);
343 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
344 }
345
346 #[cfg(any(eth_v1b, eth_v1c))]
347 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);
348
349 let pins = Pins::Mii([
350 rx_clk.into(),
351 tx_clk.into(),
352 mdio.into(),
353 mdc.into(),
354 rxdv.into(),
355 rx_d0.into(),
356 rx_d1.into(),
357 rx_d2.into(),
358 rx_d3.into(),
359 tx_d0.into(),
360 tx_d1.into(),
361 tx_d2.into(),
362 tx_d3.into(),
363 tx_en.into(),
364 ]);
365
366 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
367 }
267} 368}
268 369
269/// Ethernet station management interface. 370/// Ethernet station management interface.
270pub struct EthernetStationManagement<T: Instance> { 371pub(crate) struct EthernetStationManagement<T: Instance> {
271 peri: PhantomData<T>, 372 peri: PhantomData<T>,
272 clock_range: Cr, 373 clock_range: Cr,
273} 374}
274 375
275unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { 376impl<T: Instance> StationManagement for EthernetStationManagement<T> {
276 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { 377 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
277 let mac = T::regs().ethernet_mac(); 378 let mac = T::regs().ethernet_mac();
278 379
@@ -302,7 +403,7 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
302 } 403 }
303} 404}
304 405
305impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 406impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {
306 fn drop(&mut self) { 407 fn drop(&mut self) {
307 let dma = T::regs().ethernet_dma(); 408 let dma = T::regs().ethernet_dma();
308 let mac = T::regs().ethernet_mac(); 409 let mac = T::regs().ethernet_mac();
@@ -319,7 +420,10 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
319 dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); 420 dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
320 421
321 critical_section::with(|_| { 422 critical_section::with(|_| {
322 for pin in self.pins.iter_mut() { 423 for pin in match self.pins {
424 Pins::Rmii(ref mut pins) => pins.iter_mut(),
425 Pins::Mii(ref mut pins) => pins.iter_mut(),
426 } {
323 pin.set_as_disconnected(); 427 pin.set_as_disconnected();
324 } 428 }
325 }) 429 })
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 668378bea..2a46c1895 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -168,15 +168,15 @@ impl<'a> RDesRing<'a> {
168 // Reset or Stop Receive Command issued 168 // Reset or Stop Receive Command issued
169 Rps::STOPPED => RunningState::Stopped, 169 Rps::STOPPED => RunningState::Stopped,
170 // Fetching receive transfer descriptor 170 // Fetching receive transfer descriptor
171 Rps::RUNNINGFETCHING => RunningState::Running, 171 Rps::RUNNING_FETCHING => RunningState::Running,
172 // Waiting for receive packet 172 // Waiting for receive packet
173 Rps::RUNNINGWAITING => RunningState::Running, 173 Rps::RUNNING_WAITING => RunningState::Running,
174 // Receive descriptor unavailable 174 // Receive descriptor unavailable
175 Rps::SUSPENDED => RunningState::Stopped, 175 Rps::SUSPENDED => RunningState::Stopped,
176 // Closing receive descriptor 176 // Closing receive descriptor
177 Rps::_RESERVED_5 => RunningState::Running, 177 Rps::_RESERVED_5 => RunningState::Running,
178 // Transferring the receive packet data from receive buffer to host memory 178 // Transferring the receive packet data from receive buffer to host memory
179 Rps::RUNNINGWRITING => RunningState::Running, 179 Rps::RUNNING_WRITING => RunningState::Running,
180 _ => RunningState::Unknown, 180 _ => RunningState::Unknown,
181 } 181 }
182 } 182 }
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index b26f08cd9..034c5dd88 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -3,16 +3,16 @@ mod descriptors;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::sync::atomic::{fence, Ordering}; 4use core::sync::atomic::{fence, Ordering};
5 5
6use embassy_hal_internal::{into_ref, PeripheralRef}; 6use embassy_hal_internal::Peri;
7use stm32_metapac::syscfg::vals::EthSelPhy; 7use stm32_metapac::syscfg::vals::EthSelPhy;
8 8
9pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; 9pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
10use super::*; 10use super::*;
11use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed}; 11use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed};
12use crate::interrupt;
12use crate::interrupt::InterruptExt; 13use crate::interrupt::InterruptExt;
13use crate::pac::ETH; 14use crate::pac::ETH;
14use crate::rcc::SealedRccPeripheral; 15use crate::rcc::SealedRccPeripheral;
15use crate::{interrupt, Peripheral};
16 16
17/// Interrupt handler. 17/// Interrupt handler.
18pub struct InterruptHandler {} 18pub struct InterruptHandler {}
@@ -36,8 +36,8 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
36} 36}
37 37
38/// Ethernet driver. 38/// Ethernet driver.
39pub struct Ethernet<'d, T: Instance, P: PHY> { 39pub struct Ethernet<'d, T: Instance, P: Phy> {
40 _peri: PeripheralRef<'d, T>, 40 _peri: Peri<'d, T>,
41 pub(crate) tx: TDesRing<'d>, 41 pub(crate) tx: TDesRing<'d>,
42 pub(crate) rx: RDesRing<'d>, 42 pub(crate) rx: RDesRing<'d>,
43 pins: Pins<'d>, 43 pins: Pins<'d>,
@@ -48,8 +48,8 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
48 48
49/// Pins of ethernet driver. 49/// Pins of ethernet driver.
50enum Pins<'d> { 50enum Pins<'d> {
51 Rmii([PeripheralRef<'d, AnyPin>; 9]), 51 Rmii([Peri<'d, AnyPin>; 9]),
52 Mii([PeripheralRef<'d, AnyPin>; 14]), 52 Mii([Peri<'d, AnyPin>; 14]),
53} 53}
54 54
55macro_rules! config_pins { 55macro_rules! config_pins {
@@ -63,21 +63,21 @@ macro_rules! config_pins {
63 }; 63 };
64} 64}
65 65
66impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { 66impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
67 /// Create a new RMII ethernet driver using 9 pins. 67 /// Create a new RMII ethernet driver using 9 pins.
68 pub fn new<const TX: usize, const RX: usize>( 68 pub fn new<const TX: usize, const RX: usize>(
69 queue: &'d mut PacketQueue<TX, RX>, 69 queue: &'d mut PacketQueue<TX, RX>,
70 peri: impl Peripheral<P = T> + 'd, 70 peri: Peri<'d, T>,
71 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 71 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
72 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 72 ref_clk: Peri<'d, impl RefClkPin<T>>,
73 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 73 mdio: Peri<'d, impl MDIOPin<T>>,
74 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 74 mdc: Peri<'d, impl MDCPin<T>>,
75 crs: impl Peripheral<P = impl CRSPin<T>> + 'd, 75 crs: Peri<'d, impl CRSPin<T>>,
76 rx_d0: impl Peripheral<P = impl RXD0Pin<T>> + 'd, 76 rx_d0: Peri<'d, impl RXD0Pin<T>>,
77 rx_d1: impl Peripheral<P = impl RXD1Pin<T>> + 'd, 77 rx_d1: Peri<'d, impl RXD1Pin<T>>,
78 tx_d0: impl Peripheral<P = impl TXD0Pin<T>> + 'd, 78 tx_d0: Peri<'d, impl TXD0Pin<T>>,
79 tx_d1: impl Peripheral<P = impl TXD1Pin<T>> + 'd, 79 tx_d1: Peri<'d, impl TXD1Pin<T>>,
80 tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd, 80 tx_en: Peri<'d, impl TXEnPin<T>>,
81 phy: P, 81 phy: P,
82 mac_addr: [u8; 6], 82 mac_addr: [u8; 6],
83 ) -> Self { 83 ) -> Self {
@@ -92,19 +92,18 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
92 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); 92 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII));
93 }); 93 });
94 94
95 into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
96 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 95 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
97 96
98 let pins = Pins::Rmii([ 97 let pins = Pins::Rmii([
99 ref_clk.map_into(), 98 ref_clk.into(),
100 mdio.map_into(), 99 mdio.into(),
101 mdc.map_into(), 100 mdc.into(),
102 crs.map_into(), 101 crs.into(),
103 rx_d0.map_into(), 102 rx_d0.into(),
104 rx_d1.map_into(), 103 rx_d1.into(),
105 tx_d0.map_into(), 104 tx_d0.into(),
106 tx_d1.map_into(), 105 tx_d1.into(),
107 tx_en.map_into(), 106 tx_en.into(),
108 ]); 107 ]);
109 108
110 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 109 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
@@ -113,22 +112,22 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
113 /// Create a new MII ethernet driver using 14 pins. 112 /// Create a new MII ethernet driver using 14 pins.
114 pub fn new_mii<const TX: usize, const RX: usize>( 113 pub fn new_mii<const TX: usize, const RX: usize>(
115 queue: &'d mut PacketQueue<TX, RX>, 114 queue: &'d mut PacketQueue<TX, RX>,
116 peri: impl Peripheral<P = T> + 'd, 115 peri: Peri<'d, T>,
117 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 116 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
118 rx_clk: impl Peripheral<P = impl RXClkPin<T>> + 'd, 117 rx_clk: Peri<'d, impl RXClkPin<T>>,
119 tx_clk: impl Peripheral<P = impl TXClkPin<T>> + 'd, 118 tx_clk: Peri<'d, impl TXClkPin<T>>,
120 mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, 119 mdio: Peri<'d, impl MDIOPin<T>>,
121 mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, 120 mdc: Peri<'d, impl MDCPin<T>>,
122 rxdv: impl Peripheral<P = impl RXDVPin<T>> + 'd, 121 rxdv: Peri<'d, impl RXDVPin<T>>,
123 rx_d0: impl Peripheral<P = impl RXD0Pin<T>> + 'd, 122 rx_d0: Peri<'d, impl RXD0Pin<T>>,
124 rx_d1: impl Peripheral<P = impl RXD1Pin<T>> + 'd, 123 rx_d1: Peri<'d, impl RXD1Pin<T>>,
125 rx_d2: impl Peripheral<P = impl RXD2Pin<T>> + 'd, 124 rx_d2: Peri<'d, impl RXD2Pin<T>>,
126 rx_d3: impl Peripheral<P = impl RXD3Pin<T>> + 'd, 125 rx_d3: Peri<'d, impl RXD3Pin<T>>,
127 tx_d0: impl Peripheral<P = impl TXD0Pin<T>> + 'd, 126 tx_d0: Peri<'d, impl TXD0Pin<T>>,
128 tx_d1: impl Peripheral<P = impl TXD1Pin<T>> + 'd, 127 tx_d1: Peri<'d, impl TXD1Pin<T>>,
129 tx_d2: impl Peripheral<P = impl TXD2Pin<T>> + 'd, 128 tx_d2: Peri<'d, impl TXD2Pin<T>>,
130 tx_d3: impl Peripheral<P = impl TXD3Pin<T>> + 'd, 129 tx_d3: Peri<'d, impl TXD3Pin<T>>,
131 tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd, 130 tx_en: Peri<'d, impl TXEnPin<T>>,
132 phy: P, 131 phy: P,
133 mac_addr: [u8; 6], 132 mac_addr: [u8; 6],
134 ) -> Self { 133 ) -> Self {
@@ -145,24 +144,23 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
145 .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII)); 144 .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII));
146 }); 145 });
147 146
148 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);
149 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); 147 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);
150 148
151 let pins = Pins::Mii([ 149 let pins = Pins::Mii([
152 rx_clk.map_into(), 150 rx_clk.into(),
153 tx_clk.map_into(), 151 tx_clk.into(),
154 mdio.map_into(), 152 mdio.into(),
155 mdc.map_into(), 153 mdc.into(),
156 rxdv.map_into(), 154 rxdv.into(),
157 rx_d0.map_into(), 155 rx_d0.into(),
158 rx_d1.map_into(), 156 rx_d1.into(),
159 rx_d2.map_into(), 157 rx_d2.into(),
160 rx_d3.map_into(), 158 rx_d3.into(),
161 tx_d0.map_into(), 159 tx_d0.into(),
162 tx_d1.map_into(), 160 tx_d1.into(),
163 tx_d2.map_into(), 161 tx_d2.into(),
164 tx_d3.map_into(), 162 tx_d3.into(),
165 tx_en.map_into(), 163 tx_en.into(),
166 ]); 164 ]);
167 165
168 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 166 Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
@@ -170,7 +168,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
170 168
171 fn new_inner<const TX: usize, const RX: usize>( 169 fn new_inner<const TX: usize, const RX: usize>(
172 queue: &'d mut PacketQueue<TX, RX>, 170 queue: &'d mut PacketQueue<TX, RX>,
173 peri: impl Peripheral<P = T> + 'd, 171 peri: Peri<'d, T>,
174 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 172 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
175 pins: Pins<'d>, 173 pins: Pins<'d>,
176 phy: P, 174 phy: P,
@@ -192,6 +190,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
192 // TODO: Carrier sense ? ECRSFD 190 // TODO: Carrier sense ? ECRSFD
193 }); 191 });
194 192
193 // Disable multicast filter
194 mac.macpfr().modify(|w| w.set_pm(true));
195
195 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, 196 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
196 // so the LR write must happen after the HR write. 197 // so the LR write must happen after the HR write.
197 mac.maca0hr() 198 mac.maca0hr()
@@ -251,7 +252,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
251 }; 252 };
252 253
253 let mut this = Self { 254 let mut this = Self {
254 _peri: peri.into_ref(), 255 _peri: peri,
255 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 256 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
256 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 257 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
257 pins, 258 pins,
@@ -301,7 +302,7 @@ pub struct EthernetStationManagement<T: Instance> {
301 clock_range: u8, 302 clock_range: u8,
302} 303}
303 304
304unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { 305impl<T: Instance> StationManagement for EthernetStationManagement<T> {
305 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { 306 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
306 let mac = T::regs().ethernet_mac(); 307 let mac = T::regs().ethernet_mac();
307 308
@@ -331,7 +332,7 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
331 } 332 }
332} 333}
333 334
334impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { 335impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {
335 fn drop(&mut self) { 336 fn drop(&mut self) {
336 let dma = T::regs().ethernet_dma(); 337 let dma = T::regs().ethernet_dma();
337 let mac = T::regs().ethernet_mac(); 338 let mac = T::regs().ethernet_mac();
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 224d51b84..9fce78f95 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -5,21 +5,25 @@ 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, into_ref}; 8use embassy_hal_internal::{impl_peripheral, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; 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, Peri};
15 15
16const EXTI_COUNT: usize = 16; 16const EXTI_COUNT: usize = 16;
17const NEW_AW: AtomicWaker = AtomicWaker::new(); 17static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT];
18static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT];
19 18
20#[cfg(exti_w)] 19#[cfg(all(exti_w, feature = "_core-cm0p"))]
21fn cpu_regs() -> pac::exti::Cpu { 20fn cpu_regs() -> pac::exti::Cpu {
22 EXTI.cpu(crate::pac::CORE_INDEX) 21 EXTI.cpu(1)
22}
23
24#[cfg(all(exti_w, not(feature = "_core-cm0p")))]
25fn cpu_regs() -> pac::exti::Cpu {
26 EXTI.cpu(0)
23} 27}
24 28
25#[cfg(not(exti_w))] 29#[cfg(not(exti_w))]
@@ -41,9 +45,6 @@ fn exticr_regs() -> pac::afio::Afio {
41} 45}
42 46
43unsafe fn on_irq() { 47unsafe fn on_irq() {
44 #[cfg(feature = "low-power")]
45 crate::low_power::on_wakeup_irq();
46
47 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 48 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
48 let bits = EXTI.pr(0).read().0; 49 let bits = EXTI.pr(0).read().0;
49 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 50 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
@@ -68,6 +69,9 @@ unsafe fn on_irq() {
68 EXTI.rpr(0).write_value(Lines(bits)); 69 EXTI.rpr(0).write_value(Lines(bits));
69 EXTI.fpr(0).write_value(Lines(bits)); 70 EXTI.fpr(0).write_value(Lines(bits));
70 } 71 }
72
73 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq();
71} 75}
72 76
73struct BitIter(u32); 77struct BitIter(u32);
@@ -101,13 +105,7 @@ impl<'d> Unpin for ExtiInput<'d> {}
101 105
102impl<'d> ExtiInput<'d> { 106impl<'d> ExtiInput<'d> {
103 /// Create an EXTI input. 107 /// Create an EXTI input.
104 pub fn new<T: GpioPin>( 108 pub fn new<T: GpioPin>(pin: Peri<'d, T>, ch: Peri<'d, T::ExtiChannel>, pull: Pull) -> Self {
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. 109 // Needed if using AnyPin+AnyChannel.
112 assert_eq!(pin.pin(), ch.number()); 110 assert_eq!(pin.pin(), ch.number());
113 111
@@ -334,23 +332,12 @@ trait SealedChannel {}
334 332
335/// EXTI channel trait. 333/// EXTI channel trait.
336#[allow(private_bounds)] 334#[allow(private_bounds)]
337pub trait Channel: SealedChannel + Sized { 335pub trait Channel: PeripheralType + SealedChannel + Sized {
338 /// Get the EXTI channel number. 336 /// Get the EXTI channel number.
339 fn number(&self) -> u8; 337 fn number(&self) -> u8;
340
341 /// Type-erase (degrade) this channel into an `AnyChannel`.
342 ///
343 /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which
344 /// are all different types, into the same type. It is useful for
345 /// creating arrays of channels, or avoiding generics.
346 fn degrade(self) -> AnyChannel {
347 AnyChannel {
348 number: self.number() as u8,
349 }
350 }
351} 338}
352 339
353/// Type-erased (degraded) EXTI channel. 340/// Type-erased EXTI channel.
354/// 341///
355/// This represents ownership over any EXTI channel, known at runtime. 342/// This represents ownership over any EXTI channel, known at runtime.
356pub struct AnyChannel { 343pub struct AnyChannel {
@@ -373,6 +360,14 @@ macro_rules! impl_exti {
373 $number 360 $number
374 } 361 }
375 } 362 }
363
364 impl From<peripherals::$type> for AnyChannel {
365 fn from(val: peripherals::$type) -> Self {
366 Self {
367 number: val.number() as u8,
368 }
369 }
370 }
376 }; 371 };
377} 372}
378 373
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 9468ac632..006dcddeb 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -2,28 +2,25 @@ use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5use embassy_hal_internal::into_ref;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::mutex::Mutex; 6use embassy_sync::mutex::Mutex;
8 7
9use super::{ 8use super::{
10 blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, 9 blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout,
11 WRITE_SIZE, 10 FLASH_BASE, FLASH_SIZE, WRITE_SIZE,
12}; 11};
13use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
14use crate::peripherals::FLASH; 13use crate::peripherals::FLASH;
15use crate::{interrupt, Peripheral}; 14use crate::{interrupt, Peri};
16 15
17pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); 16pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
18 17
19impl<'d> Flash<'d, Async> { 18impl<'d> Flash<'d, Async> {
20 /// Create a new flash driver with async capabilities. 19 /// Create a new flash driver with async capabilities.
21 pub fn new( 20 pub fn new(
22 p: impl Peripheral<P = FLASH> + 'd, 21 p: Peri<'d, FLASH>,
23 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd, 22 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd,
24 ) -> Self { 23 ) -> Self {
25 into_ref!(p);
26
27 crate::interrupt::FLASH.unpend(); 24 crate::interrupt::FLASH.unpend();
28 unsafe { crate::interrupt::FLASH.enable() }; 25 unsafe { crate::interrupt::FLASH.enable() };
29 26
@@ -37,7 +34,6 @@ impl<'d> Flash<'d, Async> {
37 /// 34 ///
38 /// See module-level documentation for details on how memory regions work. 35 /// See module-level documentation for details on how memory regions work.
39 pub fn into_regions(self) -> FlashLayout<'d, Async> { 36 pub fn into_regions(self) -> FlashLayout<'d, Async> {
40 assert!(family::is_default_layout());
41 FlashLayout::new(self.inner) 37 FlashLayout::new(self.inner)
42 } 38 }
43 39
@@ -126,7 +122,7 @@ pub(super) async unsafe fn write_chunked(base: u32, size: u32, offset: u32, byte
126pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { 122pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> {
127 let start_address = base + from; 123 let start_address = base + from;
128 let end_address = base + to; 124 let end_address = base + to;
129 let regions = family::get_flash_regions(); 125 let regions = get_flash_regions();
130 126
131 ensure_sector_aligned(start_address, end_address, regions)?; 127 ensure_sector_aligned(start_address, end_address, regions)?;
132 128
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 8ec4bb2a1..10023e637 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -2,26 +2,27 @@ use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5use embassy_hal_internal::{into_ref, PeripheralRef};
6use stm32_metapac::FLASH_BASE;
7 5
8use super::{ 6use super::{
9 family, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, 7 family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE,
10 READ_SIZE, WRITE_SIZE, 8 MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE,
11}; 9};
10use crate::Peri;
11use crate::_generated::FLASH_BASE;
12use crate::peripherals::FLASH; 12use crate::peripherals::FLASH;
13use crate::Peripheral;
14 13
15/// Internal flash memory driver. 14/// Internal flash memory driver.
16pub struct Flash<'d, MODE = Async> { 15pub struct Flash<'d, MODE = Async> {
17 pub(crate) inner: PeripheralRef<'d, FLASH>, 16 pub(crate) inner: Peri<'d, FLASH>,
18 pub(crate) _mode: PhantomData<MODE>, 17 pub(crate) _mode: PhantomData<MODE>,
19} 18}
20 19
21impl<'d> Flash<'d, Blocking> { 20impl<'d> Flash<'d, Blocking> {
22 /// Create a new flash driver, usable in blocking mode. 21 /// Create a new flash driver, usable in blocking mode.
23 pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self { 22 pub fn new_blocking(p: Peri<'d, FLASH>) -> Self {
24 into_ref!(p); 23 #[cfg(bank_setup_configurable)]
24 // Check if the configuration matches the embassy setup
25 super::check_bank_setup();
25 26
26 Self { 27 Self {
27 inner: p, 28 inner: p,
@@ -35,7 +36,6 @@ impl<'d, MODE> Flash<'d, MODE> {
35 /// 36 ///
36 /// See module-level documentation for details on how memory regions work. 37 /// See module-level documentation for details on how memory regions work.
37 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { 38 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> {
38 assert!(family::is_default_layout());
39 FlashLayout::new(self.inner) 39 FlashLayout::new(self.inner)
40 } 40 }
41 41
@@ -140,7 +140,7 @@ pub(super) unsafe fn blocking_erase(
140) -> Result<(), Error> { 140) -> Result<(), Error> {
141 let start_address = base + from; 141 let start_address = base + from;
142 let end_address = base + to; 142 let end_address = base + to;
143 let regions = family::get_flash_regions(); 143 let regions = get_flash_regions();
144 144
145 ensure_sector_aligned(start_address, end_address, regions)?; 145 ensure_sector_aligned(start_address, end_address, regions)?;
146 146
diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs
new file mode 100644
index 000000000..cc3529eb9
--- /dev/null
+++ b/embassy-stm32/src/flash/eeprom.rs
@@ -0,0 +1,236 @@
1use embassy_hal_internal::drop::OnDrop;
2
3use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE};
4
5#[cfg(eeprom)]
6impl<'d> Flash<'d, Blocking> {
7 // --- Internal helpers ---
8
9 /// Checks if the given offset and size are within the EEPROM bounds.
10 fn check_eeprom_offset(&self, offset: u32, size: u32) -> Result<(), Error> {
11 if offset
12 .checked_add(size)
13 .filter(|&end| end <= EEPROM_SIZE as u32)
14 .is_some()
15 {
16 Ok(())
17 } else {
18 Err(Error::Size)
19 }
20 }
21
22 // --- Unlocked (unsafe, internal) functions ---
23
24 /// Writes a slice of bytes to EEPROM at the given offset without locking.
25 ///
26 /// # Safety
27 /// Caller must ensure EEPROM is unlocked and offset is valid.
28 unsafe fn eeprom_write_u8_slice_unlocked(&self, offset: u32, data: &[u8]) -> Result<(), Error> {
29 for (i, &byte) in data.iter().enumerate() {
30 let addr = EEPROM_BASE as u32 + offset + i as u32;
31 core::ptr::write_volatile(addr as *mut u8, byte);
32 family::wait_ready_blocking()?;
33 family::clear_all_err();
34 }
35 Ok(())
36 }
37
38 /// Writes a slice of u16 values to EEPROM at the given offset without locking.
39 ///
40 /// # Safety
41 /// Caller must ensure EEPROM is unlocked and offset is valid and aligned.
42 unsafe fn eeprom_write_u16_slice_unlocked(&self, offset: u32, data: &[u16]) -> Result<(), Error> {
43 for (i, &value) in data.iter().enumerate() {
44 let addr = EEPROM_BASE as u32 + offset + i as u32 * 2;
45 core::ptr::write_volatile(addr as *mut u16, value);
46 family::wait_ready_blocking()?;
47 family::clear_all_err();
48 }
49 Ok(())
50 }
51
52 /// Writes a slice of u32 values to EEPROM at the given offset without locking.
53 ///
54 /// # Safety
55 /// Caller must ensure EEPROM is unlocked and offset is valid and aligned.
56 unsafe fn eeprom_write_u32_slice_unlocked(&self, offset: u32, data: &[u32]) -> Result<(), Error> {
57 for (i, &value) in data.iter().enumerate() {
58 let addr = EEPROM_BASE as u32 + offset + i as u32 * 4;
59 core::ptr::write_volatile(addr as *mut u32, value);
60 family::wait_ready_blocking()?;
61 family::clear_all_err();
62 }
63 Ok(())
64 }
65
66 // --- Public, safe API ---
67
68 /// Writes a single byte to EEPROM at the given offset.
69 pub fn eeprom_write_u8(&mut self, offset: u32, value: u8) -> Result<(), Error> {
70 self.check_eeprom_offset(offset, 1)?;
71 unsafe {
72 family::unlock();
73 let _on_drop = OnDrop::new(|| family::lock());
74 self.eeprom_write_u8_slice_unlocked(offset, core::slice::from_ref(&value))?;
75 }
76 Ok(())
77 }
78
79 /// Writes a single 16-bit value to EEPROM at the given offset.
80 ///
81 /// Returns an error if the offset is not 2-byte aligned.
82 pub fn eeprom_write_u16(&mut self, offset: u32, value: u16) -> Result<(), Error> {
83 if offset % 2 != 0 {
84 return Err(Error::Unaligned);
85 }
86 self.check_eeprom_offset(offset, 2)?;
87 unsafe {
88 family::unlock();
89 let _on_drop = OnDrop::new(|| family::lock());
90 self.eeprom_write_u16_slice_unlocked(offset, core::slice::from_ref(&value))?;
91 }
92 Ok(())
93 }
94
95 /// Writes a single 32-bit value to EEPROM at the given offset.
96 ///
97 /// Returns an error if the offset is not 4-byte aligned.
98 pub fn eeprom_write_u32(&mut self, offset: u32, value: u32) -> Result<(), Error> {
99 if offset % 4 != 0 {
100 return Err(Error::Unaligned);
101 }
102 self.check_eeprom_offset(offset, 4)?;
103 unsafe {
104 family::unlock();
105 let _on_drop = OnDrop::new(|| family::lock());
106 self.eeprom_write_u32_slice_unlocked(offset, core::slice::from_ref(&value))?;
107 }
108 Ok(())
109 }
110
111 /// Writes a slice of bytes to EEPROM at the given offset.
112 pub fn eeprom_write_u8_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> {
113 self.check_eeprom_offset(offset, data.len() as u32)?;
114 unsafe {
115 family::unlock();
116 let _on_drop = OnDrop::new(|| family::lock());
117 self.eeprom_write_u8_slice_unlocked(offset, data)?;
118 }
119 Ok(())
120 }
121
122 /// Writes a slice of 16-bit values to EEPROM at the given offset.
123 ///
124 /// Returns an error if the offset is not 2-byte aligned.
125 pub fn eeprom_write_u16_slice(&mut self, offset: u32, data: &[u16]) -> Result<(), Error> {
126 if offset % 2 != 0 {
127 return Err(Error::Unaligned);
128 }
129 self.check_eeprom_offset(offset, data.len() as u32 * 2)?;
130 unsafe {
131 family::unlock();
132 let _on_drop = OnDrop::new(|| family::lock());
133 self.eeprom_write_u16_slice_unlocked(offset, data)?;
134 }
135 Ok(())
136 }
137
138 /// Writes a slice of 32-bit values to EEPROM at the given offset.
139 ///
140 /// Returns an error if the offset is not 4-byte aligned.
141 pub fn eeprom_write_u32_slice(&mut self, offset: u32, data: &[u32]) -> Result<(), Error> {
142 if offset % 4 != 0 {
143 return Err(Error::Unaligned);
144 }
145 self.check_eeprom_offset(offset, data.len() as u32 * 4)?;
146 unsafe {
147 family::unlock();
148 let _on_drop = OnDrop::new(|| family::lock());
149 self.eeprom_write_u32_slice_unlocked(offset, data)?;
150 }
151 Ok(())
152 }
153
154 /// Writes a byte slice to EEPROM at the given offset, handling alignment.
155 ///
156 /// This method will write unaligned prefix and suffix as bytes, and aligned middle as u32.
157 pub fn eeprom_write_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> {
158 self.check_eeprom_offset(offset, data.len() as u32)?;
159 let start = offset;
160 let misalign = (start % 4) as usize;
161 let prefix_len = if misalign == 0 {
162 0
163 } else {
164 (4 - misalign).min(data.len())
165 };
166 let (prefix, rest) = data.split_at(prefix_len);
167 let aligned_len = (rest.len() / 4) * 4;
168 let (bytes_for_u32_write, suffix) = rest.split_at(aligned_len);
169
170 unsafe {
171 family::unlock();
172 let _on_drop = OnDrop::new(|| family::lock());
173
174 if !prefix.is_empty() {
175 self.eeprom_write_u8_slice_unlocked(start, prefix)?;
176 }
177 if !bytes_for_u32_write.is_empty() {
178 let aligned_eeprom_offset = start + prefix_len as u32;
179 let base_eeprom_addr = EEPROM_BASE as u32 + aligned_eeprom_offset;
180 for (i, chunk) in bytes_for_u32_write.chunks_exact(4).enumerate() {
181 // Safely read a u32 from a potentially unaligned pointer into the chunk.
182 let value = (chunk.as_ptr() as *const u32).read_unaligned();
183 let current_eeprom_addr = base_eeprom_addr + (i * 4) as u32;
184 core::ptr::write_volatile(current_eeprom_addr as *mut u32, value);
185 family::wait_ready_blocking()?;
186 family::clear_all_err();
187 }
188 }
189 if !suffix.is_empty() {
190 let suffix_offset = start + (prefix_len + aligned_len) as u32;
191 self.eeprom_write_u8_slice_unlocked(suffix_offset, suffix)?;
192 }
193 }
194 Ok(())
195 }
196
197 /// Reads a single byte from EEPROM at the given offset.
198 pub fn eeprom_read_u8(&self, offset: u32) -> Result<u8, Error> {
199 self.check_eeprom_offset(offset, 1)?;
200 let addr = EEPROM_BASE as u32 + offset;
201 Ok(unsafe { core::ptr::read_volatile(addr as *const u8) })
202 }
203
204 /// Reads a single 16-bit value from EEPROM at the given offset.
205 ///
206 /// Returns an error if the offset is not 2-byte aligned.
207 pub fn eeprom_read_u16(&self, offset: u32) -> Result<u16, Error> {
208 if offset % 2 != 0 {
209 return Err(Error::Unaligned);
210 }
211 self.check_eeprom_offset(offset, 2)?;
212 let addr = EEPROM_BASE as u32 + offset;
213 Ok(unsafe { core::ptr::read_volatile(addr as *const u16) })
214 }
215
216 /// Reads a single 32-bit value from EEPROM at the given offset.
217 ///
218 /// Returns an error if the offset is not 4-byte aligned.
219 pub fn eeprom_read_u32(&self, offset: u32) -> Result<u32, Error> {
220 if offset % 4 != 0 {
221 return Err(Error::Unaligned);
222 }
223 self.check_eeprom_offset(offset, 4)?;
224 let addr = EEPROM_BASE as u32 + offset;
225 Ok(unsafe { core::ptr::read_volatile(addr as *const u32) })
226 }
227
228 /// Reads a slice of bytes from EEPROM at the given offset into the provided buffer.
229 pub fn eeprom_read_slice(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> {
230 self.check_eeprom_offset(offset, buf.len() as u32)?;
231 let addr = EEPROM_BASE as u32 + offset;
232 let src = unsafe { core::slice::from_raw_parts(addr as *const u8, buf.len()) };
233 buf.copy_from_slice(src);
234 Ok(())
235 }
236}
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 402312f68..3f9dbe945 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 pac::FLASH.cr().modify(|w| w.set_lock(true)); 9 pac::FLASH.cr().modify(|w| w.set_lock(true));
18} 10}
diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs
index ff7f810ea..bf9ad2893 100644
--- a/embassy-stm32/src/flash/f1f3.rs
+++ b/embassy-stm32/src/flash/f1f3.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 pac::FLASH.cr().modify(|w| w.set_lock(true)); 9 pac::FLASH.cr().modify(|w| w.set_lock(true));
18} 10}
@@ -64,8 +56,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
64 // BSY bit, because there is a one-cycle delay between 56 // BSY bit, because there is a one-cycle delay between
65 // setting the STRT bit and the BSY bit being asserted 57 // setting the STRT bit and the BSY bit being asserted
66 // by hardware. See STM32F105xx, STM32F107xx device errata, 58 // by hardware. See STM32F105xx, STM32F107xx device errata,
67 // section 2.2.8 59 // section 2.2.8, and also RM0316 Rev 10 section 4.2.3 for
68 #[cfg(stm32f1)] 60 // STM32F3xx series.
69 pac::FLASH.cr().read(); 61 pac::FLASH.cr().read();
70 62
71 let mut ret: Result<(), Error> = wait_ready_blocking(); 63 let mut ret: Result<(), Error> = wait_ready_blocking();
diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs
new file mode 100644
index 000000000..67e380619
--- /dev/null
+++ b/embassy-stm32/src/flash/f2.rs
@@ -0,0 +1,134 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering};
3
4use pac::flash::regs::Sr;
5
6use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false);
11
12impl FlashSector {
13 const fn snb(&self) -> u8 {
14 ((self.bank as u8) << 4) + self.index_in_bank
15 }
16}
17
18pub(crate) unsafe fn lock() {
19 pac::FLASH.cr().modify(|w| w.set_lock(true));
20}
21
22pub(crate) unsafe fn unlock() {
23 if pac::FLASH.cr().read().lock() {
24 pac::FLASH.keyr().write_value(0x4567_0123);
25 pac::FLASH.keyr().write_value(0xCDEF_89AB);
26 }
27}
28
29pub(crate) unsafe fn enable_blocking_write() {
30 assert_eq!(0, WRITE_SIZE % 4);
31 save_data_cache_state();
32
33 pac::FLASH.cr().write(|w| {
34 w.set_pg(true);
35 w.set_psize(pac::flash::vals::Psize::PSIZE32);
36 });
37}
38
39pub(crate) unsafe fn disable_blocking_write() {
40 pac::FLASH.cr().write(|w| w.set_pg(false));
41 restore_data_cache_state();
42}
43
44pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
45 write_start(start_address, buf);
46 blocking_wait_ready()
47}
48
49unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) {
50 let mut address = start_address;
51 for val in buf.chunks(4) {
52 write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
53 address += val.len() as u32;
54
55 // prevents parallelism errors
56 fence(Ordering::SeqCst);
57 }
58}
59
60pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
61 save_data_cache_state();
62
63 trace!("Blocking erasing sector number {}", sector.snb());
64
65 pac::FLASH.cr().modify(|w| {
66 w.set_ser(true);
67 w.set_snb(sector.snb())
68 });
69
70 pac::FLASH.cr().modify(|w| {
71 w.set_strt(true);
72 });
73
74 let ret: Result<(), Error> = blocking_wait_ready();
75 clear_all_err();
76 restore_data_cache_state();
77 ret
78}
79
80pub(crate) unsafe fn clear_all_err() {
81 // read and write back the same value.
82 // This clears all "write 1 to clear" bits.
83 pac::FLASH.sr().modify(|_| {});
84}
85
86unsafe fn blocking_wait_ready() -> Result<(), Error> {
87 loop {
88 let sr = pac::FLASH.sr().read();
89
90 if !sr.bsy() {
91 return get_result(sr);
92 }
93 }
94}
95
96fn get_result(sr: Sr) -> Result<(), Error> {
97 if sr.pgserr() {
98 Err(Error::Seq)
99 } else if sr.pgperr() {
100 Err(Error::Parallelism)
101 } else if sr.pgaerr() {
102 Err(Error::Unaligned)
103 } else if sr.wrperr() {
104 Err(Error::Protected)
105 } else {
106 Ok(())
107 }
108}
109
110fn save_data_cache_state() {
111 let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2;
112 if dual_bank {
113 // Disable data cache during write/erase if there are two banks, see errata 2.2.12
114 let dcen = pac::FLASH.acr().read().dcen();
115 DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed);
116 if dcen {
117 pac::FLASH.acr().modify(|w| w.set_dcen(false));
118 }
119 }
120}
121
122fn restore_data_cache_state() {
123 let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2;
124 if dual_bank {
125 // Restore data cache if it was enabled
126 let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed);
127 if dcen {
128 // Reset data cache before we enable it again
129 pac::FLASH.acr().modify(|w| w.set_dcrst(true));
130 pac::FLASH.acr().modify(|w| w.set_dcrst(false));
131 pac::FLASH.acr().modify(|w| w.set_dcen(true))
132 }
133 }
134}
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index d0bb957ee..62e0492b5 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -3,176 +3,11 @@ use core::sync::atomic::{fence, AtomicBool, Ordering};
3 3
4use embassy_sync::waitqueue::AtomicWaker; 4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr; 5use pac::flash::regs::Sr;
6use pac::FLASH_SIZE;
7 6
8use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 7use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE};
8use crate::_generated::FLASH_SIZE;
9use crate::flash::Error; 9use crate::flash::Error;
10use crate::pac; 10use crate::pac;
11#[allow(missing_docs)] // TODO
12#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
13mod alt_regions {
14 use core::marker::PhantomData;
15
16 use embassy_hal_internal::PeripheralRef;
17 use stm32_metapac::FLASH_SIZE;
18
19 use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3};
20 use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
21 use crate::peripherals::FLASH;
22
23 pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
24 size: 3 * BANK1_REGION3.erase_size,
25 ..BANK1_REGION3
26 };
27 pub const ALT_BANK2_REGION1: FlashRegion = FlashRegion {
28 bank: FlashBank::Bank2,
29 base: BANK1_REGION1.base + FLASH_SIZE as u32 / 2,
30 ..BANK1_REGION1
31 };
32 pub const ALT_BANK2_REGION2: FlashRegion = FlashRegion {
33 bank: FlashBank::Bank2,
34 base: BANK1_REGION2.base + FLASH_SIZE as u32 / 2,
35 ..BANK1_REGION2
36 };
37 pub const ALT_BANK2_REGION3: FlashRegion = FlashRegion {
38 bank: FlashBank::Bank2,
39 base: BANK1_REGION3.base + FLASH_SIZE as u32 / 2,
40 size: 3 * BANK1_REGION3.erase_size,
41 ..BANK1_REGION3
42 };
43
44 pub const ALT_FLASH_REGIONS: [&FlashRegion; 6] = [
45 &BANK1_REGION1,
46 &BANK1_REGION2,
47 &ALT_BANK1_REGION3,
48 &ALT_BANK2_REGION1,
49 &ALT_BANK2_REGION2,
50 &ALT_BANK2_REGION3,
51 ];
52
53 pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
54 pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
55 pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
56 pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
57
58 pub struct AltFlashLayout<'d, MODE = Async> {
59 pub bank1_region1: Bank1Region1<'d, MODE>,
60 pub bank1_region2: Bank1Region2<'d, MODE>,
61 pub bank1_region3: AltBank1Region3<'d, MODE>,
62 pub bank2_region1: AltBank2Region1<'d, MODE>,
63 pub bank2_region2: AltBank2Region2<'d, MODE>,
64 pub bank2_region3: AltBank2Region3<'d, MODE>,
65 }
66
67 impl<'d> Flash<'d> {
68 pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> {
69 assert!(!super::is_default_layout());
70
71 // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
72 // Also, all async flash region operations are protected with a mutex.
73 let p = self.inner;
74 AltFlashLayout {
75 bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
76 bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
77 bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
78 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
79 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
80 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
81 }
82 }
83
84 pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> {
85 assert!(!super::is_default_layout());
86
87 // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
88 // Also, all blocking flash region operations are protected with a cs.
89 let p = self.inner;
90 AltFlashLayout {
91 bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
92 bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
93 bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
94 bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
95 bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
96 bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
97 }
98 }
99 }
100
101 macro_rules! foreach_altflash_region {
102 ($type_name:ident, $region:ident) => {
103 impl<MODE> $type_name<'_, MODE> {
104 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
105 crate::flash::common::blocking_read(self.0.base, self.0.size, offset, bytes)
106 }
107 }
108
109 impl $type_name<'_, Async> {
110 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
111 self.blocking_read(offset, bytes)
112 }
113
114 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
115 let _guard = asynch::REGION_ACCESS.lock().await;
116 unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await }
117 }
118
119 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
120 let _guard = asynch::REGION_ACCESS.lock().await;
121 unsafe { asynch::erase_sectored(self.0.base, from, to).await }
122 }
123 }
124
125 impl<MODE> embedded_storage::nor_flash::ErrorType for $type_name<'_, MODE> {
126 type Error = Error;
127 }
128
129 impl<MODE> embedded_storage::nor_flash::ReadNorFlash for $type_name<'_, MODE> {
130 const READ_SIZE: usize = crate::flash::READ_SIZE;
131
132 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
133 self.blocking_read(offset, bytes)
134 }
135
136 fn capacity(&self) -> usize {
137 self.0.size as usize
138 }
139 }
140
141 impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> {
142 const READ_SIZE: usize = crate::flash::READ_SIZE;
143
144 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
145 self.read(offset, bytes).await
146 }
147
148 fn capacity(&self) -> usize {
149 self.0.size as usize
150 }
151 }
152
153 impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_, Async> {
154 const WRITE_SIZE: usize = $region.write_size as usize;
155 const ERASE_SIZE: usize = $region.erase_size as usize;
156
157 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
158 self.write(offset, bytes).await
159 }
160
161 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
162 self.erase(from, to).await
163 }
164 }
165 };
166 }
167
168 foreach_altflash_region!(AltBank1Region3, ALT_BANK1_REGION3);
169 foreach_altflash_region!(AltBank2Region1, ALT_BANK2_REGION1);
170 foreach_altflash_region!(AltBank2Region2, ALT_BANK2_REGION2);
171 foreach_altflash_region!(AltBank2Region3, ALT_BANK2_REGION3);
172}
173
174#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
175pub use alt_regions::*;
176 11
177static WAKER: AtomicWaker = AtomicWaker::new(); 12static WAKER: AtomicWaker = AtomicWaker::new();
178static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false); 13static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false);
@@ -183,30 +18,6 @@ impl FlashSector {
183 } 18 }
184} 19}
185 20
186#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
187pub(crate) fn is_default_layout() -> bool {
188 !pac::FLASH.optcr().read().db1m()
189}
190
191#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
192pub(crate) const fn is_default_layout() -> bool {
193 true
194}
195
196#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
197pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
198 if is_default_layout() {
199 &FLASH_REGIONS
200 } else {
201 &ALT_FLASH_REGIONS
202 }
203}
204
205#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
206pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
207 &FLASH_REGIONS
208}
209
210pub(crate) unsafe fn on_interrupt() { 21pub(crate) unsafe fn on_interrupt() {
211 // Clear IRQ flags 22 // Clear IRQ flags
212 pac::FLASH.sr().write(|w| { 23 pac::FLASH.sr().write(|w| {
@@ -469,7 +280,7 @@ fn pa12_is_output_pull_low() -> bool {
469 use pac::GPIOA; 280 use pac::GPIOA;
470 const PIN: usize = 12; 281 const PIN: usize = 12;
471 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT 282 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
472 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN 283 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN
473 && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW 284 && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
474} 285}
475 286
@@ -485,71 +296,83 @@ mod tests {
485 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; 296 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
486 const LARGE_SECTOR_SIZE: u32 = 128 * 1024; 297 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
487 298
488 let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| { 299 if !cfg!(feature = "dual-bank") {
489 let sector = get_sector(address, &FLASH_REGIONS); 300 let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| {
490 assert_eq!(snb, sector.snb()); 301 let sector = get_sector(address, crate::flash::get_flash_regions());
491 assert_eq!( 302 assert_eq!(snb, sector.snb());
492 FlashSector { 303 assert_eq!(
493 bank: FlashBank::Bank1, 304 FlashSector {
494 index_in_bank, 305 bank: sector.bank,
495 start, 306 index_in_bank,
496 size 307 start,
497 }, 308 size
498 sector 309 },
499 ); 310 sector
500 }; 311 );
501 312 };
502 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); 313
503 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); 314 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
504 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); 315 assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
505 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); 316 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
506 317 assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
507 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); 318
508 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); 319 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
509 320 assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
510 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); 321
511 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); 322 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
512 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); 323 assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
513 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); 324 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
514 325 assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
515 let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { 326 } else {
516 let sector = get_sector(address, &ALT_FLASH_REGIONS); 327 let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| {
517 assert_eq!(snb, sector.snb()); 328 let sector = get_sector(address, crate::flash::get_flash_regions());
518 assert_eq!( 329 assert_eq!(snb, sector.snb());
519 FlashSector { 330 assert_eq!(
520 bank, 331 FlashSector {
521 index_in_bank, 332 bank,
522 start, 333 index_in_bank,
523 size 334 start,
524 }, 335 size
525 sector 336 },
526 ) 337 sector
527 }; 338 )
528 339 };
529 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); 340
530 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); 341 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
531 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); 342 assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
532 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); 343 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
533 344 assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
534 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); 345
535 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); 346 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000);
536 347 assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF);
537 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); 348
538 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); 349 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
539 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); 350 assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
540 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); 351 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000);
541 352 assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF);
542 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); 353
543 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); 354 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000);
544 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); 355 assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF);
545 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); 356 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000);
546 357 assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF);
547 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); 358
548 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); 359 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000);
549 360 assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF);
550 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); 361
551 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); 362 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000);
552 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); 363 assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF);
553 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); 364 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
365 assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
366 }
367 }
368}
369
370#[cfg(all(bank_setup_configurable))]
371pub(crate) fn check_bank_setup() {
372 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() {
373 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config");
374 }
375 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() {
376 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config");
554 } 377 }
555} 378}
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index 09ebe9db9..0547c747a 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -1,16 +1,14 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool { 8impl FlashSector {
9 true 9 const fn snb(&self) -> u8 {
10} 10 ((self.bank as u8) << 4) + self.index_in_bank
11 11 }
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14} 12}
15 13
16pub(crate) unsafe fn lock() { 14pub(crate) unsafe fn lock() {
@@ -53,7 +51,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
53pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 51pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
54 pac::FLASH.cr().modify(|w| { 52 pac::FLASH.cr().modify(|w| {
55 w.set_ser(true); 53 w.set_ser(true);
56 w.set_snb(sector.index_in_bank) 54 w.set_snb(sector.snb())
57 }); 55 });
58 56
59 pac::FLASH.cr().modify(|w| { 57 pac::FLASH.cr().modify(|w| {
@@ -118,7 +116,7 @@ mod tests {
118 start, 116 start,
119 size 117 size
120 }, 118 },
121 get_sector(address, &FLASH_REGIONS) 119 get_sector(address, crate::flash::get_flash_regions())
122 ) 120 )
123 }; 121 };
124 122
@@ -137,7 +135,7 @@ mod tests {
137 } 135 }
138 136
139 #[test] 137 #[test]
140 #[cfg(stm32f769)] 138 #[cfg(all(stm32f769, feature = "single-bank"))]
141 fn can_get_sector() { 139 fn can_get_sector() {
142 const SMALL_SECTOR_SIZE: u32 = 32 * 1024; 140 const SMALL_SECTOR_SIZE: u32 = 32 * 1024;
143 const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; 141 const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024;
@@ -151,7 +149,7 @@ mod tests {
151 start, 149 start,
152 size 150 size
153 }, 151 },
154 get_sector(address, &FLASH_REGIONS) 152 get_sector(address, crate::flash::get_flash_regions())
155 ) 153 )
156 }; 154 };
157 155
@@ -168,4 +166,61 @@ mod tests {
168 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000); 166 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000);
169 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); 167 assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
170 } 168 }
169
170 #[test]
171 #[cfg(all(stm32f769, feature = "dual-bank"))]
172 fn can_get_sector() {
173 const SMALL_SECTOR_SIZE: u32 = 16 * 1024;
174 const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
175 const LARGE_SECTOR_SIZE: u32 = 128 * 1024;
176
177 let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32, snb: u8, bank: FlashBank| {
178 assert_eq!(
179 FlashSector {
180 bank: bank,
181 index_in_bank,
182 start,
183 size
184 },
185 get_sector(address, crate::flash::get_flash_regions())
186 );
187 assert_eq!(get_sector(address, crate::flash::get_flash_regions()).snb(), snb);
188 };
189
190 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000, 0x00, FlashBank::Bank1);
191 assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF, 0x00, FlashBank::Bank1);
192 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000, 0x03, FlashBank::Bank1);
193 assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF, 0x03, FlashBank::Bank1);
194
195 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000, 0x04, FlashBank::Bank1);
196 assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF, 0x04, FlashBank::Bank1);
197
198 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000, 0x05, FlashBank::Bank1);
199 assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF, 0x05, FlashBank::Bank1);
200 assert_sector(10, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000, 0x0A, FlashBank::Bank1);
201 assert_sector(10, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080D_FFFF, 0x0A, FlashBank::Bank1);
202
203 assert_sector(0, 0x0810_0000, SMALL_SECTOR_SIZE, 0x0810_0000, 0x10, FlashBank::Bank2);
204 assert_sector(0, 0x0810_0000, SMALL_SECTOR_SIZE, 0x0810_3FFF, 0x10, FlashBank::Bank2);
205 assert_sector(3, 0x0810_C000, SMALL_SECTOR_SIZE, 0x0810_C000, 0x13, FlashBank::Bank2);
206 assert_sector(3, 0x0810_C000, SMALL_SECTOR_SIZE, 0x0810_FFFF, 0x13, FlashBank::Bank2);
207
208 assert_sector(4, 0x0811_0000, MEDIUM_SECTOR_SIZE, 0x0811_0000, 0x14, FlashBank::Bank2);
209 assert_sector(4, 0x0811_0000, MEDIUM_SECTOR_SIZE, 0x0811_FFFF, 0x14, FlashBank::Bank2);
210
211 assert_sector(5, 0x0812_0000, LARGE_SECTOR_SIZE, 0x0812_0000, 0x15, FlashBank::Bank2);
212 assert_sector(5, 0x0812_0000, LARGE_SECTOR_SIZE, 0x0813_FFFF, 0x15, FlashBank::Bank2);
213 assert_sector(10, 0x081C_0000, LARGE_SECTOR_SIZE, 0x081C_0000, 0x1A, FlashBank::Bank2);
214 assert_sector(10, 0x081C_0000, LARGE_SECTOR_SIZE, 0x081D_FFFF, 0x1A, FlashBank::Bank2);
215 }
216}
217
218#[cfg(all(bank_setup_configurable))]
219pub(crate) fn check_bank_setup() {
220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() {
221 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config");
222 }
223 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() {
224 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config");
225 }
171} 226}
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs
index 01a0c603f..bc1fd360c 100644
--- a/embassy-stm32/src/flash/g.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -3,24 +3,16 @@ use core::sync::atomic::{fence, Ordering};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 6use super::{FlashSector, WRITE_SIZE};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
10pub(crate) const fn is_default_layout() -> bool {
11 true
12}
13
14pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
16}
17
18pub(crate) unsafe fn lock() { 10pub(crate) unsafe fn lock() {
19 pac::FLASH.cr().modify(|w| w.set_lock(true)); 11 pac::FLASH.cr().modify(|w| w.set_lock(true));
20} 12}
21pub(crate) unsafe fn unlock() { 13pub(crate) unsafe fn unlock() {
22 // Wait, while the memory interface is busy. 14 // Wait, while the memory interface is busy.
23 while pac::FLASH.sr().read().bsy() {} 15 wait_busy();
24 16
25 // Unlock flash 17 // Unlock flash
26 if pac::FLASH.cr().read().lock() { 18 if pac::FLASH.cr().read().lock() {
@@ -53,12 +45,17 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
53 45
54pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
55 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; 47 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
56 while pac::FLASH.sr().read().bsy() {} 48 wait_busy();
57 clear_all_err(); 49 clear_all_err();
58 50
59 interrupt::free(|_| { 51 interrupt::free(|_| {
60 pac::FLASH.cr().modify(|w| { 52 pac::FLASH.cr().modify(|w| {
61 w.set_per(true); 53 w.set_per(true);
54 #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))]
55 w.set_bker(sector.bank == crate::flash::FlashBank::Bank2);
56 #[cfg(flash_g0x0)]
57 w.set_pnb(idx as u16);
58 #[cfg(not(flash_g0x0))]
62 w.set_pnb(idx as u8); 59 w.set_pnb(idx as u8);
63 w.set_strt(true); 60 w.set_strt(true);
64 }); 61 });
@@ -94,3 +91,33 @@ pub(crate) unsafe fn clear_all_err() {
94 // This clears all "write 1 to clear" bits. 91 // This clears all "write 1 to clear" bits.
95 pac::FLASH.sr().modify(|_| {}); 92 pac::FLASH.sr().modify(|_| {});
96} 93}
94
95#[cfg(any(flash_g0x0, flash_g0x1))]
96fn wait_busy() {
97 while pac::FLASH.sr().read().bsy() | pac::FLASH.sr().read().bsy2() {}
98}
99
100#[cfg(not(any(flash_g0x0, flash_g0x1)))]
101fn wait_busy() {
102 while pac::FLASH.sr().read().bsy() {}
103}
104
105#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))]
106pub(crate) fn check_bank_setup() {
107 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
108 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config");
109 }
110 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
111 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config");
112 }
113}
114
115#[cfg(all(bank_setup_configurable, flash_g0x1))]
116pub(crate) fn check_bank_setup() {
117 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() {
118 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config");
119 }
120 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() {
121 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config");
122 }
123}
diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs
new file mode 100644
index 000000000..fd9bfcc75
--- /dev/null
+++ b/embassy-stm32/src/flash/h5.rs
@@ -0,0 +1,166 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering};
3
4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error;
6use crate::pac;
7
8pub(crate) unsafe fn lock() {
9 if !pac::FLASH.nscr().read().lock() {
10 pac::FLASH.nscr().modify(|r| {
11 r.set_lock(true);
12 });
13 }
14}
15
16pub(crate) unsafe fn unlock() {
17 // TODO: check locked first
18 while pac::FLASH.nssr().read().bsy() {
19 #[cfg(feature = "defmt")]
20 defmt::trace!("busy")
21 }
22
23 // only unlock if locked to begin with
24 if pac::FLASH.nscr().read().lock() {
25 pac::FLASH.nskeyr().write_value(0x4567_0123);
26 pac::FLASH.nskeyr().write_value(0xCDEF_89AB);
27 }
28}
29
30pub(crate) unsafe fn enable_blocking_write() {
31 assert_eq!(0, WRITE_SIZE % 4);
32}
33
34pub(crate) unsafe fn disable_blocking_write() {}
35
36pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
37 // // We cannot have the write setup sequence in begin_write as it depends on the address
38 // let bank = if start_address < BANK1_REGION.end() {
39 // pac::FLASH.bank(0)
40 // } else {
41 // pac::FLASH.bank(1)
42 // };
43
44 cortex_m::asm::isb();
45 cortex_m::asm::dsb();
46 fence(Ordering::SeqCst);
47
48 clear_all_err();
49
50 pac::FLASH.nscr().write(|w| {
51 w.set_pg(true);
52 // w.set_psize(2); // 32 bits at once
53 });
54
55 let mut res = None;
56 let mut address = start_address;
57 // TODO: see write size
58 for val in buf.chunks(4) {
59 write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
60 address += val.len() as u32;
61
62 res = Some(blocking_wait_ready().map_err(|e| {
63 error!("write err");
64 e
65 }));
66 pac::FLASH.nssr().modify(|w| {
67 if w.eop() {
68 w.set_eop(true);
69 }
70 });
71 if unwrap!(res).is_err() {
72 break;
73 }
74 }
75
76 cortex_m::asm::isb();
77 cortex_m::asm::dsb();
78 fence(Ordering::SeqCst);
79
80 pac::FLASH.nscr().write(|w| w.set_pg(false));
81
82 unwrap!(res)
83}
84
85pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
86 // pac::FLASH.wrp2r_cur().read().wrpsg()
87 // TODO: write protection check
88 if pac::FLASH.nscr().read().lock() == true {
89 error!("flash locked");
90 }
91
92 loop {
93 let sr = pac::FLASH.nssr().read();
94 if !sr.bsy() && !sr.dbne() {
95 break;
96 }
97 }
98 clear_all_err();
99
100 pac::FLASH.nscr().modify(|r| {
101 // TODO: later check bank swap
102 r.set_bksel(match sector.bank {
103 crate::flash::FlashBank::Bank1 => stm32_metapac::flash::vals::NscrBksel::B_0X0,
104 crate::flash::FlashBank::Bank2 => stm32_metapac::flash::vals::NscrBksel::B_0X1,
105 _ => unreachable!(),
106 });
107 r.set_snb(sector.index_in_bank);
108 r.set_ser(true);
109 });
110
111 pac::FLASH.nscr().modify(|r| {
112 r.set_strt(true);
113 });
114
115 cortex_m::asm::isb();
116 cortex_m::asm::dsb();
117 fence(Ordering::SeqCst);
118
119 let ret: Result<(), Error> = blocking_wait_ready().map_err(|e| {
120 error!("erase err");
121 e
122 });
123
124 pac::FLASH.nscr().modify(|w| w.set_ser(false));
125 clear_all_err();
126 ret
127}
128
129pub(crate) unsafe fn clear_all_err() {
130 pac::FLASH.nssr().modify(|_| {})
131}
132
133unsafe fn blocking_wait_ready() -> Result<(), Error> {
134 loop {
135 let sr = pac::FLASH.nssr().read();
136
137 if !sr.bsy() {
138 if sr.optchangeerr() {
139 error!("optchangeerr");
140 return Err(Error::Prog);
141 }
142 if sr.obkwerr() {
143 error!("obkwerr");
144 return Err(Error::Seq);
145 }
146 if sr.obkerr() {
147 error!("obkerr");
148 return Err(Error::Seq);
149 }
150 if sr.incerr() {
151 error!("incerr");
152 return Err(Error::Unaligned);
153 }
154 if sr.strberr() {
155 error!("strberr");
156 return Err(Error::Parallelism);
157 }
158 if sr.wrperr() {
159 error!("protected");
160 return Err(Error::Protected);
161 }
162
163 return Ok(());
164 }
165 }
166}
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index 82e77d130..f8e210556 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -8,17 +8,9 @@ use cortex_m::interrupt;
8use pac::flash::regs::Nssr; 8use pac::flash::regs::Nssr;
9use pac::flash::vals::Bksel; 9use pac::flash::vals::Bksel;
10 10
11use super::{Error, FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 11use super::{Error, FlashBank, FlashSector, WRITE_SIZE};
12use crate::pac; 12use crate::pac;
13 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() { 14pub(crate) unsafe fn lock() {
23 pac::FLASH.nscr().modify(|w| w.set_lock(true)); 15 pac::FLASH.nscr().modify(|w| w.set_lock(true));
24} 16}
@@ -55,6 +47,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
55} 47}
56 48
57pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 49pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
50 assert!(sector.bank != FlashBank::Otp);
58 assert!(sector.index_in_bank < 8); 51 assert!(sector.index_in_bank < 8);
59 52
60 while busy() {} 53 while busy() {}
@@ -67,6 +60,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
67 (FlashBank::Bank2, true) => Bksel::BANK1, 60 (FlashBank::Bank2, true) => Bksel::BANK1,
68 (FlashBank::Bank2, false) => Bksel::BANK2, 61 (FlashBank::Bank2, false) => Bksel::BANK2,
69 (FlashBank::Bank1, true) => Bksel::BANK2, 62 (FlashBank::Bank1, true) => Bksel::BANK2,
63 _ => unreachable!(),
70 }); 64 });
71 w.set_snb(sector.index_in_bank); 65 w.set_snb(sector.index_in_bank);
72 w.set_ser(true); 66 w.set_ser(true);
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 254915381..f1d84101c 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,22 +1,14 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12const fn is_dual_bank() -> bool { 8const fn is_dual_bank() -> bool {
13 FLASH_REGIONS.len() >= 2 9 FLASH_REGIONS.len() >= 2
14} 10}
15 11
16pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] {
17 &FLASH_REGIONS
18}
19
20pub(crate) unsafe fn lock() { 12pub(crate) unsafe fn lock() {
21 pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true)); 13 pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true));
22 if is_dual_bank() { 14 if is_dual_bank() {
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index a0bfeb395..1b82704ec 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 #[cfg(any(flash_wl, flash_wb, flash_l4))] 9 #[cfg(any(flash_wl, flash_wb, flash_l4))]
18 pac::FLASH.cr().modify(|w| w.set_lock(true)); 10 pac::FLASH.cr().modify(|w| w.set_lock(true));
@@ -23,6 +15,9 @@ pub(crate) unsafe fn lock() {
23 w.set_prglock(true); 15 w.set_prglock(true);
24 w.set_pelock(true); 16 w.set_pelock(true);
25 }); 17 });
18
19 #[cfg(any(flash_l5))]
20 pac::FLASH.nscr().modify(|w| w.set_nslock(true));
26} 21}
27 22
28pub(crate) unsafe fn unlock() { 23pub(crate) unsafe fn unlock() {
@@ -46,6 +41,14 @@ pub(crate) unsafe fn unlock() {
46 pac::FLASH.prgkeyr().write_value(0x1314_1516); 41 pac::FLASH.prgkeyr().write_value(0x1314_1516);
47 } 42 }
48 } 43 }
44
45 #[cfg(any(flash_l5))]
46 {
47 if pac::FLASH.nscr().read().nslock() {
48 pac::FLASH.nskeyr().write_value(0x4567_0123);
49 pac::FLASH.nskeyr().write_value(0xCDEF_89AB);
50 }
51 }
49} 52}
50 53
51pub(crate) unsafe fn enable_blocking_write() { 54pub(crate) unsafe fn enable_blocking_write() {
@@ -53,11 +56,17 @@ pub(crate) unsafe fn enable_blocking_write() {
53 56
54 #[cfg(any(flash_wl, flash_wb, flash_l4))] 57 #[cfg(any(flash_wl, flash_wb, flash_l4))]
55 pac::FLASH.cr().write(|w| w.set_pg(true)); 58 pac::FLASH.cr().write(|w| w.set_pg(true));
59
60 #[cfg(any(flash_l5))]
61 pac::FLASH.nscr().write(|w| w.set_nspg(true));
56} 62}
57 63
58pub(crate) unsafe fn disable_blocking_write() { 64pub(crate) unsafe fn disable_blocking_write() {
59 #[cfg(any(flash_wl, flash_wb, flash_l4))] 65 #[cfg(any(flash_wl, flash_wb, flash_l4))]
60 pac::FLASH.cr().write(|w| w.set_pg(false)); 66 pac::FLASH.cr().write(|w| w.set_pg(false));
67
68 #[cfg(any(flash_l5))]
69 pac::FLASH.nscr().write(|w| w.set_nspg(false));
61} 70}
62 71
63pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 72pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
@@ -84,13 +93,25 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
84 write_volatile(sector.start as *mut u32, 0xFFFFFFFF); 93 write_volatile(sector.start as *mut u32, 0xFFFFFFFF);
85 } 94 }
86 95
87 #[cfg(any(flash_wl, flash_wb, flash_l4))] 96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))]
88 { 97 {
89 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; 98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
90 99
91 #[cfg(flash_l4)] 100 #[cfg(flash_l4)]
92 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; 101 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) };
93 102
103 #[cfg(flash_l5)]
104 let (idx, bank) = if pac::FLASH.optr().read().dbank() {
105 if idx > 255 {
106 (idx - 256, Some(true))
107 } else {
108 (idx, Some(false))
109 }
110 } else {
111 (idx, None)
112 };
113
114 #[cfg(not(flash_l5))]
94 pac::FLASH.cr().modify(|w| { 115 pac::FLASH.cr().modify(|w| {
95 w.set_per(true); 116 w.set_per(true);
96 w.set_pnb(idx as u8); 117 w.set_pnb(idx as u8);
@@ -101,6 +122,16 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
101 #[cfg(any(flash_l4))] 122 #[cfg(any(flash_l4))]
102 w.set_bker(bank); 123 w.set_bker(bank);
103 }); 124 });
125
126 #[cfg(flash_l5)]
127 pac::FLASH.nscr().modify(|w| {
128 w.set_nsper(true);
129 w.set_nspnb(idx as u8);
130 if let Some(bank) = bank {
131 w.set_nsbker(bank);
132 }
133 w.set_nsstrt(true);
134 });
104 } 135 }
105 136
106 let ret: Result<(), Error> = wait_ready_blocking(); 137 let ret: Result<(), Error> = wait_ready_blocking();
@@ -108,6 +139,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
108 #[cfg(any(flash_wl, flash_wb, flash_l4))] 139 #[cfg(any(flash_wl, flash_wb, flash_l4))]
109 pac::FLASH.cr().modify(|w| w.set_per(false)); 140 pac::FLASH.cr().modify(|w| w.set_per(false));
110 141
142 #[cfg(any(flash_l5))]
143 pac::FLASH.nscr().modify(|w| w.set_nsper(false));
144
111 #[cfg(any(flash_l0, flash_l1))] 145 #[cfg(any(flash_l0, flash_l1))]
112 pac::FLASH.pecr().modify(|w| { 146 pac::FLASH.pecr().modify(|w| {
113 w.set_erase(false); 147 w.set_erase(false);
@@ -121,42 +155,98 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
121pub(crate) unsafe fn clear_all_err() { 155pub(crate) unsafe fn clear_all_err() {
122 // read and write back the same value. 156 // read and write back the same value.
123 // This clears all "write 1 to clear" bits. 157 // This clears all "write 1 to clear" bits.
158 #[cfg(not(flash_l5))]
124 pac::FLASH.sr().modify(|_| {}); 159 pac::FLASH.sr().modify(|_| {});
160
161 #[cfg(flash_l5)]
162 pac::FLASH.nssr().modify(|_| {});
125} 163}
126 164
127unsafe fn wait_ready_blocking() -> Result<(), Error> { 165pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
128 loop { 166 loop {
129 let sr = pac::FLASH.sr().read(); 167 #[cfg(not(flash_l5))]
130 168 {
131 if !sr.bsy() { 169 let sr = pac::FLASH.sr().read();
132 #[cfg(any(flash_wl, flash_wb, flash_l4))] 170
133 if sr.progerr() { 171 if !sr.bsy() {
134 return Err(Error::Prog); 172 #[cfg(any(flash_wl, flash_wb, flash_l4))]
173 if sr.progerr() {
174 return Err(Error::Prog);
175 }
176
177 if sr.wrperr() {
178 return Err(Error::Protected);
179 }
180
181 if sr.pgaerr() {
182 return Err(Error::Unaligned);
183 }
184
185 if sr.sizerr() {
186 return Err(Error::Size);
187 }
188
189 #[cfg(any(flash_wl, flash_wb, flash_l4))]
190 if sr.miserr() {
191 return Err(Error::Miss);
192 }
193
194 #[cfg(any(flash_wl, flash_wb, flash_l4))]
195 if sr.pgserr() {
196 return Err(Error::Seq);
197 }
198
199 return Ok(());
135 } 200 }
201 }
136 202
137 if sr.wrperr() { 203 #[cfg(flash_l5)]
138 return Err(Error::Protected); 204 {
139 } 205 let nssr = pac::FLASH.nssr().read();
140 206
141 if sr.pgaerr() { 207 if !nssr.nsbsy() {
142 return Err(Error::Unaligned); 208 if nssr.nsprogerr() {
143 } 209 return Err(Error::Prog);
210 }
144 211
145 if sr.sizerr() { 212 if nssr.nswrperr() {
146 return Err(Error::Size); 213 return Err(Error::Protected);
147 } 214 }
148 215
149 #[cfg(any(flash_wl, flash_wb, flash_l4))] 216 if nssr.nspgaerr() {
150 if sr.miserr() { 217 return Err(Error::Unaligned);
151 return Err(Error::Miss); 218 }
152 }
153 219
154 #[cfg(any(flash_wl, flash_wb, flash_l4))] 220 if nssr.nssizerr() {
155 if sr.pgserr() { 221 return Err(Error::Size);
156 return Err(Error::Seq); 222 }
157 } 223
224 if nssr.nspgserr() {
225 return Err(Error::Seq);
226 }
158 227
159 return Ok(()); 228 return Ok(());
229 }
160 } 230 }
161 } 231 }
162} 232}
233
234#[cfg(all(bank_setup_configurable, flash_l5))]
235pub(crate) fn check_bank_setup() {
236 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
237 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config");
238 }
239 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
240 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config");
241 }
242}
243
244#[cfg(all(bank_setup_configurable, flash_l4))]
245pub(crate) fn check_bank_setup() {
246 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() {
247 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config");
248 }
249 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() {
250 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config");
251 }
252}
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index ce2d1a04c..a3f9e00f7 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -5,27 +5,25 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
5mod asynch; 5mod asynch;
6#[cfg(flash)] 6#[cfg(flash)]
7mod common; 7mod common;
8#[cfg(eeprom)]
9mod eeprom;
8 10
9#[cfg(flash_f4)] 11#[cfg(flash_f4)]
10pub use asynch::InterruptHandler; 12pub use asynch::InterruptHandler;
11#[cfg(flash)] 13#[cfg(flash)]
12pub use common::*; 14pub use common::*;
15#[cfg(eeprom)]
16#[allow(unused_imports)]
17pub use eeprom::*;
13 18
14pub use crate::_generated::flash_regions::*; 19pub use crate::_generated::flash_regions::*;
15pub use crate::_generated::MAX_ERASE_SIZE; 20#[cfg(eeprom)]
16pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; 21pub use crate::_generated::{EEPROM_BASE, EEPROM_SIZE};
17 22pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE};
18/// Get whether the default flash layout is being used.
19///
20/// In some chips, dual-bank is not default. This will then return `false`
21/// when dual-bank is enabled.
22pub fn is_default_layout() -> bool {
23 family::is_default_layout()
24}
25 23
26/// Get all flash regions. 24/// Get all flash regions.
27pub fn get_flash_regions() -> &'static [&'static FlashRegion] { 25pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
28 family::get_flash_regions() 26 &FLASH_REGIONS
29} 27}
30 28
31/// Read size (always 1) 29/// Read size (always 1)
@@ -89,23 +87,29 @@ pub enum FlashBank {
89 Bank1 = 0, 87 Bank1 = 0,
90 /// Bank 2 88 /// Bank 2
91 Bank2 = 1, 89 Bank2 = 1,
90 /// OTP region,
91 Otp,
92} 92}
93 93#[cfg(all(eeprom, not(any(flash_l0, flash_l1))))]
94#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] 94compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is an unsupported configuration.");
95#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")]
95#[cfg_attr(flash_f0, path = "f0.rs")] 96#[cfg_attr(flash_f0, path = "f0.rs")]
96#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] 97#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")]
98#[cfg_attr(flash_f2, path = "f2.rs")]
97#[cfg_attr(flash_f4, path = "f4.rs")] 99#[cfg_attr(flash_f4, path = "f4.rs")]
98#[cfg_attr(flash_f7, path = "f7.rs")] 100#[cfg_attr(flash_f7, path = "f7.rs")]
99#[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] 101#[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")]
100#[cfg_attr(flash_h7, path = "h7.rs")] 102#[cfg_attr(flash_h7, path = "h7.rs")]
101#[cfg_attr(flash_h7ab, path = "h7.rs")] 103#[cfg_attr(flash_h7ab, path = "h7.rs")]
102#[cfg_attr(flash_u5, path = "u5.rs")] 104#[cfg_attr(flash_u5, path = "u5.rs")]
105#[cfg_attr(flash_h5, path = "h5.rs")]
103#[cfg_attr(flash_h50, path = "h50.rs")] 106#[cfg_attr(flash_h50, path = "h50.rs")]
104#[cfg_attr(flash_u0, path = "u0.rs")] 107#[cfg_attr(flash_u0, path = "u0.rs")]
105#[cfg_attr( 108#[cfg_attr(
106 not(any( 109 not(any(
107 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, 110 flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4,
108 flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 111 flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5,
112 flash_h50, flash_u0, flash_h5,
109 )), 113 )),
110 path = "other.rs" 114 path = "other.rs"
111)] 115)]
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
index 20f84a72f..293a79be3 100644
--- a/embassy-stm32/src/flash/other.rs
+++ b/embassy-stm32/src/flash/other.rs
@@ -1,14 +1,6 @@
1#![allow(unused)] 1#![allow(unused)]
2 2
3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 3use super::{Error, FlashSector, WRITE_SIZE};
4
5pub(crate) const fn is_default_layout() -> bool {
6 true
7}
8
9pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS
11}
12 4
13pub(crate) unsafe fn lock() { 5pub(crate) unsafe fn lock() {
14 unimplemented!(); 6 unimplemented!();
diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs
index bfdbd15a5..68d847eca 100644
--- a/embassy-stm32/src/flash/u0.rs
+++ b/embassy-stm32/src/flash/u0.rs
@@ -3,18 +3,10 @@ use core::sync::atomic::{fence, Ordering};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
6use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 6use super::{FlashSector, WRITE_SIZE};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
10pub(crate) const fn is_default_layout() -> bool {
11 true
12}
13
14pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
15 &FLASH_REGIONS
16}
17
18pub(crate) unsafe fn lock() { 10pub(crate) unsafe fn lock() {
19 pac::FLASH.cr().modify(|w| w.set_lock(true)); 11 pac::FLASH.cr().modify(|w| w.set_lock(true));
20} 12}
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index 0601017ce..131caa195 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -1,18 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
3 3
4use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 4use super::{FlashBank, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub(crate) const fn is_default_layout() -> bool {
9 true
10}
11
12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS
14}
15
16pub(crate) unsafe fn lock() { 8pub(crate) unsafe fn lock() {
17 #[cfg(feature = "trustzone-secure")] 9 #[cfg(feature = "trustzone-secure")]
18 pac::FLASH.seccr().modify(|w| w.set_lock(true)); 10 pac::FLASH.seccr().modify(|w| w.set_lock(true));
@@ -70,12 +62,24 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
70 #[cfg(feature = "trustzone-secure")] 62 #[cfg(feature = "trustzone-secure")]
71 pac::FLASH.seccr().modify(|w| { 63 pac::FLASH.seccr().modify(|w| {
72 w.set_per(pac::flash::vals::SeccrPer::B_0X1); 64 w.set_per(pac::flash::vals::SeccrPer::B_0X1);
73 w.set_pnb(sector.index_in_bank) 65 w.set_pnb(sector.index_in_bank);
66 // TODO: add check for bank swap
67 w.set_bker(match sector.bank {
68 FlashBank::Bank1 => pac::flash::vals::SeccrBker::B_0X0,
69 FlashBank::Bank2 => pac::flash::vals::SeccrBker::B_0X1,
70 _ => unreachable!(),
71 });
74 }); 72 });
75 #[cfg(not(feature = "trustzone-secure"))] 73 #[cfg(not(feature = "trustzone-secure"))]
76 pac::FLASH.nscr().modify(|w| { 74 pac::FLASH.nscr().modify(|w| {
77 w.set_per(pac::flash::vals::NscrPer::B_0X1); 75 w.set_per(pac::flash::vals::NscrPer::B_0X1);
78 w.set_pnb(sector.index_in_bank) 76 w.set_pnb(sector.index_in_bank);
77 // TODO: add check for bank swap
78 w.set_bker(match sector.bank {
79 FlashBank::Bank1 => pac::flash::vals::NscrBker::B_0X0,
80 FlashBank::Bank2 => pac::flash::vals::NscrBker::B_0X1,
81 _ => unreachable!(),
82 });
79 }); 83 });
80 84
81 #[cfg(feature = "trustzone-secure")] 85 #[cfg(feature = "trustzone-secure")]
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index 83b49a3dd..71ca775cb 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -1,10 +1,10 @@
1//! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC) 1//! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC)
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3 3
4use embassy_hal_internal::into_ref; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::gpio::{AfType, OutputType, Pull, Speed}; 6use crate::gpio::{AfType, OutputType, Pull, Speed};
7use crate::{rcc, Peripheral}; 7use crate::{rcc, Peri};
8 8
9/// FMC driver 9/// FMC driver
10pub struct Fmc<'d, T: Instance> { 10pub struct Fmc<'d, T: Instance> {
@@ -21,7 +21,7 @@ where
21 /// 21 ///
22 /// **Note:** This is currently used to provide access to some basic FMC functions 22 /// **Note:** This is currently used to provide access to some basic FMC functions
23 /// for manual configuration for memory types that stm32-fmc does not support. 23 /// for manual configuration for memory types that stm32-fmc does not support.
24 pub fn new_raw(_instance: impl Peripheral<P = T> + 'd) -> Self { 24 pub fn new_raw(_instance: Peri<'d, T>) -> Self {
25 Self { peri: PhantomData } 25 Self { peri: PhantomData }
26 } 26 }
27 27
@@ -74,8 +74,7 @@ where
74 74
75macro_rules! config_pins { 75macro_rules! config_pins {
76 ($($pin:ident),*) => { 76 ($($pin:ident),*) => {
77 into_ref!($($pin),*); 77 $(
78 $(
79 $pin.set_as_af($pin.af_num(), AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)); 78 $pin.set_as_af($pin.af_num(), AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up));
80 )* 79 )*
81 }; 80 };
@@ -92,12 +91,12 @@ macro_rules! fmc_sdram_constructor {
92 )) => { 91 )) => {
93 /// Create a new FMC instance. 92 /// Create a new FMC instance.
94 pub fn $name<CHIP: stm32_fmc::SdramChip>( 93 pub fn $name<CHIP: stm32_fmc::SdramChip>(
95 _instance: impl Peripheral<P = T> + 'd, 94 _instance: Peri<'d, T>,
96 $($addr_pin_name: impl Peripheral<P = impl $addr_signal<T>> + 'd),*, 95 $($addr_pin_name: Peri<'d, impl $addr_signal<T>>),*,
97 $($ba_pin_name: impl Peripheral<P = impl $ba_signal<T>> + 'd),*, 96 $($ba_pin_name: Peri<'d, impl $ba_signal<T>>),*,
98 $($d_pin_name: impl Peripheral<P = impl $d_signal<T>> + 'd),*, 97 $($d_pin_name: Peri<'d, impl $d_signal<T>>),*,
99 $($nbl_pin_name: impl Peripheral<P = impl $nbl_signal<T>> + 'd),*, 98 $($nbl_pin_name: Peri<'d, impl $nbl_signal<T>>),*,
100 $($ctrl_pin_name: impl Peripheral<P = impl $ctrl_signal<T>> + 'd),*, 99 $($ctrl_pin_name: Peri<'d, impl $ctrl_signal<T>>),*,
101 chip: CHIP 100 chip: CHIP
102 ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> { 101 ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> {
103 102
@@ -245,7 +244,7 @@ trait SealedInstance: crate::rcc::RccPeripheral {
245 244
246/// FMC instance trait. 245/// FMC instance trait.
247#[allow(private_bounds)] 246#[allow(private_bounds)]
248pub trait Instance: SealedInstance + 'static {} 247pub trait Instance: SealedInstance + PeripheralType + 'static {}
249 248
250foreach_peripheral!( 249foreach_peripheral!(
251 (fmc, $inst:ident) => { 250 (fmc, $inst:ident) => {
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs
index 8ca61bc39..b6ae24ee8 100644
--- a/embassy-stm32/src/fmt.rs
+++ b/embassy-stm32/src/fmt.rs
@@ -7,6 +7,28 @@ use core::fmt::{Debug, Display, LowerHex};
7compile_error!("You may not enable both `defmt` and `log` features."); 7compile_error!("You may not enable both `defmt` and `log` features.");
8 8
9#[collapse_debuginfo(yes)] 9#[collapse_debuginfo(yes)]
10macro_rules! rcc_assert {
11 ($($x:tt)*) => {
12 {
13 #[cfg(not(feature = "unchecked-overclocking"))]
14 {
15 #[cfg(not(feature = "defmt"))]
16 ::core::assert!($($x)*);
17 #[cfg(feature = "defmt")]
18 ::defmt::assert!($($x)*);
19 }
20 #[cfg(feature = "unchecked-overclocking")]
21 {
22 #[cfg(feature = "log")]
23 ::log::warn!("`rcc_assert!` skipped: `unchecked-overclocking` feature is enabled.");
24 #[cfg(feature = "defmt")]
25 ::defmt::warn!("`rcc_assert!` skipped: `unchecked-overclocking` feature is enabled.");
26 }
27 }
28 };
29}
30
31#[collapse_debuginfo(yes)]
10macro_rules! assert { 32macro_rules! assert {
11 ($($x:tt)*) => { 33 ($($x:tt)*) => {
12 { 34 {
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 87519f51e..bb37c4194 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -4,10 +4,10 @@
4use core::convert::Infallible; 4use core::convert::Infallible;
5 5
6use critical_section::CriticalSection; 6use critical_section::CriticalSection;
7use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 7use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
8 8
9use crate::pac::gpio::{self, vals}; 9use crate::pac::gpio::{self, vals};
10use crate::{pac, peripherals, Peripheral}; 10use crate::peripherals;
11 11
12/// GPIO flexible pin. 12/// GPIO flexible pin.
13/// 13///
@@ -15,7 +15,7 @@ use crate::{pac, peripherals, Peripheral};
15/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output 15/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
16/// mode. 16/// mode.
17pub struct Flex<'d> { 17pub struct Flex<'d> {
18 pub(crate) pin: PeripheralRef<'d, AnyPin>, 18 pub(crate) pin: Peri<'d, AnyPin>,
19} 19}
20 20
21impl<'d> Flex<'d> { 21impl<'d> Flex<'d> {
@@ -25,10 +25,9 @@ impl<'d> Flex<'d> {
25 /// before the pin is put into output mode. 25 /// before the pin is put into output mode.
26 /// 26 ///
27 #[inline] 27 #[inline]
28 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self { 28 pub fn new(pin: Peri<'d, impl Pin>) -> Self {
29 into_ref!(pin);
30 // Pin will be in disconnected state. 29 // Pin will be in disconnected state.
31 Self { pin: pin.map_into() } 30 Self { pin: pin.into() }
32 } 31 }
33 32
34 /// Put the pin into input mode. 33 /// Put the pin into input mode.
@@ -61,7 +60,7 @@ impl<'d> Flex<'d> {
61 #[cfg(gpio_v2)] 60 #[cfg(gpio_v2)]
62 { 61 {
63 r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr())); 62 r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr()));
64 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); 63 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL));
65 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); 64 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
66 } 65 }
67 }); 66 });
@@ -82,13 +81,13 @@ impl<'d> Flex<'d> {
82 { 81 {
83 r.cr(n / 8).modify(|w| { 82 r.cr(n / 8).modify(|w| {
84 w.set_mode(n % 8, speed.to_mode()); 83 w.set_mode(n % 8, speed.to_mode());
85 w.set_cnf_out(n % 8, vals::CnfOut::PUSHPULL); 84 w.set_cnf_out(n % 8, vals::CnfOut::PUSH_PULL);
86 }); 85 });
87 } 86 }
88 #[cfg(gpio_v2)] 87 #[cfg(gpio_v2)]
89 { 88 {
90 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); 89 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
91 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); 90 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL));
92 r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr())); 91 r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr()));
93 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); 92 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
94 } 93 }
@@ -112,7 +111,7 @@ impl<'d> Flex<'d> {
112 let r = self.pin.block(); 111 let r = self.pin.block();
113 let n = self.pin.pin() as usize; 112 let n = self.pin.pin() as usize;
114 r.cr(n / 8).modify(|w| w.set_mode(n % 8, speed.to_mode())); 113 r.cr(n / 8).modify(|w| w.set_mode(n % 8, speed.to_mode()));
115 r.cr(n / 8).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPENDRAIN)); 114 r.cr(n / 8).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPEN_DRAIN));
116 }); 115 });
117 116
118 #[cfg(gpio_v2)] 117 #[cfg(gpio_v2)]
@@ -130,7 +129,7 @@ impl<'d> Flex<'d> {
130 let r = self.pin.block(); 129 let r = self.pin.block();
131 let n = self.pin.pin() as usize; 130 let n = self.pin.pin() as usize;
132 r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr())); 131 r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr()));
133 r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN)); 132 r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPEN_DRAIN));
134 r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr())); 133 r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr()));
135 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); 134 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
136 }); 135 });
@@ -253,8 +252,8 @@ impl Pull {
253 const fn to_pupdr(self) -> vals::Pupdr { 252 const fn to_pupdr(self) -> vals::Pupdr {
254 match self { 253 match self {
255 Pull::None => vals::Pupdr::FLOATING, 254 Pull::None => vals::Pupdr::FLOATING,
256 Pull::Up => vals::Pupdr::PULLUP, 255 Pull::Up => vals::Pupdr::PULL_UP,
257 Pull::Down => vals::Pupdr::PULLDOWN, 256 Pull::Down => vals::Pupdr::PULL_DOWN,
258 } 257 }
259 } 258 }
260} 259}
@@ -293,11 +292,11 @@ impl Speed {
293 #[cfg(gpio_v2)] 292 #[cfg(gpio_v2)]
294 const fn to_ospeedr(self: Speed) -> vals::Ospeedr { 293 const fn to_ospeedr(self: Speed) -> vals::Ospeedr {
295 match self { 294 match self {
296 Speed::Low => vals::Ospeedr::LOWSPEED, 295 Speed::Low => vals::Ospeedr::LOW_SPEED,
297 Speed::Medium => vals::Ospeedr::MEDIUMSPEED, 296 Speed::Medium => vals::Ospeedr::MEDIUM_SPEED,
298 #[cfg(not(syscfg_f0))] 297 #[cfg(not(syscfg_f0))]
299 Speed::High => vals::Ospeedr::HIGHSPEED, 298 Speed::High => vals::Ospeedr::HIGH_SPEED,
300 Speed::VeryHigh => vals::Ospeedr::VERYHIGHSPEED, 299 Speed::VeryHigh => vals::Ospeedr::VERY_HIGH_SPEED,
301 } 300 }
302 } 301 }
303} 302}
@@ -310,7 +309,7 @@ pub struct Input<'d> {
310impl<'d> Input<'d> { 309impl<'d> Input<'d> {
311 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. 310 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
312 #[inline] 311 #[inline]
313 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self { 312 pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
314 let mut pin = Flex::new(pin); 313 let mut pin = Flex::new(pin);
315 pin.set_as_input(pull); 314 pin.set_as_input(pull);
316 Self { pin } 315 Self { pin }
@@ -375,7 +374,7 @@ pub struct Output<'d> {
375impl<'d> Output<'d> { 374impl<'d> Output<'d> {
376 /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. 375 /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration.
377 #[inline] 376 #[inline]
378 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed) -> Self { 377 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, speed: Speed) -> Self {
379 let mut pin = Flex::new(pin); 378 let mut pin = Flex::new(pin);
380 match initial_output { 379 match initial_output {
381 Level::High => pin.set_high(), 380 Level::High => pin.set_high(),
@@ -440,7 +439,7 @@ pub struct OutputOpenDrain<'d> {
440impl<'d> OutputOpenDrain<'d> { 439impl<'d> OutputOpenDrain<'d> {
441 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed]. 440 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed].
442 #[inline] 441 #[inline]
443 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed) -> Self { 442 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, speed: Speed) -> Self {
444 let mut pin = Flex::new(pin); 443 let mut pin = Flex::new(pin);
445 match initial_output { 444 match initial_output {
446 Level::High => pin.set_high(), 445 Level::High => pin.set_high(),
@@ -454,7 +453,7 @@ impl<'d> OutputOpenDrain<'d> {
454 /// and [Pull]. 453 /// and [Pull].
455 #[inline] 454 #[inline]
456 #[cfg(gpio_v2)] 455 #[cfg(gpio_v2)]
457 pub fn new_pull(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { 456 pub fn new_pull(pin: Peri<'d, impl Pin>, initial_output: Level, speed: Speed, pull: Pull) -> Self {
458 let mut pin = Flex::new(pin); 457 let mut pin = Flex::new(pin);
459 match initial_output { 458 match initial_output {
460 Level::High => pin.set_high(), 459 Level::High => pin.set_high(),
@@ -539,16 +538,16 @@ impl OutputType {
539 #[cfg(gpio_v1)] 538 #[cfg(gpio_v1)]
540 const fn to_cnf_out(self) -> vals::CnfOut { 539 const fn to_cnf_out(self) -> vals::CnfOut {
541 match self { 540 match self {
542 OutputType::PushPull => vals::CnfOut::ALTPUSHPULL, 541 OutputType::PushPull => vals::CnfOut::ALT_PUSH_PULL,
543 OutputType::OpenDrain => vals::CnfOut::ALTOPENDRAIN, 542 OutputType::OpenDrain => vals::CnfOut::ALT_OPEN_DRAIN,
544 } 543 }
545 } 544 }
546 545
547 #[cfg(gpio_v2)] 546 #[cfg(gpio_v2)]
548 const fn to_ot(self) -> vals::Ot { 547 const fn to_ot(self) -> vals::Ot {
549 match self { 548 match self {
550 OutputType::PushPull => vals::Ot::PUSHPULL, 549 OutputType::PushPull => vals::Ot::PUSH_PULL,
551 OutputType::OpenDrain => vals::Ot::OPENDRAIN, 550 OutputType::OpenDrain => vals::Ot::OPEN_DRAIN,
552 } 551 }
553 } 552 }
554} 553}
@@ -624,8 +623,8 @@ impl AfType {
624 pub const fn input(pull: Pull) -> Self { 623 pub const fn input(pull: Pull) -> Self {
625 Self { 624 Self {
626 pupdr: pull.to_pupdr(), 625 pupdr: pull.to_pupdr(),
627 ot: vals::Ot::PUSHPULL, 626 ot: vals::Ot::PUSH_PULL,
628 ospeedr: vals::Ospeedr::LOWSPEED, 627 ospeedr: vals::Ospeedr::LOW_SPEED,
629 } 628 }
630 } 629 }
631 630
@@ -659,6 +658,16 @@ fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) {
659} 658}
660 659
661#[inline(never)] 660#[inline(never)]
661#[cfg(gpio_v2)]
662fn set_speed(pin_port: u8, speed: Speed) {
663 let pin = unsafe { AnyPin::steal(pin_port) };
664 let r = pin.block();
665 let n = pin._pin() as usize;
666
667 r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr()));
668}
669
670#[inline(never)]
662fn set_as_analog(pin_port: u8) { 671fn set_as_analog(pin_port: u8) {
663 let pin = unsafe { AnyPin::steal(pin_port) }; 672 let pin = unsafe { AnyPin::steal(pin_port) };
664 let r = pin.block(); 673 let r = pin.block();
@@ -695,8 +704,8 @@ fn get_pull(pin_port: u8) -> Pull {
695 #[cfg(gpio_v2)] 704 #[cfg(gpio_v2)]
696 return match r.pupdr().read().pupdr(n) { 705 return match r.pupdr().read().pupdr(n) {
697 vals::Pupdr::FLOATING => Pull::None, 706 vals::Pupdr::FLOATING => Pull::None,
698 vals::Pupdr::PULLDOWN => Pull::Down, 707 vals::Pupdr::PULL_DOWN => Pull::Down,
699 vals::Pupdr::PULLUP => Pull::Up, 708 vals::Pupdr::PULL_UP => Pull::Up,
700 vals::Pupdr::_RESERVED_3 => Pull::None, 709 vals::Pupdr::_RESERVED_3 => Pull::None,
701 }; 710 };
702} 711}
@@ -716,7 +725,7 @@ pub(crate) trait SealedPin {
716 725
717 #[inline] 726 #[inline]
718 fn block(&self) -> gpio::Gpio { 727 fn block(&self) -> gpio::Gpio {
719 pac::GPIO(self._port() as _) 728 crate::_generated::gpio_block(self._port() as _)
720 } 729 }
721 730
722 /// Set the output as high. 731 /// Set the output as high.
@@ -739,6 +748,12 @@ pub(crate) trait SealedPin {
739 } 748 }
740 749
741 #[inline] 750 #[inline]
751 #[cfg(gpio_v2)]
752 fn set_speed(&self, speed: Speed) {
753 set_speed(self.pin_port(), speed)
754 }
755
756 #[inline]
742 fn set_as_analog(&self) { 757 fn set_as_analog(&self) {
743 set_as_analog(self.pin_port()); 758 set_as_analog(self.pin_port());
744 } 759 }
@@ -764,7 +779,7 @@ pub(crate) trait SealedPin {
764 779
765/// GPIO pin trait. 780/// GPIO pin trait.
766#[allow(private_bounds)] 781#[allow(private_bounds)]
767pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static { 782pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
768 /// EXTI channel assigned to this pin. 783 /// EXTI channel assigned to this pin.
769 /// 784 ///
770 /// For example, PC4 uses EXTI4. 785 /// For example, PC4 uses EXTI4.
@@ -782,18 +797,6 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static
782 fn port(&self) -> u8 { 797 fn port(&self) -> u8 {
783 self._port() 798 self._port()
784 } 799 }
785
786 /// Type-erase (degrade) this pin into an `AnyPin`.
787 ///
788 /// This converts pin singletons (`PA5`, `PB6`, ...), which
789 /// are all different types, into the same type. It is useful for
790 /// creating arrays of pins, or avoiding generics.
791 #[inline]
792 fn degrade(self) -> AnyPin {
793 AnyPin {
794 pin_port: self.pin_port(),
795 }
796 }
797} 800}
798 801
799/// Type-erased GPIO pin 802/// Type-erased GPIO pin
@@ -806,8 +809,8 @@ impl AnyPin {
806 /// 809 ///
807 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... 810 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
808 #[inline] 811 #[inline]
809 pub unsafe fn steal(pin_port: u8) -> Self { 812 pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> {
810 Self { pin_port } 813 Peri::new_unchecked(Self { pin_port })
811 } 814 }
812 815
813 #[inline] 816 #[inline]
@@ -819,7 +822,7 @@ impl AnyPin {
819 #[cfg(feature = "unstable-pac")] 822 #[cfg(feature = "unstable-pac")]
820 #[inline] 823 #[inline]
821 pub fn block(&self) -> gpio::Gpio { 824 pub fn block(&self) -> gpio::Gpio {
822 pac::GPIO(self._port() as _) 825 crate::_generated::gpio_block(self._port() as _)
823 } 826 }
824} 827}
825 828
@@ -851,8 +854,10 @@ foreach_pin!(
851 } 854 }
852 855
853 impl From<peripherals::$pin_name> for AnyPin { 856 impl From<peripherals::$pin_name> for AnyPin {
854 fn from(x: peripherals::$pin_name) -> Self { 857 fn from(val: peripherals::$pin_name) -> Self {
855 x.degrade() 858 Self {
859 pin_port: val.pin_port(),
860 }
856 } 861 }
857 } 862 }
858 }; 863 };
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
index 4d4a8ec5b..e62151bb5 100644
--- a/embassy-stm32/src/hash/mod.rs
+++ b/embassy-stm32/src/hash/mod.rs
@@ -8,16 +8,18 @@ use core::ptr;
8#[cfg(hash_v2)] 8#[cfg(hash_v2)]
9use core::task::Poll; 9use core::task::Poll;
10 10
11use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::PeripheralType;
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
13use stm32_metapac::hash::regs::*; 13use stm32_metapac::hash::regs::*;
14 14
15use crate::dma::NoDma;
16#[cfg(hash_v2)] 15#[cfg(hash_v2)]
17use crate::dma::Transfer; 16use crate::dma::ChannelAndRequest;
18use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
18#[cfg(hash_v2)]
19use crate::mode::Async;
20use crate::mode::{Blocking, Mode};
19use crate::peripherals::HASH; 21use crate::peripherals::HASH;
20use crate::{interrupt, pac, peripherals, rcc, Peripheral}; 22use crate::{interrupt, pac, peripherals, rcc, Peri};
21 23
22#[cfg(hash_v1)] 24#[cfg(hash_v1)]
23const NUM_CONTEXT_REGS: usize = 51; 25const NUM_CONTEXT_REGS: usize = 51;
@@ -99,6 +101,7 @@ pub enum DataType {
99 101
100/// Stores the state of the HASH peripheral for suspending/resuming 102/// Stores the state of the HASH peripheral for suspending/resuming
101/// digest calculation. 103/// digest calculation.
104#[derive(Clone)]
102pub struct Context<'c> { 105pub struct Context<'c> {
103 first_word_sent: bool, 106 first_word_sent: bool,
104 key_sent: bool, 107 key_sent: bool,
@@ -116,24 +119,25 @@ pub struct Context<'c> {
116type HmacKey<'k> = Option<&'k [u8]>; 119type HmacKey<'k> = Option<&'k [u8]>;
117 120
118/// HASH driver. 121/// HASH driver.
119pub struct Hash<'d, T: Instance, D = NoDma> { 122pub struct Hash<'d, T: Instance, M: Mode> {
120 _peripheral: PeripheralRef<'d, T>, 123 _peripheral: Peri<'d, T>,
121 #[allow(dead_code)] 124 _phantom: PhantomData<M>,
122 dma: PeripheralRef<'d, D>, 125 #[cfg(hash_v2)]
126 dma: Option<ChannelAndRequest<'d>>,
123} 127}
124 128
125impl<'d, T: Instance, D> Hash<'d, T, D> { 129impl<'d, T: Instance> Hash<'d, T, Blocking> {
126 /// Instantiates, resets, and enables the HASH peripheral. 130 /// Instantiates, resets, and enables the HASH peripheral.
127 pub fn new( 131 pub fn new_blocking(
128 peripheral: impl Peripheral<P = T> + 'd, 132 peripheral: Peri<'d, T>,
129 dma: impl Peripheral<P = D> + 'd,
130 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 133 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
131 ) -> Self { 134 ) -> Self {
132 rcc::enable_and_reset::<HASH>(); 135 rcc::enable_and_reset::<HASH>();
133 into_ref!(peripheral, dma);
134 let instance = Self { 136 let instance = Self {
135 _peripheral: peripheral, 137 _peripheral: peripheral,
136 dma: dma, 138 _phantom: PhantomData,
139 #[cfg(hash_v2)]
140 dma: None,
137 }; 141 };
138 142
139 T::Interrupt::unpend(); 143 T::Interrupt::unpend();
@@ -141,7 +145,9 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
141 145
142 instance 146 instance
143 } 147 }
148}
144 149
150impl<'d, T: Instance, M: Mode> Hash<'d, T, M> {
145 /// Starts computation of a new hash and returns the saved peripheral state. 151 /// Starts computation of a new hash and returns the saved peripheral state.
146 pub fn start<'c>(&mut self, algorithm: Algorithm, format: DataType, key: HmacKey<'c>) -> Context<'c> { 152 pub fn start<'c>(&mut self, algorithm: Algorithm, format: DataType, key: HmacKey<'c>) -> Context<'c> {
147 // Define a context for this new computation. 153 // Define a context for this new computation.
@@ -282,14 +288,135 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
282 self.store_context(ctx); 288 self.store_context(ctx);
283 } 289 }
284 290
291 /// Computes a digest for the given context.
292 /// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
293 /// The largest returned digest size is 128 bytes for SHA-512.
294 /// Panics if the supplied digest buffer is too short.
295 pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize {
296 // Restore the peripheral state.
297 self.load_context(&ctx);
298
299 // Hash the leftover bytes, if any.
300 self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]);
301 ctx.buflen = 0;
302
303 //Start the digest calculation.
304 T::regs().str().write(|w| w.set_dcal(true));
305
306 // Load the HMAC key if provided.
307 if let Some(key) = ctx.key {
308 while !T::regs().sr().read().dinis() {}
309 self.accumulate_blocking(key);
310 T::regs().str().write(|w| w.set_dcal(true));
311 }
312
313 // Block until digest computation is complete.
314 while !T::regs().sr().read().dcis() {}
315
316 // Return the digest.
317 let digest_words = match ctx.algo {
318 Algorithm::SHA1 => 5,
319 #[cfg(any(hash_v1, hash_v2, hash_v4))]
320 Algorithm::MD5 => 4,
321 Algorithm::SHA224 => 7,
322 Algorithm::SHA256 => 8,
323 #[cfg(hash_v3)]
324 Algorithm::SHA384 => 12,
325 #[cfg(hash_v3)]
326 Algorithm::SHA512_224 => 7,
327 #[cfg(hash_v3)]
328 Algorithm::SHA512_256 => 8,
329 #[cfg(hash_v3)]
330 Algorithm::SHA512 => 16,
331 };
332
333 let digest_len_bytes = digest_words * 4;
334 // Panics if the supplied digest buffer is too short.
335 if digest.len() < digest_len_bytes {
336 panic!("Digest buffer must be at least {} bytes long.", digest_words * 4);
337 }
338
339 let mut i = 0;
340 while i < digest_words {
341 let word = T::regs().hr(i).read();
342 digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice());
343 i += 1;
344 }
345 digest_len_bytes
346 }
347
348 /// Push data into the hash core.
349 fn accumulate_blocking(&mut self, input: &[u8]) {
350 // Set the number of valid bits.
351 let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8;
352 T::regs().str().modify(|w| w.set_nblw(num_valid_bits));
353
354 let mut i = 0;
355 while i < input.len() {
356 let mut word: [u8; 4] = [0; 4];
357 let copy_idx = min(i + 4, input.len());
358 word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]);
359 T::regs().din().write_value(u32::from_ne_bytes(word));
360 i += 4;
361 }
362 }
363
364 /// Save the peripheral state to a context.
365 fn store_context<'c>(&mut self, ctx: &mut Context<'c>) {
366 // Block waiting for data in ready.
367 while !T::regs().sr().read().dinis() {}
368
369 // Store peripheral context.
370 ctx.imr = T::regs().imr().read().0;
371 ctx.str = T::regs().str().read().0;
372 ctx.cr = T::regs().cr().read().0;
373 let mut i = 0;
374 while i < NUM_CONTEXT_REGS {
375 ctx.csr[i] = T::regs().csr(i).read();
376 i += 1;
377 }
378 }
379
380 /// Restore the peripheral state from a context.
381 fn load_context(&mut self, ctx: &Context) {
382 // Restore the peripheral state from the context.
383 T::regs().imr().write_value(Imr { 0: ctx.imr });
384 T::regs().str().write_value(Str { 0: ctx.str });
385 T::regs().cr().write_value(Cr { 0: ctx.cr });
386 T::regs().cr().modify(|w| w.set_init(true));
387 let mut i = 0;
388 while i < NUM_CONTEXT_REGS {
389 T::regs().csr(i).write_value(ctx.csr[i]);
390 i += 1;
391 }
392 }
393}
394
395#[cfg(hash_v2)]
396impl<'d, T: Instance> Hash<'d, T, Async> {
397 /// Instantiates, resets, and enables the HASH peripheral.
398 pub fn new(
399 peripheral: Peri<'d, T>,
400 dma: Peri<'d, impl Dma<T>>,
401 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
402 ) -> Self {
403 rcc::enable_and_reset::<HASH>();
404 let instance = Self {
405 _peripheral: peripheral,
406 _phantom: PhantomData,
407 dma: new_dma!(dma),
408 };
409
410 T::Interrupt::unpend();
411 unsafe { T::Interrupt::enable() };
412
413 instance
414 }
415
285 /// Restores the peripheral state using the given context, 416 /// Restores the peripheral state using the given context,
286 /// then updates the state with the provided data. 417 /// then updates the state with the provided data.
287 /// Peripheral state is saved upon return. 418 /// Peripheral state is saved upon return.
288 #[cfg(hash_v2)] 419 pub async fn update(&mut self, ctx: &mut Context<'_>, input: &[u8]) {
289 pub async fn update<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8])
290 where
291 D: crate::hash::Dma<T>,
292 {
293 // Restore the peripheral state. 420 // Restore the peripheral state.
294 self.load_context(&ctx); 421 self.load_context(&ctx);
295 422
@@ -353,68 +480,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
353 /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. 480 /// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
354 /// The largest returned digest size is 128 bytes for SHA-512. 481 /// The largest returned digest size is 128 bytes for SHA-512.
355 /// Panics if the supplied digest buffer is too short. 482 /// Panics if the supplied digest buffer is too short.
356 pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { 483 pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize {
357 // Restore the peripheral state.
358 self.load_context(&ctx);
359
360 // Hash the leftover bytes, if any.
361 self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]);
362 ctx.buflen = 0;
363
364 //Start the digest calculation.
365 T::regs().str().write(|w| w.set_dcal(true));
366
367 // Load the HMAC key if provided.
368 if let Some(key) = ctx.key {
369 while !T::regs().sr().read().dinis() {}
370 self.accumulate_blocking(key);
371 T::regs().str().write(|w| w.set_dcal(true));
372 }
373
374 // Block until digest computation is complete.
375 while !T::regs().sr().read().dcis() {}
376
377 // Return the digest.
378 let digest_words = match ctx.algo {
379 Algorithm::SHA1 => 5,
380 #[cfg(any(hash_v1, hash_v2, hash_v4))]
381 Algorithm::MD5 => 4,
382 Algorithm::SHA224 => 7,
383 Algorithm::SHA256 => 8,
384 #[cfg(hash_v3)]
385 Algorithm::SHA384 => 12,
386 #[cfg(hash_v3)]
387 Algorithm::SHA512_224 => 7,
388 #[cfg(hash_v3)]
389 Algorithm::SHA512_256 => 8,
390 #[cfg(hash_v3)]
391 Algorithm::SHA512 => 16,
392 };
393
394 let digest_len_bytes = digest_words * 4;
395 // Panics if the supplied digest buffer is too short.
396 if digest.len() < digest_len_bytes {
397 panic!("Digest buffer must be at least {} bytes long.", digest_words * 4);
398 }
399
400 let mut i = 0;
401 while i < digest_words {
402 let word = T::regs().hr(i).read();
403 digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice());
404 i += 1;
405 }
406 digest_len_bytes
407 }
408
409 /// Computes a digest for the given context.
410 /// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
411 /// The largest returned digest size is 128 bytes for SHA-512.
412 /// Panics if the supplied digest buffer is too short.
413 #[cfg(hash_v2)]
414 pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize
415 where
416 D: crate::hash::Dma<T>,
417 {
418 // Restore the peripheral state. 484 // Restore the peripheral state.
419 self.load_context(&ctx); 485 self.load_context(&ctx);
420 486
@@ -483,27 +549,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
483 } 549 }
484 550
485 /// Push data into the hash core. 551 /// Push data into the hash core.
486 fn accumulate_blocking(&mut self, input: &[u8]) { 552 async fn accumulate(&mut self, input: &[u8]) {
487 // Set the number of valid bits.
488 let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8;
489 T::regs().str().modify(|w| w.set_nblw(num_valid_bits));
490
491 let mut i = 0;
492 while i < input.len() {
493 let mut word: [u8; 4] = [0; 4];
494 let copy_idx = min(i + 4, input.len());
495 word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]);
496 T::regs().din().write_value(u32::from_ne_bytes(word));
497 i += 4;
498 }
499 }
500
501 /// Push data into the hash core.
502 #[cfg(hash_v2)]
503 async fn accumulate(&mut self, input: &[u8])
504 where
505 D: crate::hash::Dma<T>,
506 {
507 // Ignore an input length of 0. 553 // Ignore an input length of 0.
508 if input.len() == 0 { 554 if input.len() == 0 {
509 return; 555 return;
@@ -514,50 +560,20 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
514 T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); 560 T::regs().str().modify(|w| w.set_nblw(num_valid_bits));
515 561
516 // Configure DMA to transfer input to hash core. 562 // Configure DMA to transfer input to hash core.
517 let dma_request = self.dma.request(); 563 let dst_ptr: *mut u32 = T::regs().din().as_ptr();
518 let dst_ptr = T::regs().din().as_ptr();
519 let mut num_words = input.len() / 4; 564 let mut num_words = input.len() / 4;
520 if input.len() % 4 > 0 { 565 if input.len() % 4 > 0 {
521 num_words += 1; 566 num_words += 1;
522 } 567 }
523 let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); 568 let src_ptr: *const [u8] = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words);
524 let dma_transfer = 569
525 unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; 570 let dma = self.dma.as_mut().unwrap();
571 let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr as *mut u32, Default::default()) };
526 T::regs().cr().modify(|w| w.set_dmae(true)); 572 T::regs().cr().modify(|w| w.set_dmae(true));
527 573
528 // Wait for the transfer to complete. 574 // Wait for the transfer to complete.
529 dma_transfer.await; 575 dma_transfer.await;
530 } 576 }
531
532 /// Save the peripheral state to a context.
533 fn store_context<'c>(&mut self, ctx: &mut Context<'c>) {
534 // Block waiting for data in ready.
535 while !T::regs().sr().read().dinis() {}
536
537 // Store peripheral context.
538 ctx.imr = T::regs().imr().read().0;
539 ctx.str = T::regs().str().read().0;
540 ctx.cr = T::regs().cr().read().0;
541 let mut i = 0;
542 while i < NUM_CONTEXT_REGS {
543 ctx.csr[i] = T::regs().csr(i).read();
544 i += 1;
545 }
546 }
547
548 /// Restore the peripheral state from a context.
549 fn load_context(&mut self, ctx: &Context) {
550 // Restore the peripheral state from the context.
551 T::regs().imr().write_value(Imr { 0: ctx.imr });
552 T::regs().str().write_value(Str { 0: ctx.str });
553 T::regs().cr().write_value(Cr { 0: ctx.cr });
554 T::regs().cr().modify(|w| w.set_init(true));
555 let mut i = 0;
556 while i < NUM_CONTEXT_REGS {
557 T::regs().csr(i).write_value(ctx.csr[i]);
558 i += 1;
559 }
560 }
561} 577}
562 578
563trait SealedInstance { 579trait SealedInstance {
@@ -566,7 +582,7 @@ trait SealedInstance {
566 582
567/// HASH instance trait. 583/// HASH instance trait.
568#[allow(private_bounds)] 584#[allow(private_bounds)]
569pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 585pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send {
570 /// Interrupt for this HASH instance. 586 /// Interrupt for this HASH instance.
571 type Interrupt: interrupt::typelevel::Interrupt; 587 type Interrupt: interrupt::typelevel::Interrupt;
572} 588}
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 13343fc2a..1d0594125 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -4,12 +4,12 @@ mod traits;
4 4
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6 6
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::Peri;
8pub use traits::Instance; 8pub use traits::Instance;
9 9
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::rcc;
11use crate::time::Hertz; 12use crate::time::Hertz;
12use crate::{rcc, Peripheral};
13 13
14/// HRTIM burst controller instance. 14/// HRTIM burst controller instance.
15pub struct BurstController<T: Instance> { 15pub struct BurstController<T: Instance> {
@@ -62,13 +62,13 @@ pub trait AdvancedChannel<T: Instance>: SealedAdvancedChannel<T> {}
62 62
63/// HRTIM PWM pin. 63/// HRTIM PWM pin.
64pub struct PwmPin<'d, T, C> { 64pub struct PwmPin<'d, T, C> {
65 _pin: PeripheralRef<'d, AnyPin>, 65 _pin: Peri<'d, AnyPin>,
66 phantom: PhantomData<(T, C)>, 66 phantom: PhantomData<(T, C)>,
67} 67}
68 68
69/// HRTIM complementary PWM pin. 69/// HRTIM complementary PWM pin.
70pub struct ComplementaryPwmPin<'d, T, C> { 70pub struct ComplementaryPwmPin<'d, T, C> {
71 _pin: PeripheralRef<'d, AnyPin>, 71 _pin: Peri<'d, AnyPin>,
72 phantom: PhantomData<(T, C)>, 72 phantom: PhantomData<(T, C)>,
73} 73}
74 74
@@ -76,8 +76,7 @@ macro_rules! advanced_channel_impl {
76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
77 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { 77 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
78 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 78 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
79 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { 79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
80 into_ref!(pin);
81 critical_section::with(|_| { 80 critical_section::with(|_| {
82 pin.set_low(); 81 pin.set_low();
83 pin.set_as_af( 82 pin.set_as_af(
@@ -86,7 +85,7 @@ macro_rules! advanced_channel_impl {
86 ); 85 );
87 }); 86 });
88 PwmPin { 87 PwmPin {
89 _pin: pin.map_into(), 88 _pin: pin.into(),
90 phantom: PhantomData, 89 phantom: PhantomData,
91 } 90 }
92 } 91 }
@@ -94,8 +93,7 @@ macro_rules! advanced_channel_impl {
94 93
95 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { 94 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
96 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 95 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
97 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<T>> + 'd) -> Self { 96 pub fn $new_chx(pin: Peri<'d, impl $complementary_pin_trait<T>>) -> Self {
98 into_ref!(pin);
99 critical_section::with(|_| { 97 critical_section::with(|_| {
100 pin.set_low(); 98 pin.set_low();
101 pin.set_as_af( 99 pin.set_as_af(
@@ -104,7 +102,7 @@ macro_rules! advanced_channel_impl {
104 ); 102 );
105 }); 103 });
106 ComplementaryPwmPin { 104 ComplementaryPwmPin {
107 _pin: pin.map_into(), 105 _pin: pin.into(),
108 phantom: PhantomData, 106 phantom: PhantomData,
109 } 107 }
110 } 108 }
@@ -129,7 +127,7 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin);
129 127
130/// Struct used to divide a high resolution timer into multiple channels 128/// Struct used to divide a high resolution timer into multiple channels
131pub struct AdvancedPwm<'d, T: Instance> { 129pub struct AdvancedPwm<'d, T: Instance> {
132 _inner: PeripheralRef<'d, T>, 130 _inner: Peri<'d, T>,
133 /// Master instance. 131 /// Master instance.
134 pub master: Master<T>, 132 pub master: Master<T>,
135 /// Burst controller. 133 /// Burst controller.
@@ -154,7 +152,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
154 /// 152 ///
155 /// This splits the HRTIM into its constituent parts, which you can then use individually. 153 /// This splits the HRTIM into its constituent parts, which you can then use individually.
156 pub fn new( 154 pub fn new(
157 tim: impl Peripheral<P = T> + 'd, 155 tim: Peri<'d, T>,
158 _cha: Option<PwmPin<'d, T, ChA<T>>>, 156 _cha: Option<PwmPin<'d, T, ChA<T>>>,
159 _chan: Option<ComplementaryPwmPin<'d, T, ChA<T>>>, 157 _chan: Option<ComplementaryPwmPin<'d, T, ChA<T>>>,
160 _chb: Option<PwmPin<'d, T, ChB<T>>>, 158 _chb: Option<PwmPin<'d, T, ChB<T>>>,
@@ -171,9 +169,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
171 Self::new_inner(tim) 169 Self::new_inner(tim)
172 } 170 }
173 171
174 fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { 172 fn new_inner(tim: Peri<'d, T>) -> Self {
175 into_ref!(tim);
176
177 rcc::enable_and_reset::<T>(); 173 rcc::enable_and_reset::<T>();
178 174
179 #[cfg(stm32f334)] 175 #[cfg(stm32f334)]
@@ -236,8 +232,6 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
236impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { 232impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
237 /// Create a new HRTIM bridge converter driver. 233 /// Create a new HRTIM bridge converter driver.
238 pub fn new(_channel: C, frequency: Hertz) -> Self { 234 pub fn new(_channel: C, frequency: Hertz) -> Self {
239 use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
240
241 T::set_channel_frequency(C::raw(), frequency); 235 T::set_channel_frequency(C::raw(), frequency);
242 236
243 // Always enable preload 237 // Always enable preload
@@ -258,28 +252,16 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
258 // Therefore, software-implemented dead time must be used when setting the duty cycles 252 // Therefore, software-implemented dead time must be used when setting the duty cycles
259 253
260 // Set output 1 to active on a period event 254 // Set output 1 to active on a period event
261 T::regs() 255 T::regs().tim(C::raw()).setr(0).modify(|w| w.set_per(true));
262 .tim(C::raw())
263 .setr(0)
264 .modify(|w| w.set_per(Activeeffect::SETACTIVE));
265 256
266 // Set output 1 to inactive on a compare 1 event 257 // Set output 1 to inactive on a compare 1 event
267 T::regs() 258 T::regs().tim(C::raw()).rstr(0).modify(|w| w.set_cmp(0, true));
268 .tim(C::raw())
269 .rstr(0)
270 .modify(|w| w.set_cmp(0, Inactiveeffect::SETINACTIVE));
271 259
272 // Set output 2 to active on a compare 2 event 260 // Set output 2 to active on a compare 2 event
273 T::regs() 261 T::regs().tim(C::raw()).setr(1).modify(|w| w.set_cmp(1, true));
274 .tim(C::raw())
275 .setr(1)
276 .modify(|w| w.set_cmp(1, Activeeffect::SETACTIVE));
277 262
278 // Set output 2 to inactive on a compare 3 event 263 // Set output 2 to inactive on a compare 3 event
279 T::regs() 264 T::regs().tim(C::raw()).rstr(1).modify(|w| w.set_cmp(2, true));
280 .tim(C::raw())
281 .rstr(1)
282 .modify(|w| w.set_cmp(2, Inactiveeffect::SETINACTIVE));
283 265
284 Self { 266 Self {
285 timer: PhantomData, 267 timer: PhantomData,
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs
index 75f9971e2..6c0661146 100644
--- a/embassy-stm32/src/hrtim/traits.rs
+++ b/embassy-stm32/src/hrtim/traits.rs
@@ -1,3 +1,5 @@
1use embassy_hal_internal::PeripheralType;
2
1use crate::rcc::RccPeripheral; 3use crate::rcc::RccPeripheral;
2use crate::time::Hertz; 4use crate::time::Hertz;
3 5
@@ -153,7 +155,7 @@ pub(crate) trait SealedInstance: RccPeripheral {
153 155
154/// HRTIM instance trait. 156/// HRTIM instance trait.
155#[allow(private_bounds)] 157#[allow(private_bounds)]
156pub trait Instance: SealedInstance + 'static {} 158pub trait Instance: SealedInstance + PeripheralType + 'static {}
157 159
158foreach_interrupt! { 160foreach_interrupt! {
159 ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { 161 ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => {
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index 06ab7a9bc..31527bcdb 100644
--- a/embassy-stm32/src/hsem/mod.rs
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -1,13 +1,14 @@
1//! Hardware Semaphore (HSEM) 1//! Hardware Semaphore (HSEM)
2 2
3use embassy_hal_internal::PeripheralType;
4
5use crate::pac;
6use crate::rcc::RccPeripheral;
3// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. 7// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs.
4// Those MCUs have a different HSEM implementation (Secure semaphore lock support, 8// Those MCUs have a different HSEM implementation (Secure semaphore lock support,
5// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), 9// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute),
6// which is not yet supported by this code. 10// which is not yet supported by this code.
7use embassy_hal_internal::{into_ref, PeripheralRef}; 11use crate::Peri;
8
9use crate::rcc::RccPeripheral;
10use crate::{pac, Peripheral};
11 12
12/// HSEM error. 13/// HSEM error.
13#[derive(Debug)] 14#[derive(Debug)]
@@ -73,13 +74,12 @@ fn core_id_to_index(core: CoreId) -> usize {
73 74
74/// HSEM driver 75/// HSEM driver
75pub struct HardwareSemaphore<'d, T: Instance> { 76pub struct HardwareSemaphore<'d, T: Instance> {
76 _peri: PeripheralRef<'d, T>, 77 _peri: Peri<'d, T>,
77} 78}
78 79
79impl<'d, T: Instance> HardwareSemaphore<'d, T> { 80impl<'d, T: Instance> HardwareSemaphore<'d, T> {
80 /// Creates a new HardwareSemaphore instance. 81 /// Creates a new HardwareSemaphore instance.
81 pub fn new(peripheral: impl Peripheral<P = T> + 'd) -> Self { 82 pub fn new(peripheral: Peri<'d, T>) -> Self {
82 into_ref!(peripheral);
83 HardwareSemaphore { _peri: peripheral } 83 HardwareSemaphore { _peri: peripheral }
84 } 84 }
85 85
@@ -177,7 +177,7 @@ trait SealedInstance {
177 177
178/// HSEM instance trait. 178/// HSEM instance trait.
179#[allow(private_bounds)] 179#[allow(private_bounds)]
180pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} 180pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {}
181 181
182impl SealedInstance for crate::peripherals::HSEM { 182impl SealedInstance for crate::peripherals::HSEM {
183 fn regs() -> crate::pac::hsem::Hsem { 183 fn regs() -> crate::pac::hsem::Hsem {
diff --git a/embassy-stm32/src/hspi/enums.rs b/embassy-stm32/src/hspi/enums.rs
new file mode 100644
index 000000000..83a88f4d9
--- /dev/null
+++ b/embassy-stm32/src/hspi/enums.rs
@@ -0,0 +1,422 @@
1//! Enums used in Hspi configuration.
2
3#[allow(dead_code)]
4#[derive(Copy, Clone)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub(crate) enum HspiMode {
7 IndirectWrite,
8 IndirectRead,
9 AutoPolling,
10 MemoryMapped,
11}
12
13impl Into<u8> for HspiMode {
14 fn into(self) -> u8 {
15 match self {
16 HspiMode::IndirectWrite => 0b00,
17 HspiMode::IndirectRead => 0b01,
18 HspiMode::AutoPolling => 0b10,
19 HspiMode::MemoryMapped => 0b11,
20 }
21 }
22}
23
24/// Hspi lane width
25#[allow(dead_code)]
26#[derive(Copy, Clone)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub enum HspiWidth {
29 /// None
30 NONE,
31 /// Single lane
32 SING,
33 /// Dual lanes
34 DUAL,
35 /// Quad lanes
36 QUAD,
37 /// Eight lanes
38 OCTO,
39 /// Sixteen lanes
40 HEXADECA,
41}
42
43impl Into<u8> for HspiWidth {
44 fn into(self) -> u8 {
45 match self {
46 HspiWidth::NONE => 0b00,
47 HspiWidth::SING => 0b01,
48 HspiWidth::DUAL => 0b10,
49 HspiWidth::QUAD => 0b11,
50 HspiWidth::OCTO => 0b100,
51 HspiWidth::HEXADECA => 0b101,
52 }
53 }
54}
55
56/// Flash bank selection
57#[allow(dead_code)]
58#[derive(Copy, Clone)]
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
60pub enum FlashSelection {
61 /// Bank 1
62 Flash1,
63 /// Bank 2
64 Flash2,
65}
66
67impl Into<bool> for FlashSelection {
68 fn into(self) -> bool {
69 match self {
70 FlashSelection::Flash1 => false,
71 FlashSelection::Flash2 => true,
72 }
73 }
74}
75
76/// Wrap Size
77#[allow(dead_code)]
78#[allow(missing_docs)]
79#[derive(Copy, Clone)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub enum WrapSize {
82 None,
83 _16Bytes,
84 _32Bytes,
85 _64Bytes,
86 _128Bytes,
87}
88
89impl Into<u8> for WrapSize {
90 fn into(self) -> u8 {
91 match self {
92 WrapSize::None => 0x00,
93 WrapSize::_16Bytes => 0x02,
94 WrapSize::_32Bytes => 0x03,
95 WrapSize::_64Bytes => 0x04,
96 WrapSize::_128Bytes => 0x05,
97 }
98 }
99}
100
101/// Memory Type
102#[allow(missing_docs)]
103#[allow(dead_code)]
104#[derive(Copy, Clone)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub enum MemoryType {
107 Micron,
108 Macronix,
109 Standard,
110 MacronixRam,
111 HyperBusMemory,
112 HyperBusRegister,
113}
114
115impl Into<u8> for MemoryType {
116 fn into(self) -> u8 {
117 match self {
118 MemoryType::Micron => 0x00,
119 MemoryType::Macronix => 0x01,
120 MemoryType::Standard => 0x02,
121 MemoryType::MacronixRam => 0x03,
122 MemoryType::HyperBusMemory => 0x04,
123 MemoryType::HyperBusRegister => 0x04,
124 }
125 }
126}
127
128/// Hspi memory size.
129#[allow(missing_docs)]
130#[derive(Copy, Clone)]
131#[cfg_attr(feature = "defmt", derive(defmt::Format))]
132pub enum MemorySize {
133 _1KiB,
134 _2KiB,
135 _4KiB,
136 _8KiB,
137 _16KiB,
138 _32KiB,
139 _64KiB,
140 _128KiB,
141 _256KiB,
142 _512KiB,
143 _1MiB,
144 _2MiB,
145 _4MiB,
146 _8MiB,
147 _16MiB,
148 _32MiB,
149 _64MiB,
150 _128MiB,
151 _256MiB,
152 _512MiB,
153 _1GiB,
154 _2GiB,
155 _4GiB,
156 Other(u8),
157}
158
159impl Into<u8> for MemorySize {
160 fn into(self) -> u8 {
161 match self {
162 MemorySize::_1KiB => 6,
163 MemorySize::_2KiB => 7,
164 MemorySize::_4KiB => 8,
165 MemorySize::_8KiB => 9,
166 MemorySize::_16KiB => 10,
167 MemorySize::_32KiB => 11,
168 MemorySize::_64KiB => 12,
169 MemorySize::_128KiB => 13,
170 MemorySize::_256KiB => 14,
171 MemorySize::_512KiB => 15,
172 MemorySize::_1MiB => 16,
173 MemorySize::_2MiB => 17,
174 MemorySize::_4MiB => 18,
175 MemorySize::_8MiB => 19,
176 MemorySize::_16MiB => 20,
177 MemorySize::_32MiB => 21,
178 MemorySize::_64MiB => 22,
179 MemorySize::_128MiB => 23,
180 MemorySize::_256MiB => 24,
181 MemorySize::_512MiB => 25,
182 MemorySize::_1GiB => 26,
183 MemorySize::_2GiB => 27,
184 MemorySize::_4GiB => 28,
185 MemorySize::Other(val) => val,
186 }
187 }
188}
189
190/// Hspi Address size
191#[derive(Copy, Clone)]
192#[cfg_attr(feature = "defmt", derive(defmt::Format))]
193pub enum AddressSize {
194 /// 8-bit address
195 _8Bit,
196 /// 16-bit address
197 _16Bit,
198 /// 24-bit address
199 _24Bit,
200 /// 32-bit address
201 _32Bit,
202}
203
204impl Into<u8> for AddressSize {
205 fn into(self) -> u8 {
206 match self {
207 AddressSize::_8Bit => 0b00,
208 AddressSize::_16Bit => 0b01,
209 AddressSize::_24Bit => 0b10,
210 AddressSize::_32Bit => 0b11,
211 }
212 }
213}
214
215/// Time the Chip Select line stays high.
216#[allow(missing_docs)]
217#[derive(Copy, Clone)]
218#[cfg_attr(feature = "defmt", derive(defmt::Format))]
219pub enum ChipSelectHighTime {
220 _1Cycle,
221 _2Cycle,
222 _3Cycle,
223 _4Cycle,
224 _5Cycle,
225 _6Cycle,
226 _7Cycle,
227 _8Cycle,
228}
229
230impl Into<u8> for ChipSelectHighTime {
231 fn into(self) -> u8 {
232 match self {
233 ChipSelectHighTime::_1Cycle => 0,
234 ChipSelectHighTime::_2Cycle => 1,
235 ChipSelectHighTime::_3Cycle => 2,
236 ChipSelectHighTime::_4Cycle => 3,
237 ChipSelectHighTime::_5Cycle => 4,
238 ChipSelectHighTime::_6Cycle => 5,
239 ChipSelectHighTime::_7Cycle => 6,
240 ChipSelectHighTime::_8Cycle => 7,
241 }
242 }
243}
244
245/// FIFO threshold.
246#[allow(missing_docs)]
247#[derive(Copy, Clone)]
248#[cfg_attr(feature = "defmt", derive(defmt::Format))]
249pub enum FIFOThresholdLevel {
250 _1Bytes,
251 _2Bytes,
252 _3Bytes,
253 _4Bytes,
254 _5Bytes,
255 _6Bytes,
256 _7Bytes,
257 _8Bytes,
258 _9Bytes,
259 _10Bytes,
260 _11Bytes,
261 _12Bytes,
262 _13Bytes,
263 _14Bytes,
264 _15Bytes,
265 _16Bytes,
266 _17Bytes,
267 _18Bytes,
268 _19Bytes,
269 _20Bytes,
270 _21Bytes,
271 _22Bytes,
272 _23Bytes,
273 _24Bytes,
274 _25Bytes,
275 _26Bytes,
276 _27Bytes,
277 _28Bytes,
278 _29Bytes,
279 _30Bytes,
280 _31Bytes,
281 _32Bytes,
282}
283
284impl Into<u8> for FIFOThresholdLevel {
285 fn into(self) -> u8 {
286 match self {
287 FIFOThresholdLevel::_1Bytes => 0,
288 FIFOThresholdLevel::_2Bytes => 1,
289 FIFOThresholdLevel::_3Bytes => 2,
290 FIFOThresholdLevel::_4Bytes => 3,
291 FIFOThresholdLevel::_5Bytes => 4,
292 FIFOThresholdLevel::_6Bytes => 5,
293 FIFOThresholdLevel::_7Bytes => 6,
294 FIFOThresholdLevel::_8Bytes => 7,
295 FIFOThresholdLevel::_9Bytes => 8,
296 FIFOThresholdLevel::_10Bytes => 9,
297 FIFOThresholdLevel::_11Bytes => 10,
298 FIFOThresholdLevel::_12Bytes => 11,
299 FIFOThresholdLevel::_13Bytes => 12,
300 FIFOThresholdLevel::_14Bytes => 13,
301 FIFOThresholdLevel::_15Bytes => 14,
302 FIFOThresholdLevel::_16Bytes => 15,
303 FIFOThresholdLevel::_17Bytes => 16,
304 FIFOThresholdLevel::_18Bytes => 17,
305 FIFOThresholdLevel::_19Bytes => 18,
306 FIFOThresholdLevel::_20Bytes => 19,
307 FIFOThresholdLevel::_21Bytes => 20,
308 FIFOThresholdLevel::_22Bytes => 21,
309 FIFOThresholdLevel::_23Bytes => 22,
310 FIFOThresholdLevel::_24Bytes => 23,
311 FIFOThresholdLevel::_25Bytes => 24,
312 FIFOThresholdLevel::_26Bytes => 25,
313 FIFOThresholdLevel::_27Bytes => 26,
314 FIFOThresholdLevel::_28Bytes => 27,
315 FIFOThresholdLevel::_29Bytes => 28,
316 FIFOThresholdLevel::_30Bytes => 29,
317 FIFOThresholdLevel::_31Bytes => 30,
318 FIFOThresholdLevel::_32Bytes => 31,
319 }
320 }
321}
322
323/// Dummy cycle count
324#[allow(missing_docs)]
325#[derive(Copy, Clone)]
326#[cfg_attr(feature = "defmt", derive(defmt::Format))]
327pub enum DummyCycles {
328 _0,
329 _1,
330 _2,
331 _3,
332 _4,
333 _5,
334 _6,
335 _7,
336 _8,
337 _9,
338 _10,
339 _11,
340 _12,
341 _13,
342 _14,
343 _15,
344 _16,
345 _17,
346 _18,
347 _19,
348 _20,
349 _21,
350 _22,
351 _23,
352 _24,
353 _25,
354 _26,
355 _27,
356 _28,
357 _29,
358 _30,
359 _31,
360}
361
362impl Into<u8> for DummyCycles {
363 fn into(self) -> u8 {
364 match self {
365 DummyCycles::_0 => 0,
366 DummyCycles::_1 => 1,
367 DummyCycles::_2 => 2,
368 DummyCycles::_3 => 3,
369 DummyCycles::_4 => 4,
370 DummyCycles::_5 => 5,
371 DummyCycles::_6 => 6,
372 DummyCycles::_7 => 7,
373 DummyCycles::_8 => 8,
374 DummyCycles::_9 => 9,
375 DummyCycles::_10 => 10,
376 DummyCycles::_11 => 11,
377 DummyCycles::_12 => 12,
378 DummyCycles::_13 => 13,
379 DummyCycles::_14 => 14,
380 DummyCycles::_15 => 15,
381 DummyCycles::_16 => 16,
382 DummyCycles::_17 => 17,
383 DummyCycles::_18 => 18,
384 DummyCycles::_19 => 19,
385 DummyCycles::_20 => 20,
386 DummyCycles::_21 => 21,
387 DummyCycles::_22 => 22,
388 DummyCycles::_23 => 23,
389 DummyCycles::_24 => 24,
390 DummyCycles::_25 => 25,
391 DummyCycles::_26 => 26,
392 DummyCycles::_27 => 27,
393 DummyCycles::_28 => 28,
394 DummyCycles::_29 => 29,
395 DummyCycles::_30 => 30,
396 DummyCycles::_31 => 31,
397 }
398 }
399}
400
401/// Functional mode
402#[allow(missing_docs)]
403#[allow(dead_code)]
404#[derive(Copy, Clone)]
405#[cfg_attr(feature = "defmt", derive(defmt::Format))]
406pub enum FunctionalMode {
407 IndirectWrite,
408 IndirectRead,
409 AutoStatusPolling,
410 MemoryMapped,
411}
412
413impl Into<u8> for FunctionalMode {
414 fn into(self) -> u8 {
415 match self {
416 FunctionalMode::IndirectWrite => 0x00,
417 FunctionalMode::IndirectRead => 0x01,
418 FunctionalMode::AutoStatusPolling => 0x02,
419 FunctionalMode::MemoryMapped => 0x03,
420 }
421 }
422}
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs
new file mode 100644
index 000000000..62bc0e979
--- /dev/null
+++ b/embassy-stm32/src/hspi/mod.rs
@@ -0,0 +1,1007 @@
1//! HSPI Serial Peripheral Interface
2//!
3
4// NOTE: This is a partial implementation of the HSPI driver.
5// It implements only Single and Octal SPI modes, but additional
6// modes can be added as needed following the same pattern and
7// using ospi/mod.rs as a reference.
8
9#![macro_use]
10
11pub mod enums;
12
13use core::marker::PhantomData;
14
15use embassy_embedded_hal::{GetConfig, SetConfig};
16use embassy_hal_internal::{Peri, PeripheralType};
17pub use enums::*;
18
19use crate::dma::{word, ChannelAndRequest};
20use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
21use crate::mode::{Async, Blocking, Mode as PeriMode};
22use crate::pac::hspi::Hspi as Regs;
23use crate::peripherals;
24use crate::rcc::{self, RccPeripheral};
25
26/// HSPI driver config.
27#[derive(Clone, Copy)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub struct Config {
30 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
31 /// or space is available in the FIFO
32 pub fifo_threshold: FIFOThresholdLevel,
33 /// Indicates the type of external device connected
34 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
35 /// Defines the size of the external device connected to the HSPI corresponding
36 /// to the number of address bits required to access the device
37 pub device_size: MemorySize,
38 /// Sets the minimum number of clock cycles that the chip select signal must be held high
39 /// between commands
40 pub chip_select_high_time: ChipSelectHighTime,
41 /// Enables the free running clock
42 pub free_running_clock: bool,
43 /// Sets the clock level when the device is not selected
44 pub clock_mode: bool,
45 /// Indicates the wrap size corresponding to the external device configuration
46 pub wrap_size: WrapSize,
47 /// Specified the prescaler factor used for generating the external clock based
48 /// on the AHB clock
49 pub clock_prescaler: u8,
50 /// Allows the delay of 1/2 cycle the data sampling to account for external
51 /// signal delays
52 pub sample_shifting: bool,
53 /// Allows hold to 1/4 cycle the data
54 pub delay_hold_quarter_cycle: bool,
55 /// Enables the transaction boundary feature and defines the boundary to release
56 /// the chip select
57 pub chip_select_boundary: u8,
58 /// Enables the delay block bypass so the sampling is not affected by the delay block
59 pub delay_block_bypass: bool,
60 /// Enables communication regulation feature. Chip select is released when the other
61 /// HSPI requests access to the bus
62 pub max_transfer: u8,
63 /// Enables the refresh feature, chip select is released every refresh + 1 clock cycles
64 pub refresh: u32,
65}
66
67impl Default for Config {
68 fn default() -> Self {
69 Self {
70 fifo_threshold: FIFOThresholdLevel::_16Bytes,
71 memory_type: MemoryType::Micron,
72 device_size: MemorySize::Other(0),
73 chip_select_high_time: ChipSelectHighTime::_5Cycle,
74 free_running_clock: false,
75 clock_mode: false,
76 wrap_size: WrapSize::None,
77 clock_prescaler: 0,
78 sample_shifting: false,
79 delay_hold_quarter_cycle: false,
80 chip_select_boundary: 0, // Acceptable range 0 to 31
81 delay_block_bypass: true,
82 max_transfer: 0,
83 refresh: 0,
84 }
85 }
86}
87
88/// HSPI transfer configuration.
89pub struct TransferConfig {
90 /// Instruction width (IMODE)
91 pub iwidth: HspiWidth,
92 /// Instruction Id
93 pub instruction: Option<u32>,
94 /// Number of Instruction Bytes
95 pub isize: AddressSize,
96 /// Instruction Double Transfer rate enable
97 pub idtr: bool,
98
99 /// Address width (ADMODE)
100 pub adwidth: HspiWidth,
101 /// Device memory address
102 pub address: Option<u32>,
103 /// Number of Address Bytes
104 pub adsize: AddressSize,
105 /// Address Double Transfer rate enable
106 pub addtr: bool,
107
108 /// Alternate bytes width (ABMODE)
109 pub abwidth: HspiWidth,
110 /// Alternate Bytes
111 pub alternate_bytes: Option<u32>,
112 /// Number of Alternate Bytes
113 pub absize: AddressSize,
114 /// Alternate Bytes Double Transfer rate enable
115 pub abdtr: bool,
116
117 /// Data width (DMODE)
118 pub dwidth: HspiWidth,
119 /// Data buffer
120 pub ddtr: bool,
121
122 /// Number of dummy cycles (DCYC)
123 pub dummy: DummyCycles,
124}
125
126impl Default for TransferConfig {
127 fn default() -> Self {
128 Self {
129 iwidth: HspiWidth::NONE,
130 instruction: None,
131 isize: AddressSize::_8Bit,
132 idtr: false,
133
134 adwidth: HspiWidth::NONE,
135 address: None,
136 adsize: AddressSize::_8Bit,
137 addtr: false,
138
139 abwidth: HspiWidth::NONE,
140 alternate_bytes: None,
141 absize: AddressSize::_8Bit,
142 abdtr: false,
143
144 dwidth: HspiWidth::NONE,
145 ddtr: false,
146
147 dummy: DummyCycles::_0,
148 }
149 }
150}
151
152/// Error used for HSPI implementation
153#[derive(Debug)]
154#[cfg_attr(feature = "defmt", derive(defmt::Format))]
155pub enum HspiError {
156 /// Peripheral configuration is invalid
157 InvalidConfiguration,
158 /// Operation configuration is invalid
159 InvalidCommand,
160 /// Size zero buffer passed to instruction
161 EmptyBuffer,
162}
163
164/// HSPI driver.
165pub struct Hspi<'d, T: Instance, M: PeriMode> {
166 _peri: Peri<'d, T>,
167 sck: Option<Peri<'d, AnyPin>>,
168 d0: Option<Peri<'d, AnyPin>>,
169 d1: Option<Peri<'d, AnyPin>>,
170 d2: Option<Peri<'d, AnyPin>>,
171 d3: Option<Peri<'d, AnyPin>>,
172 d4: Option<Peri<'d, AnyPin>>,
173 d5: Option<Peri<'d, AnyPin>>,
174 d6: Option<Peri<'d, AnyPin>>,
175 d7: Option<Peri<'d, AnyPin>>,
176 d8: Option<Peri<'d, AnyPin>>,
177 d9: Option<Peri<'d, AnyPin>>,
178 d10: Option<Peri<'d, AnyPin>>,
179 d11: Option<Peri<'d, AnyPin>>,
180 d12: Option<Peri<'d, AnyPin>>,
181 d13: Option<Peri<'d, AnyPin>>,
182 d14: Option<Peri<'d, AnyPin>>,
183 d15: Option<Peri<'d, AnyPin>>,
184 nss: Option<Peri<'d, AnyPin>>,
185 dqs0: Option<Peri<'d, AnyPin>>,
186 dqs1: Option<Peri<'d, AnyPin>>,
187 dma: Option<ChannelAndRequest<'d>>,
188 _phantom: PhantomData<M>,
189 config: Config,
190 width: HspiWidth,
191}
192
193impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
194 /// Enter memory mode.
195 /// The Input `read_config` is used to configure the read operation in memory mode
196 pub fn enable_memory_mapped_mode(
197 &mut self,
198 read_config: TransferConfig,
199 write_config: TransferConfig,
200 ) -> Result<(), HspiError> {
201 // Use configure command to set read config
202 self.configure_command(&read_config, None)?;
203
204 // Set writing configurations, there are separate registers for write configurations in memory mapped mode
205 T::REGS.wccr().modify(|w| {
206 w.set_imode(write_config.iwidth.into());
207 w.set_idtr(write_config.idtr);
208 w.set_isize(write_config.isize.into());
209
210 w.set_admode(write_config.adwidth.into());
211 w.set_addtr(write_config.idtr);
212 w.set_adsize(write_config.adsize.into());
213
214 w.set_dmode(write_config.dwidth.into());
215 w.set_ddtr(write_config.ddtr);
216
217 w.set_abmode(write_config.abwidth.into());
218 w.set_dqse(true);
219 });
220
221 T::REGS.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into()));
222
223 // Enable memory mapped mode
224 T::REGS.cr().modify(|r| {
225 r.set_fmode(FunctionalMode::MemoryMapped.into());
226 r.set_tcen(false);
227 });
228 Ok(())
229 }
230
231 /// Quit from memory mapped mode
232 pub fn disable_memory_mapped_mode(&mut self) {
233 T::REGS.cr().modify(|r| {
234 r.set_fmode(FunctionalMode::IndirectWrite.into());
235 r.set_abort(true);
236 r.set_dmaen(false);
237 r.set_en(false);
238 });
239
240 // Clear transfer complete flag
241 T::REGS.fcr().write(|w| w.set_ctcf(true));
242
243 // Re-enable HSPI
244 T::REGS.cr().modify(|r| {
245 r.set_en(true);
246 });
247 }
248
249 fn new_inner(
250 peri: Peri<'d, T>,
251 d0: Option<Peri<'d, AnyPin>>,
252 d1: Option<Peri<'d, AnyPin>>,
253 d2: Option<Peri<'d, AnyPin>>,
254 d3: Option<Peri<'d, AnyPin>>,
255 d4: Option<Peri<'d, AnyPin>>,
256 d5: Option<Peri<'d, AnyPin>>,
257 d6: Option<Peri<'d, AnyPin>>,
258 d7: Option<Peri<'d, AnyPin>>,
259 d8: Option<Peri<'d, AnyPin>>,
260 d9: Option<Peri<'d, AnyPin>>,
261 d10: Option<Peri<'d, AnyPin>>,
262 d11: Option<Peri<'d, AnyPin>>,
263 d12: Option<Peri<'d, AnyPin>>,
264 d13: Option<Peri<'d, AnyPin>>,
265 d14: Option<Peri<'d, AnyPin>>,
266 d15: Option<Peri<'d, AnyPin>>,
267 sck: Option<Peri<'d, AnyPin>>,
268 nss: Option<Peri<'d, AnyPin>>,
269 dqs0: Option<Peri<'d, AnyPin>>,
270 dqs1: Option<Peri<'d, AnyPin>>,
271 dma: Option<ChannelAndRequest<'d>>,
272 config: Config,
273 width: HspiWidth,
274 dual_memory_mode: bool,
275 ) -> Self {
276 // System configuration
277 rcc::enable_and_reset::<T>();
278
279 // Call this function just to check that the clock for HSPI1 is properly setup
280 let _ = T::frequency();
281
282 while T::REGS.sr().read().busy() {}
283
284 Self::configure_registers(&config, Some(dual_memory_mode));
285
286 Self {
287 _peri: peri,
288 sck,
289 d0,
290 d1,
291 d2,
292 d3,
293 d4,
294 d5,
295 d6,
296 d7,
297 d8,
298 d9,
299 d10,
300 d11,
301 d12,
302 d13,
303 d14,
304 d15,
305 nss,
306 dqs0,
307 dqs1,
308 dma,
309 _phantom: PhantomData,
310 config,
311 width,
312 }
313 }
314
315 fn configure_registers(config: &Config, dual_memory_mode: Option<bool>) {
316 // Device configuration
317 T::REGS.dcr1().modify(|w| {
318 w.set_mtyp(config.memory_type.into());
319 w.set_devsize(config.device_size.into());
320 w.set_csht(config.chip_select_high_time.into());
321 w.set_frck(false);
322 w.set_ckmode(config.clock_mode);
323 w.set_dlybyp(config.delay_block_bypass);
324 });
325
326 T::REGS.dcr2().modify(|w| {
327 w.set_wrapsize(config.wrap_size.into());
328 });
329
330 T::REGS.dcr3().modify(|w| {
331 w.set_csbound(config.chip_select_boundary);
332 w.set_maxtran(config.max_transfer);
333 });
334
335 T::REGS.dcr4().modify(|w| {
336 w.set_refresh(config.refresh);
337 });
338
339 T::REGS.cr().modify(|w| {
340 w.set_fthres(config.fifo_threshold.into());
341 });
342
343 // Wait for busy flag to clear
344 while T::REGS.sr().read().busy() {}
345
346 T::REGS.dcr2().modify(|w| {
347 w.set_prescaler(config.clock_prescaler);
348 });
349
350 // The configuration of clock prescaler trigger automatically a calibration process
351 // So it is necessary to wait the calibration is complete
352 while T::REGS.sr().read().busy() {}
353
354 if let Some(dual_memory_mode) = dual_memory_mode {
355 T::REGS.cr().modify(|w| {
356 w.set_dmm(dual_memory_mode);
357 });
358 }
359
360 T::REGS.tcr().modify(|w| {
361 w.set_sshift(config.sample_shifting);
362 w.set_dhqc(config.delay_hold_quarter_cycle);
363 });
364
365 // Enable peripheral
366 T::REGS.cr().modify(|w| {
367 w.set_en(true);
368 });
369
370 // Free running clock needs to be set after peripheral enable
371 if config.free_running_clock {
372 T::REGS.dcr1().modify(|w| {
373 w.set_frck(config.free_running_clock);
374 });
375 }
376 }
377
378 // Function to configure the peripheral for the requested command
379 fn configure_command(&mut self, command: &TransferConfig, data_len: Option<usize>) -> Result<(), HspiError> {
380 // Check that transaction doesn't use more than hardware initialized pins
381 if <enums::HspiWidth as Into<u8>>::into(command.iwidth) > <enums::HspiWidth as Into<u8>>::into(self.width)
382 || <enums::HspiWidth as Into<u8>>::into(command.adwidth) > <enums::HspiWidth as Into<u8>>::into(self.width)
383 || <enums::HspiWidth as Into<u8>>::into(command.abwidth) > <enums::HspiWidth as Into<u8>>::into(self.width)
384 || <enums::HspiWidth as Into<u8>>::into(command.dwidth) > <enums::HspiWidth as Into<u8>>::into(self.width)
385 {
386 return Err(HspiError::InvalidCommand);
387 }
388
389 while T::REGS.sr().read().busy() {}
390
391 T::REGS.cr().modify(|w| {
392 w.set_fmode(0.into());
393 });
394
395 // Configure alternate bytes
396 if let Some(ab) = command.alternate_bytes {
397 T::REGS.abr().write(|v| v.set_alternate(ab));
398 T::REGS.ccr().modify(|w| {
399 w.set_abmode(command.abwidth.into());
400 w.set_abdtr(command.abdtr);
401 w.set_absize(command.absize.into());
402 })
403 }
404
405 // Configure dummy cycles
406 T::REGS.tcr().modify(|w| {
407 w.set_dcyc(command.dummy.into());
408 });
409
410 // Configure data
411 if let Some(data_length) = data_len {
412 T::REGS.dlr().write(|v| {
413 v.set_dl((data_length - 1) as u32);
414 })
415 } else {
416 T::REGS.dlr().write(|v| {
417 v.set_dl((0) as u32);
418 })
419 }
420
421 // Configure instruction/address/data modes
422 T::REGS.ccr().modify(|w| {
423 w.set_imode(command.iwidth.into());
424 w.set_idtr(command.idtr);
425 w.set_isize(command.isize.into());
426
427 w.set_admode(command.adwidth.into());
428 w.set_addtr(command.addtr);
429 w.set_adsize(command.adsize.into());
430
431 w.set_dmode(command.dwidth.into());
432 w.set_ddtr(command.ddtr);
433 });
434
435 // Configure DQS
436 T::REGS.ccr().modify(|w| {
437 w.set_dqse(command.ddtr && command.instruction.unwrap_or(0) != 0x12ED);
438 });
439
440 // Set information required to initiate transaction
441 if let Some(instruction) = command.instruction {
442 if let Some(address) = command.address {
443 T::REGS.ir().write(|v| {
444 v.set_instruction(instruction);
445 });
446
447 T::REGS.ar().write(|v| {
448 v.set_address(address);
449 });
450 } else {
451 T::REGS.ir().write(|v| {
452 v.set_instruction(instruction);
453 });
454 }
455 } else {
456 if let Some(address) = command.address {
457 T::REGS.ar().write(|v| {
458 v.set_address(address);
459 });
460 } else {
461 // The only single phase transaction supported is instruction only
462 return Err(HspiError::InvalidCommand);
463 }
464 }
465
466 Ok(())
467 }
468
469 /// Function used to control or configure the target device without data transfer
470 pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), HspiError> {
471 // Wait for peripheral to be free
472 while T::REGS.sr().read().busy() {}
473
474 // Need additional validation that command configuration doesn't have data set
475 self.configure_command(command, None)?;
476
477 // Transaction initiated by setting final configuration, i.e the instruction register
478 while !T::REGS.sr().read().tcf() {}
479 T::REGS.fcr().write(|w| {
480 w.set_ctcf(true);
481 });
482
483 Ok(())
484 }
485
486 /// Blocking read with byte by byte data transfer
487 pub fn blocking_read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), HspiError> {
488 if buf.is_empty() {
489 return Err(HspiError::EmptyBuffer);
490 }
491
492 // Wait for peripheral to be free
493 while T::REGS.sr().read().busy() {}
494
495 // Ensure DMA is not enabled for this transaction
496 T::REGS.cr().modify(|w| {
497 w.set_dmaen(false);
498 });
499
500 self.configure_command(&transaction, Some(buf.len()))?;
501
502 let current_address = T::REGS.ar().read().address();
503 let current_instruction = T::REGS.ir().read().instruction();
504
505 // For a indirect read transaction, the transaction begins when the instruction/address is set
506 T::REGS
507 .cr()
508 .modify(|v| v.set_fmode(FunctionalMode::IndirectRead.into()));
509 if T::REGS.ccr().read().admode() == HspiWidth::NONE.into() {
510 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
511 } else {
512 T::REGS.ar().write(|v| v.set_address(current_address));
513 }
514
515 for idx in 0..buf.len() {
516 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
517 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() };
518 }
519
520 while !T::REGS.sr().read().tcf() {}
521 T::REGS.fcr().write(|v| v.set_ctcf(true));
522
523 Ok(())
524 }
525
526 /// Blocking write with byte by byte data transfer
527 pub fn blocking_write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), HspiError> {
528 if buf.is_empty() {
529 return Err(HspiError::EmptyBuffer);
530 }
531
532 // Wait for peripheral to be free
533 while T::REGS.sr().read().busy() {}
534
535 T::REGS.cr().modify(|w| {
536 w.set_dmaen(false);
537 });
538
539 self.configure_command(&transaction, Some(buf.len()))?;
540
541 T::REGS
542 .cr()
543 .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into()));
544
545 for idx in 0..buf.len() {
546 while !T::REGS.sr().read().ftf() {}
547 unsafe { (T::REGS.dr().as_ptr() as *mut W).write_volatile(buf[idx]) };
548 }
549
550 while !T::REGS.sr().read().tcf() {}
551 T::REGS.fcr().write(|v| v.set_ctcf(true));
552
553 Ok(())
554 }
555
556 /// Set new bus configuration
557 pub fn set_config(&mut self, config: &Config) {
558 // Wait for busy flag to clear
559 while T::REGS.sr().read().busy() {}
560
561 // Disable DMA channel while configuring the peripheral
562 T::REGS.cr().modify(|w| {
563 w.set_dmaen(false);
564 });
565
566 Self::configure_registers(config, None);
567
568 self.config = *config;
569 }
570
571 /// Get current configuration
572 pub fn get_config(&self) -> Config {
573 self.config
574 }
575}
576
577impl<'d, T: Instance> Hspi<'d, T, Blocking> {
578 /// Create new blocking HSPI driver for single spi external chip
579 pub fn new_blocking_singlespi(
580 peri: Peri<'d, T>,
581 sck: Peri<'d, impl SckPin<T>>,
582 d0: Peri<'d, impl D0Pin<T>>,
583 d1: Peri<'d, impl D1Pin<T>>,
584 nss: Peri<'d, impl NSSPin<T>>,
585 config: Config,
586 ) -> Self {
587 Self::new_inner(
588 peri,
589 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
590 new_pin!(d1, AfType::input(Pull::None)),
591 None,
592 None,
593 None,
594 None,
595 None,
596 None,
597 None,
598 None,
599 None,
600 None,
601 None,
602 None,
603 None,
604 None,
605 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
606 new_pin!(
607 nss,
608 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
609 ),
610 None,
611 None,
612 None,
613 config,
614 HspiWidth::SING,
615 false,
616 )
617 }
618
619 /// Create new blocking HSPI driver for octospi external chip
620 pub fn new_blocking_octospi(
621 peri: Peri<'d, T>,
622 sck: Peri<'d, impl SckPin<T>>,
623 d0: Peri<'d, impl D0Pin<T>>,
624 d1: Peri<'d, impl D1Pin<T>>,
625 d2: Peri<'d, impl D2Pin<T>>,
626 d3: Peri<'d, impl D3Pin<T>>,
627 d4: Peri<'d, impl D4Pin<T>>,
628 d5: Peri<'d, impl D5Pin<T>>,
629 d6: Peri<'d, impl D6Pin<T>>,
630 d7: Peri<'d, impl D7Pin<T>>,
631 nss: Peri<'d, impl NSSPin<T>>,
632 dqs0: Peri<'d, impl DQS0Pin<T>>,
633 config: Config,
634 ) -> Self {
635 Self::new_inner(
636 peri,
637 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
638 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
639 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
640 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
641 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
642 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
643 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
644 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
645 None,
646 None,
647 None,
648 None,
649 None,
650 None,
651 None,
652 None,
653 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
654 new_pin!(
655 nss,
656 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
657 ),
658 new_pin!(dqs0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
659 None,
660 None,
661 config,
662 HspiWidth::OCTO,
663 false,
664 )
665 }
666}
667
668impl<'d, T: Instance> Hspi<'d, T, Async> {
669 /// Create new HSPI driver for a single spi external chip
670 pub fn new_singlespi(
671 peri: Peri<'d, T>,
672 sck: Peri<'d, impl SckPin<T>>,
673 d0: Peri<'d, impl D0Pin<T>>,
674 d1: Peri<'d, impl D1Pin<T>>,
675 nss: Peri<'d, impl NSSPin<T>>,
676 dma: Peri<'d, impl HspiDma<T>>,
677 config: Config,
678 ) -> Self {
679 Self::new_inner(
680 peri,
681 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
682 new_pin!(d1, AfType::input(Pull::None)),
683 None,
684 None,
685 None,
686 None,
687 None,
688 None,
689 None,
690 None,
691 None,
692 None,
693 None,
694 None,
695 None,
696 None,
697 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
698 new_pin!(
699 nss,
700 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
701 ),
702 None,
703 None,
704 new_dma!(dma),
705 config,
706 HspiWidth::SING,
707 false,
708 )
709 }
710
711 /// Create new HSPI driver for octospi external chip
712 pub fn new_octospi(
713 peri: Peri<'d, T>,
714 sck: Peri<'d, impl SckPin<T>>,
715 d0: Peri<'d, impl D0Pin<T>>,
716 d1: Peri<'d, impl D1Pin<T>>,
717 d2: Peri<'d, impl D2Pin<T>>,
718 d3: Peri<'d, impl D3Pin<T>>,
719 d4: Peri<'d, impl D4Pin<T>>,
720 d5: Peri<'d, impl D5Pin<T>>,
721 d6: Peri<'d, impl D6Pin<T>>,
722 d7: Peri<'d, impl D7Pin<T>>,
723 nss: Peri<'d, impl NSSPin<T>>,
724 dqs0: Peri<'d, impl DQS0Pin<T>>,
725 dma: Peri<'d, impl HspiDma<T>>,
726 config: Config,
727 ) -> Self {
728 Self::new_inner(
729 peri,
730 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
731 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
732 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
733 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
734 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
735 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
736 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
737 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
738 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
739 None,
740 None,
741 None,
742 None,
743 None,
744 None,
745 None,
746 None,
747 new_pin!(
748 nss,
749 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
750 ),
751 new_pin!(dqs0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
752 None,
753 new_dma!(dma),
754 config,
755 HspiWidth::OCTO,
756 false,
757 )
758 }
759
760 /// Blocking read with DMA transfer
761 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), HspiError> {
762 if buf.is_empty() {
763 return Err(HspiError::EmptyBuffer);
764 }
765
766 // Wait for peripheral to be free
767 while T::REGS.sr().read().busy() {}
768
769 self.configure_command(&transaction, Some(buf.len()))?;
770
771 let current_address = T::REGS.ar().read().address();
772 let current_instruction = T::REGS.ir().read().instruction();
773
774 // For a indirect read transaction, the transaction begins when the instruction/address is set
775 T::REGS
776 .cr()
777 .modify(|v| v.set_fmode(FunctionalMode::IndirectRead.into()));
778 if T::REGS.ccr().read().admode() == HspiWidth::NONE.into() {
779 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
780 } else {
781 T::REGS.ar().write(|v| v.set_address(current_address));
782 }
783
784 let transfer = unsafe {
785 self.dma
786 .as_mut()
787 .unwrap()
788 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
789 };
790
791 T::REGS.cr().modify(|w| w.set_dmaen(true));
792
793 transfer.blocking_wait();
794
795 finish_dma(T::REGS);
796
797 Ok(())
798 }
799
800 /// Blocking write with DMA transfer
801 pub fn blocking_write_dma<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), HspiError> {
802 if buf.is_empty() {
803 return Err(HspiError::EmptyBuffer);
804 }
805
806 // Wait for peripheral to be free
807 while T::REGS.sr().read().busy() {}
808
809 self.configure_command(&transaction, Some(buf.len()))?;
810 T::REGS
811 .cr()
812 .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into()));
813
814 let transfer = unsafe {
815 self.dma
816 .as_mut()
817 .unwrap()
818 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
819 };
820
821 T::REGS.cr().modify(|w| w.set_dmaen(true));
822
823 transfer.blocking_wait();
824
825 finish_dma(T::REGS);
826
827 Ok(())
828 }
829
830 /// Asynchronous read from external device
831 pub async fn read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), HspiError> {
832 if buf.is_empty() {
833 return Err(HspiError::EmptyBuffer);
834 }
835
836 // Wait for peripheral to be free
837 while T::REGS.sr().read().busy() {}
838
839 self.configure_command(&transaction, Some(buf.len()))?;
840
841 let current_address = T::REGS.ar().read().address();
842 let current_instruction = T::REGS.ir().read().instruction();
843
844 // For a indirect read transaction, the transaction begins when the instruction/address is set
845 T::REGS
846 .cr()
847 .modify(|v| v.set_fmode(FunctionalMode::IndirectRead.into()));
848 if T::REGS.ccr().read().admode() == HspiWidth::NONE.into() {
849 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
850 } else {
851 T::REGS.ar().write(|v| v.set_address(current_address));
852 }
853
854 let transfer = unsafe {
855 self.dma
856 .as_mut()
857 .unwrap()
858 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
859 };
860
861 T::REGS.cr().modify(|w| w.set_dmaen(true));
862
863 transfer.await;
864
865 finish_dma(T::REGS);
866
867 Ok(())
868 }
869
870 /// Asynchronous write to external device
871 pub async fn write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), HspiError> {
872 if buf.is_empty() {
873 return Err(HspiError::EmptyBuffer);
874 }
875
876 // Wait for peripheral to be free
877 while T::REGS.sr().read().busy() {}
878
879 self.configure_command(&transaction, Some(buf.len()))?;
880 T::REGS
881 .cr()
882 .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into()));
883
884 let transfer = unsafe {
885 self.dma
886 .as_mut()
887 .unwrap()
888 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
889 };
890
891 T::REGS.cr().modify(|w| w.set_dmaen(true));
892
893 transfer.await;
894
895 finish_dma(T::REGS);
896
897 Ok(())
898 }
899}
900
901impl<'d, T: Instance, M: PeriMode> Drop for Hspi<'d, T, M> {
902 fn drop(&mut self) {
903 self.sck.as_ref().map(|x| x.set_as_disconnected());
904 self.d0.as_ref().map(|x| x.set_as_disconnected());
905 self.d1.as_ref().map(|x| x.set_as_disconnected());
906 self.d2.as_ref().map(|x| x.set_as_disconnected());
907 self.d3.as_ref().map(|x| x.set_as_disconnected());
908 self.d4.as_ref().map(|x| x.set_as_disconnected());
909 self.d5.as_ref().map(|x| x.set_as_disconnected());
910 self.d6.as_ref().map(|x| x.set_as_disconnected());
911 self.d7.as_ref().map(|x| x.set_as_disconnected());
912 self.d8.as_ref().map(|x| x.set_as_disconnected());
913 self.d9.as_ref().map(|x| x.set_as_disconnected());
914 self.d10.as_ref().map(|x| x.set_as_disconnected());
915 self.d11.as_ref().map(|x| x.set_as_disconnected());
916 self.d12.as_ref().map(|x| x.set_as_disconnected());
917 self.d13.as_ref().map(|x| x.set_as_disconnected());
918 self.d14.as_ref().map(|x| x.set_as_disconnected());
919 self.d15.as_ref().map(|x| x.set_as_disconnected());
920 self.nss.as_ref().map(|x| x.set_as_disconnected());
921 self.dqs0.as_ref().map(|x| x.set_as_disconnected());
922 self.dqs1.as_ref().map(|x| x.set_as_disconnected());
923
924 rcc::disable::<T>();
925 }
926}
927
928fn finish_dma(regs: Regs) {
929 while !regs.sr().read().tcf() {}
930 regs.fcr().write(|v| v.set_ctcf(true));
931
932 regs.cr().modify(|w| {
933 w.set_dmaen(false);
934 });
935}
936
937/// HSPI instance trait.
938pub(crate) trait SealedInstance {
939 const REGS: Regs;
940}
941
942/// HSPI instance trait.
943#[allow(private_bounds)]
944pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {}
945
946pin_trait!(SckPin, Instance);
947pin_trait!(NckPin, Instance);
948pin_trait!(D0Pin, Instance);
949pin_trait!(D1Pin, Instance);
950pin_trait!(D2Pin, Instance);
951pin_trait!(D3Pin, Instance);
952pin_trait!(D4Pin, Instance);
953pin_trait!(D5Pin, Instance);
954pin_trait!(D6Pin, Instance);
955pin_trait!(D7Pin, Instance);
956pin_trait!(D8Pin, Instance);
957pin_trait!(D9Pin, Instance);
958pin_trait!(D10Pin, Instance);
959pin_trait!(D11Pin, Instance);
960pin_trait!(D12Pin, Instance);
961pin_trait!(D13Pin, Instance);
962pin_trait!(D14Pin, Instance);
963pin_trait!(D15Pin, Instance);
964pin_trait!(DQS0Pin, Instance);
965pin_trait!(DQS1Pin, Instance);
966pin_trait!(NSSPin, Instance);
967dma_trait!(HspiDma, Instance);
968
969foreach_peripheral!(
970 (hspi, $inst:ident) => {
971 impl SealedInstance for peripherals::$inst {
972 const REGS: Regs = crate::pac::$inst;
973 }
974
975 impl Instance for peripherals::$inst {}
976 };
977);
978
979impl<'d, T: Instance, M: PeriMode> SetConfig for Hspi<'d, T, M> {
980 type Config = Config;
981 type ConfigError = ();
982 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
983 self.set_config(config);
984 Ok(())
985 }
986}
987
988impl<'d, T: Instance, M: PeriMode> GetConfig for Hspi<'d, T, M> {
989 type Config = Config;
990 fn get_config(&self) -> Self::Config {
991 self.get_config()
992 }
993}
994
995/// Word sizes usable for HSPI.
996#[allow(private_bounds)]
997pub trait Word: word::Word {}
998
999macro_rules! impl_word {
1000 ($T:ty) => {
1001 impl Word for $T {}
1002 };
1003}
1004
1005impl_word!(u8);
1006impl_word!(u16);
1007impl_word!(u32);
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 2ff21702b..825dd240c 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -12,7 +12,7 @@ use core::iter;
12use core::marker::PhantomData; 12use core::marker::PhantomData;
13 13
14pub use config::*; 14pub use config::*;
15use embassy_hal_internal::{Peripheral, PeripheralRef}; 15use embassy_hal_internal::Peri;
16use embassy_sync::waitqueue::AtomicWaker; 16use embassy_sync::waitqueue::AtomicWaker;
17#[cfg(feature = "time")] 17#[cfg(feature = "time")]
18use embassy_time::{Duration, Instant}; 18use embassy_time::{Duration, Instant};
@@ -47,6 +47,24 @@ pub enum Error {
47 ZeroLengthTransfer, 47 ZeroLengthTransfer,
48} 48}
49 49
50impl core::fmt::Display for Error {
51 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52 let message = match self {
53 Self::Bus => "Bus Error",
54 Self::Arbitration => "Arbitration Lost",
55 Self::Nack => "ACK Not Received",
56 Self::Timeout => "Request Timed Out",
57 Self::Crc => "CRC Mismatch",
58 Self::Overrun => "Buffer Overrun",
59 Self::ZeroLengthTransfer => "Zero-Length Transfers are not allowed",
60 };
61
62 write!(f, "{}", message)
63 }
64}
65
66impl core::error::Error for Error {}
67
50/// I2C modes 68/// I2C modes
51pub mod mode { 69pub mod mode {
52 trait SealedMode {} 70 trait SealedMode {}
@@ -99,8 +117,8 @@ pub enum SendStatus {
99 117
100struct I2CDropGuard<'d> { 118struct I2CDropGuard<'d> {
101 info: &'static Info, 119 info: &'static Info,
102 scl: Option<PeripheralRef<'d, AnyPin>>, 120 scl: Option<Peri<'d, AnyPin>>,
103 sda: Option<PeripheralRef<'d, AnyPin>>, 121 sda: Option<Peri<'d, AnyPin>>,
104} 122}
105impl<'d> Drop for I2CDropGuard<'d> { 123impl<'d> Drop for I2CDropGuard<'d> {
106 fn drop(&mut self) { 124 fn drop(&mut self) {
@@ -132,14 +150,14 @@ pub struct I2c<'d, M: Mode, IM: MasterMode> {
132impl<'d> I2c<'d, Async, Master> { 150impl<'d> I2c<'d, Async, Master> {
133 /// Create a new I2C driver. 151 /// Create a new I2C driver.
134 pub fn new<T: Instance>( 152 pub fn new<T: Instance>(
135 peri: impl Peripheral<P = T> + 'd, 153 peri: Peri<'d, T>,
136 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 154 scl: Peri<'d, impl SclPin<T>>,
137 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 155 sda: Peri<'d, impl SdaPin<T>>,
138 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
139 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
140 + 'd, 158 + 'd,
141 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 159 tx_dma: Peri<'d, impl TxDma<T>>,
142 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 160 rx_dma: Peri<'d, impl RxDma<T>>,
143 freq: Hertz, 161 freq: Hertz,
144 config: Config, 162 config: Config,
145 ) -> Self { 163 ) -> Self {
@@ -158,9 +176,9 @@ impl<'d> I2c<'d, Async, Master> {
158impl<'d> I2c<'d, Blocking, Master> { 176impl<'d> I2c<'d, Blocking, Master> {
159 /// Create a new blocking I2C driver. 177 /// Create a new blocking I2C driver.
160 pub fn new_blocking<T: Instance>( 178 pub fn new_blocking<T: Instance>(
161 peri: impl Peripheral<P = T> + 'd, 179 peri: Peri<'d, T>,
162 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 180 scl: Peri<'d, impl SclPin<T>>,
163 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 181 sda: Peri<'d, impl SdaPin<T>>,
164 freq: Hertz, 182 freq: Hertz,
165 config: Config, 183 config: Config,
166 ) -> Self { 184 ) -> Self {
@@ -179,9 +197,9 @@ impl<'d> I2c<'d, Blocking, Master> {
179impl<'d, M: Mode> I2c<'d, M, Master> { 197impl<'d, M: Mode> I2c<'d, M, Master> {
180 /// Create a new I2C driver. 198 /// Create a new I2C driver.
181 fn new_inner<T: Instance>( 199 fn new_inner<T: Instance>(
182 _peri: impl Peripheral<P = T> + 'd, 200 _peri: Peri<'d, T>,
183 scl: Option<PeripheralRef<'d, AnyPin>>, 201 scl: Option<Peri<'d, AnyPin>>,
184 sda: Option<PeripheralRef<'d, AnyPin>>, 202 sda: Option<Peri<'d, AnyPin>>,
185 tx_dma: Option<ChannelAndRequest<'d>>, 203 tx_dma: Option<ChannelAndRequest<'d>>,
186 rx_dma: Option<ChannelAndRequest<'d>>, 204 rx_dma: Option<ChannelAndRequest<'d>>,
187 freq: Hertz, 205 freq: Hertz,
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 64ccd24c7..990ce7d21 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -40,7 +40,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
40 let regs = T::info().regs; 40 let regs = T::info().regs;
41 let isr = regs.isr().read(); 41 let isr = regs.isr().read();
42 42
43 if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() { 43 if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() {
44 T::state().waker.wake(); 44 T::state().waker.wake();
45 } 45 }
46 46
@@ -48,10 +48,11 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
48 regs.cr1().modify(|w| { 48 regs.cr1().modify(|w| {
49 w.set_addrie(false); 49 w.set_addrie(false);
50 w.set_stopie(false); 50 w.set_stopie(false);
51 // The flag can only be cleared by writting to nbytes, we won't do that here
51 w.set_tcie(false); 52 w.set_tcie(false);
52 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable 53 // Error flags are to be read in the routines, so we also don't clear them here
53 // the interrupt 54 w.set_nackie(false);
54 w.set_tcie(false); 55 w.set_errie(false);
55 }); 56 });
56 }); 57 });
57} 58}
@@ -107,7 +108,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
107 // is BUSY or I2C is in slave mode. 108 // is BUSY or I2C is in slave mode.
108 109
109 let reload = if reload { 110 let reload = if reload {
110 i2c::vals::Reload::NOTCOMPLETED 111 i2c::vals::Reload::NOT_COMPLETED
111 } else { 112 } else {
112 i2c::vals::Reload::COMPLETED 113 i2c::vals::Reload::COMPLETED
113 }; 114 };
@@ -148,7 +149,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
148 } 149 }
149 150
150 let reload = if reload { 151 let reload = if reload {
151 i2c::vals::Reload::NOTCOMPLETED 152 i2c::vals::Reload::NOT_COMPLETED
152 } else { 153 } else {
153 i2c::vals::Reload::COMPLETED 154 i2c::vals::Reload::COMPLETED
154 }; 155 };
@@ -177,7 +178,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
177 } 178 }
178 179
179 let will_reload = if will_reload { 180 let will_reload = if will_reload {
180 i2c::vals::Reload::NOTCOMPLETED 181 i2c::vals::Reload::NOT_COMPLETED
181 } else { 182 } else {
182 i2c::vals::Reload::COMPLETED 183 i2c::vals::Reload::COMPLETED
183 }; 184 };
@@ -483,6 +484,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
483 write: &[u8], 484 write: &[u8],
484 first_slice: bool, 485 first_slice: bool,
485 last_slice: bool, 486 last_slice: bool,
487 send_stop: bool,
486 timeout: Timeout, 488 timeout: Timeout,
487 ) -> Result<(), Error> { 489 ) -> Result<(), Error> {
488 let total_len = write.len(); 490 let total_len = write.len();
@@ -494,6 +496,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
494 if first_slice { 496 if first_slice {
495 w.set_tcie(true); 497 w.set_tcie(true);
496 } 498 }
499 w.set_nackie(true);
500 w.set_errie(true);
497 }); 501 });
498 let dst = regs.txdr().as_ptr() as *mut u8; 502 let dst = regs.txdr().as_ptr() as *mut u8;
499 503
@@ -504,18 +508,41 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
504 508
505 let on_drop = OnDrop::new(|| { 509 let on_drop = OnDrop::new(|| {
506 let regs = self.info.regs; 510 let regs = self.info.regs;
511 let isr = regs.isr().read();
507 regs.cr1().modify(|w| { 512 regs.cr1().modify(|w| {
508 if last_slice { 513 if last_slice || isr.nackf() || isr.arlo() || isr.berr() || isr.ovr() {
509 w.set_txdmaen(false); 514 w.set_txdmaen(false);
510 } 515 }
511 w.set_tcie(false); 516 w.set_tcie(false);
512 }) 517 w.set_nackie(false);
518 w.set_errie(false);
519 });
520 regs.icr().write(|w| {
521 w.set_nackcf(true);
522 w.set_berrcf(true);
523 w.set_arlocf(true);
524 w.set_ovrcf(true);
525 });
513 }); 526 });
514 527
515 poll_fn(|cx| { 528 poll_fn(|cx| {
516 self.state.waker.register(cx.waker()); 529 self.state.waker.register(cx.waker());
517 530
518 let isr = self.info.regs.isr().read(); 531 let isr = self.info.regs.isr().read();
532
533 if isr.nackf() {
534 return Poll::Ready(Err(Error::Nack));
535 }
536 if isr.arlo() {
537 return Poll::Ready(Err(Error::Arbitration));
538 }
539 if isr.berr() {
540 return Poll::Ready(Err(Error::Bus));
541 }
542 if isr.ovr() {
543 return Poll::Ready(Err(Error::Overrun));
544 }
545
519 if remaining_len == total_len { 546 if remaining_len == total_len {
520 if first_slice { 547 if first_slice {
521 Self::master_write( 548 Self::master_write(
@@ -550,10 +577,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
550 .await?; 577 .await?;
551 578
552 dma_transfer.await; 579 dma_transfer.await;
553
554 if last_slice { 580 if last_slice {
555 // This should be done already 581 // This should be done already
556 self.wait_tc(timeout)?; 582 self.wait_tc(timeout)?;
583 }
584
585 if last_slice & send_stop {
557 self.master_stop(); 586 self.master_stop();
558 } 587 }
559 588
@@ -576,6 +605,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
576 regs.cr1().modify(|w| { 605 regs.cr1().modify(|w| {
577 w.set_rxdmaen(true); 606 w.set_rxdmaen(true);
578 w.set_tcie(true); 607 w.set_tcie(true);
608 w.set_nackie(true);
609 w.set_errie(true);
579 }); 610 });
580 let src = regs.rxdr().as_ptr() as *mut u8; 611 let src = regs.rxdr().as_ptr() as *mut u8;
581 612
@@ -589,34 +620,62 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
589 regs.cr1().modify(|w| { 620 regs.cr1().modify(|w| {
590 w.set_rxdmaen(false); 621 w.set_rxdmaen(false);
591 w.set_tcie(false); 622 w.set_tcie(false);
592 }) 623 w.set_nackie(false);
624 w.set_errie(false);
625 });
626 regs.icr().write(|w| {
627 w.set_nackcf(true);
628 w.set_berrcf(true);
629 w.set_arlocf(true);
630 w.set_ovrcf(true);
631 });
593 }); 632 });
594 633
595 poll_fn(|cx| { 634 poll_fn(|cx| {
596 self.state.waker.register(cx.waker()); 635 self.state.waker.register(cx.waker());
597 636
598 let isr = self.info.regs.isr().read(); 637 let isr = self.info.regs.isr().read();
638
639 if isr.nackf() {
640 return Poll::Ready(Err(Error::Nack));
641 }
642 if isr.arlo() {
643 return Poll::Ready(Err(Error::Arbitration));
644 }
645 if isr.berr() {
646 return Poll::Ready(Err(Error::Bus));
647 }
648 if isr.ovr() {
649 return Poll::Ready(Err(Error::Overrun));
650 }
651
599 if remaining_len == total_len { 652 if remaining_len == total_len {
600 Self::master_read( 653 Self::master_read(
601 self.info, 654 self.info,
602 address, 655 address,
603 total_len.min(255), 656 total_len.min(255),
604 Stop::Software, 657 Stop::Automatic,
605 total_len > 255, 658 total_len > 255,
606 restart, 659 restart,
607 timeout, 660 timeout,
608 )?; 661 )?;
609 } else if !(isr.tcr() || isr.tc()) { 662 if total_len <= 255 {
663 return Poll::Ready(Ok(()));
664 }
665 } else if isr.tcr() {
610 // poll_fn was woken without an interrupt present 666 // poll_fn was woken without an interrupt present
611 return Poll::Pending; 667 return Poll::Pending;
612 } else if remaining_len == 0 {
613 return Poll::Ready(Ok(()));
614 } else { 668 } else {
615 let last_piece = remaining_len <= 255; 669 let last_piece = remaining_len <= 255;
616 670
617 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { 671 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) {
618 return Poll::Ready(Err(e)); 672 return Poll::Ready(Err(e));
619 } 673 }
674 // Return here if we are on last chunk,
675 // end of transfer will be awaited with the DMA below
676 if last_piece {
677 return Poll::Ready(Ok(()));
678 }
620 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 679 self.info.regs.cr1().modify(|w| w.set_tcie(true));
621 } 680 }
622 681
@@ -626,11 +685,6 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
626 .await?; 685 .await?;
627 686
628 dma_transfer.await; 687 dma_transfer.await;
629
630 // This should be done already
631 self.wait_tc(timeout)?;
632 self.master_stop();
633
634 drop(on_drop); 688 drop(on_drop);
635 689
636 Ok(()) 690 Ok(())
@@ -645,7 +699,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
645 self.write_internal(address.into(), write, true, timeout) 699 self.write_internal(address.into(), write, true, timeout)
646 } else { 700 } else {
647 timeout 701 timeout
648 .with(self.write_dma_internal(address.into(), write, true, true, timeout)) 702 .with(self.write_dma_internal(address.into(), write, true, true, true, timeout))
649 .await 703 .await
650 } 704 }
651 } 705 }
@@ -667,7 +721,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
667 let next = iter.next(); 721 let next = iter.next();
668 let is_last = next.is_none(); 722 let is_last = next.is_none();
669 723
670 let fut = self.write_dma_internal(address, c, first, is_last, timeout); 724 let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout);
671 timeout.with(fut).await?; 725 timeout.with(fut).await?;
672 first = false; 726 first = false;
673 current = next; 727 current = next;
@@ -694,7 +748,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
694 if write.is_empty() { 748 if write.is_empty() {
695 self.write_internal(address.into(), write, false, timeout)?; 749 self.write_internal(address.into(), write, false, timeout)?;
696 } else { 750 } else {
697 let fut = self.write_dma_internal(address.into(), write, true, true, timeout); 751 let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout);
698 timeout.with(fut).await?; 752 timeout.with(fut).await?;
699 } 753 }
700 754
@@ -1202,7 +1256,12 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> {
1202 type Config = Hertz; 1256 type Config = Hertz;
1203 type ConfigError = (); 1257 type ConfigError = ();
1204 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1258 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
1259 self.info.regs.cr1().modify(|reg| {
1260 reg.set_pe(false);
1261 });
1262
1205 let timings = Timings::new(self.kernel_clock, *config); 1263 let timings = Timings::new(self.kernel_clock, *config);
1264
1206 self.info.regs.timingr().write(|reg| { 1265 self.info.regs.timingr().write(|reg| {
1207 reg.set_presc(timings.prescale); 1266 reg.set_presc(timings.prescale);
1208 reg.set_scll(timings.scll); 1267 reg.set_scll(timings.scll);
@@ -1211,6 +1270,10 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> {
1211 reg.set_scldel(timings.scldel); 1270 reg.set_scldel(timings.scldel);
1212 }); 1271 });
1213 1272
1273 self.info.regs.cr1().modify(|reg| {
1274 reg.set_pe(true);
1275 });
1276
1214 Ok(()) 1277 Ok(())
1215 } 1278 }
1216} 1279}
@@ -1232,3 +1295,4 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M, MultiMaster> {
1232 Ok(()) 1295 Ok(())
1233 } 1296 }
1234} 1297}
1298
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 094de2461..5005a5cdb 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -1,14 +1,14 @@
1//! Inter-IC Sound (I2S) 1//! Inter-IC Sound (I2S)
2 2
3use embassy_hal_internal::into_ref; 3use embassy_futures::join::join;
4use stm32_metapac::spi::vals;
4 5
5use crate::dma::ChannelAndRequest; 6use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer};
6use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 7use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
7use crate::mode::Async; 8use crate::mode::Async;
8use crate::pac::spi::vals; 9use crate::spi::{Config as SpiConfig, RegsExt as _, *};
9use crate::spi::{Config as SpiConfig, *};
10use crate::time::Hertz; 10use crate::time::Hertz;
11use crate::{Peripheral, PeripheralRef}; 11use crate::Peri;
12 12
13/// I2S mode 13/// I2S mode
14#[derive(Copy, Clone)] 14#[derive(Copy, Clone)]
@@ -19,6 +19,19 @@ pub enum Mode {
19 Slave, 19 Slave,
20} 20}
21 21
22/// I2S function
23#[derive(Copy, Clone)]
24#[allow(dead_code)]
25enum Function {
26 /// Transmit audio data
27 Transmit,
28 /// Receive audio data
29 Receive,
30 #[cfg(spi_v3)]
31 /// Transmit and Receive audio data
32 FullDuplex,
33}
34
22/// I2C standard 35/// I2C standard
23#[derive(Copy, Clone)] 36#[derive(Copy, Clone)]
24pub enum Standard { 37pub enum Standard {
@@ -34,6 +47,30 @@ pub enum Standard {
34 PcmShortSync, 47 PcmShortSync,
35} 48}
36 49
50/// SAI error
51#[derive(Debug, PartialEq, Eq)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum Error {
54 /// `write` called on a SAI in receive mode.
55 NotATransmitter,
56 /// `read` called on a SAI in transmit mode.
57 NotAReceiver,
58 /// Overrun
59 Overrun,
60}
61
62impl From<ringbuffer::Error> for Error {
63 fn from(#[allow(unused)] err: ringbuffer::Error) -> Self {
64 #[cfg(feature = "defmt")]
65 {
66 if err == ringbuffer::Error::DmaUnsynced {
67 defmt::error!("Ringbuffer broken invariants detected!");
68 }
69 }
70 Self::Overrun
71 }
72}
73
37impl Standard { 74impl Standard {
38 #[cfg(any(spi_v1, spi_v3, spi_f1))] 75 #[cfg(any(spi_v1, spi_v3, spi_f1))]
39 const fn i2sstd(&self) -> vals::I2sstd { 76 const fn i2sstd(&self) -> vals::I2sstd {
@@ -103,8 +140,8 @@ impl ClockPolarity {
103 #[cfg(any(spi_v1, spi_v3, spi_f1))] 140 #[cfg(any(spi_v1, spi_v3, spi_f1))]
104 const fn ckpol(&self) -> vals::Ckpol { 141 const fn ckpol(&self) -> vals::Ckpol {
105 match self { 142 match self {
106 ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, 143 ClockPolarity::IdleHigh => vals::Ckpol::IDLE_HIGH,
107 ClockPolarity::IdleLow => vals::Ckpol::IDLELOW, 144 ClockPolarity::IdleLow => vals::Ckpol::IDLE_LOW,
108 } 145 }
109 } 146 }
110} 147}
@@ -142,50 +179,107 @@ impl Default for Config {
142 } 179 }
143} 180}
144 181
145/// I2S driver. 182/// I2S driver writer. Useful for moving write functionality across tasks.
146pub struct I2S<'d> { 183pub struct Writer<'s, 'd, W: Word>(&'s mut WritableRingBuffer<'d, W>);
147 _peri: Spi<'d, Async>, 184
148 txsd: Option<PeripheralRef<'d, AnyPin>>, 185impl<'s, 'd, W: Word> Writer<'s, 'd, W> {
149 rxsd: Option<PeripheralRef<'d, AnyPin>>, 186 /// Write data to the I2S ringbuffer.
150 ws: Option<PeripheralRef<'d, AnyPin>>, 187 /// This appends the data to the buffer and returns immediately. The data will be transmitted in the background.
151 ck: Option<PeripheralRef<'d, AnyPin>>, 188 /// If thfre’s no space in the buffer, this waits until there is.
152 mck: Option<PeripheralRef<'d, AnyPin>>, 189 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
190 self.0.write_exact(data).await?;
191 Ok(())
192 }
193
194 /// Reset the ring buffer to its initial state.
195 /// Can be used to recover from overrun.
196 /// The ringbuffer will always auto-reset on Overrun in any case.
197 pub fn reset(&mut self) {
198 self.0.clear();
199 }
153} 200}
154 201
155/// I2S function 202/// I2S driver reader. Useful for moving read functionality across tasks.
156#[derive(Copy, Clone)] 203pub struct Reader<'s, 'd, W: Word>(&'s mut ReadableRingBuffer<'d, W>);
157#[allow(dead_code)] 204
158enum Function { 205impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
159 /// Transmit audio data 206 /// Read data from the I2S ringbuffer.
160 Transmit, 207 /// SAI is always receiving data in the background. This function pops already-received data from the buffer.
161 /// Receive audio data 208 /// If there’s less than data.len() data in the buffer, this waits until there is.
162 Receive, 209 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
163 #[cfg(spi_v3)] 210 self.0.read_exact(data).await?;
164 /// Transmit and Receive audio data 211 Ok(())
165 FullDuplex, 212 }
213
214 /// Reset the ring buffer to its initial state.
215 /// Can be used to prevent overrun.
216 /// The ringbuffer will always auto-reset on Overrun in any case.
217 pub fn reset(&mut self) {
218 self.0.clear();
219 }
220}
221
222/// I2S driver.
223pub struct I2S<'d, W: Word> {
224 #[allow(dead_code)]
225 mode: Mode,
226 spi: Spi<'d, Async>,
227 txsd: Option<Peri<'d, AnyPin>>,
228 rxsd: Option<Peri<'d, AnyPin>>,
229 ws: Option<Peri<'d, AnyPin>>,
230 ck: Option<Peri<'d, AnyPin>>,
231 mck: Option<Peri<'d, AnyPin>>,
232 tx_ring_buffer: Option<WritableRingBuffer<'d, W>>,
233 rx_ring_buffer: Option<ReadableRingBuffer<'d, W>>,
166} 234}
167 235
168impl<'d> I2S<'d> { 236impl<'d, W: Word> I2S<'d, W> {
169 /// Create a transmitter driver 237 /// Create a transmitter driver.
170 pub fn new_txonly<T: Instance>( 238 pub fn new_txonly<T: Instance>(
171 peri: impl Peripheral<P = T> + 'd, 239 peri: Peri<'d, T>,
172 sd: impl Peripheral<P = impl MosiPin<T>> + 'd, 240 sd: Peri<'d, impl MosiPin<T>>,
173 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 241 ws: Peri<'d, impl WsPin<T>>,
174 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 242 ck: Peri<'d, impl CkPin<T>>,
175 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 243 mck: Peri<'d, impl MckPin<T>>,
176 txdma: impl Peripheral<P = impl TxDma<T>> + 'd, 244 txdma: Peri<'d, impl TxDma<T>>,
245 txdma_buf: &'d mut [W],
246 freq: Hertz,
247 config: Config,
248 ) -> Self {
249 Self::new_inner(
250 peri,
251 new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
252 None,
253 ws,
254 ck,
255 new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
256 new_dma!(txdma).map(|d| (d, txdma_buf)),
257 None,
258 freq,
259 config,
260 Function::Transmit,
261 )
262 }
263
264 /// Create a transmitter driver without a master clock pin.
265 pub fn new_txonly_nomck<T: Instance>(
266 peri: Peri<'d, T>,
267 sd: Peri<'d, impl MosiPin<T>>,
268 ws: Peri<'d, impl WsPin<T>>,
269 ck: Peri<'d, impl CkPin<T>>,
270 txdma: Peri<'d, impl TxDma<T>>,
271 txdma_buf: &'d mut [W],
177 freq: Hertz, 272 freq: Hertz,
178 config: Config, 273 config: Config,
179 ) -> Self { 274 ) -> Self {
180 into_ref!(sd);
181 Self::new_inner( 275 Self::new_inner(
182 peri, 276 peri,
183 new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 277 new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
184 None, 278 None,
185 ws, 279 ws,
186 ck, 280 ck,
187 mck, 281 None,
188 new_dma!(txdma), 282 new_dma!(txdma).map(|d| (d, txdma_buf)),
189 None, 283 None,
190 freq, 284 freq,
191 config, 285 config,
@@ -193,120 +287,210 @@ impl<'d> I2S<'d> {
193 ) 287 )
194 } 288 }
195 289
196 /// Create a receiver driver 290 /// Create a receiver driver.
197 pub fn new_rxonly<T: Instance>( 291 pub fn new_rxonly<T: Instance>(
198 peri: impl Peripheral<P = T> + 'd, 292 peri: Peri<'d, T>,
199 sd: impl Peripheral<P = impl MisoPin<T>> + 'd, 293 sd: Peri<'d, impl MisoPin<T>>,
200 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 294 ws: Peri<'d, impl WsPin<T>>,
201 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 295 ck: Peri<'d, impl CkPin<T>>,
202 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 296 mck: Peri<'d, impl MckPin<T>>,
203 #[cfg(not(spi_v3))] txdma: impl Peripheral<P = impl TxDma<T>> + 'd, 297 rxdma: Peri<'d, impl RxDma<T>>,
204 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd, 298 rxdma_buf: &'d mut [W],
205 freq: Hertz, 299 freq: Hertz,
206 config: Config, 300 config: Config,
207 ) -> Self { 301 ) -> Self {
208 into_ref!(sd);
209 Self::new_inner( 302 Self::new_inner(
210 peri, 303 peri,
211 None, 304 None,
212 new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 305 new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
213 ws, 306 ws,
214 ck, 307 ck,
215 mck, 308 new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
216 #[cfg(not(spi_v3))]
217 new_dma!(txdma),
218 #[cfg(spi_v3)]
219 None, 309 None,
220 new_dma!(rxdma), 310 new_dma!(rxdma).map(|d| (d, rxdma_buf)),
221 freq, 311 freq,
222 config, 312 config,
223 #[cfg(not(spi_v3))]
224 Function::Transmit,
225 #[cfg(spi_v3)]
226 Function::Receive, 313 Function::Receive,
227 ) 314 )
228 } 315 }
229 316
230 #[cfg(spi_v3)] 317 #[cfg(spi_v3)]
231 /// Create a full duplex transmitter driver 318 /// Create a full duplex driver.
232 pub fn new_full_duplex<T: Instance>( 319 pub fn new_full_duplex<T: Instance>(
233 peri: impl Peripheral<P = T> + 'd, 320 peri: Peri<'d, T>,
234 txsd: impl Peripheral<P = impl MosiPin<T>> + 'd, 321 txsd: Peri<'d, impl MosiPin<T>>,
235 rxsd: impl Peripheral<P = impl MisoPin<T>> + 'd, 322 rxsd: Peri<'d, impl MisoPin<T>>,
236 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 323 ws: Peri<'d, impl WsPin<T>>,
237 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 324 ck: Peri<'d, impl CkPin<T>>,
238 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 325 mck: Peri<'d, impl MckPin<T>>,
239 txdma: impl Peripheral<P = impl TxDma<T>> + 'd, 326 txdma: Peri<'d, impl TxDma<T>>,
240 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd, 327 txdma_buf: &'d mut [W],
328 rxdma: Peri<'d, impl RxDma<T>>,
329 rxdma_buf: &'d mut [W],
241 freq: Hertz, 330 freq: Hertz,
242 config: Config, 331 config: Config,
243 ) -> Self { 332 ) -> Self {
244 into_ref!(txsd, rxsd);
245 Self::new_inner( 333 Self::new_inner(
246 peri, 334 peri,
247 new_pin!(txsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 335 new_pin!(txsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
248 new_pin!(rxsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 336 new_pin!(rxsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
249 ws, 337 ws,
250 ck, 338 ck,
251 mck, 339 new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
252 new_dma!(txdma), 340 new_dma!(txdma).map(|d| (d, txdma_buf)),
253 new_dma!(rxdma), 341 new_dma!(rxdma).map(|d| (d, rxdma_buf)),
254 freq, 342 freq,
255 config, 343 config,
256 Function::FullDuplex, 344 Function::FullDuplex,
257 ) 345 )
258 } 346 }
259 347
260 /// Write audio data. 348 /// Start I2S driver.
261 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 349 pub fn start(&mut self) {
262 self._peri.read(data).await 350 self.spi.info.regs.cr1().modify(|w| {
351 w.set_spe(false);
352 });
353 self.spi.set_word_size(W::CONFIG);
354 if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer {
355 tx_ring_buffer.start();
356
357 set_txdmaen(self.spi.info.regs, true);
358 }
359 if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer {
360 rx_ring_buffer.start();
361 // SPIv3 clears rxfifo on SPE=0
362 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
363 flush_rx_fifo(self.spi.info.regs);
364
365 set_rxdmaen(self.spi.info.regs, true);
366 }
367 self.spi.info.regs.cr1().modify(|w| {
368 w.set_spe(true);
369 });
370 #[cfg(any(spi_v3, spi_v4, spi_v5))]
371 self.spi.info.regs.cr1().modify(|w| {
372 w.set_cstart(true);
373 });
263 } 374 }
264 375
265 /// Write audio data. 376 /// Reset the ring buffer to its initial state.
266 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 377 /// Can be used to recover from overrun.
267 self._peri.write(data).await 378 pub fn clear(&mut self) {
379 if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer {
380 rx_ring_buffer.clear();
381 }
382 if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer {
383 tx_ring_buffer.clear();
384 }
268 } 385 }
269 386
270 /// Transfer audio data. 387 /// Stop I2S driver.
271 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 388 pub async fn stop(&mut self) {
272 self._peri.transfer(read, write).await 389 let regs = self.spi.info.regs;
390
391 let tx_f = async {
392 if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer {
393 tx_ring_buffer.stop().await;
394
395 set_txdmaen(regs, false);
396 }
397 };
398
399 let rx_f = async {
400 if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer {
401 rx_ring_buffer.stop().await;
402
403 set_rxdmaen(regs, false);
404 }
405 };
406
407 join(rx_f, tx_f).await;
408
409 #[cfg(any(spi_v3, spi_v4, spi_v5))]
410 {
411 if let Mode::Master = self.mode {
412 regs.cr1().modify(|w| {
413 w.set_csusp(true);
414 });
415
416 while regs.cr1().read().cstart() {}
417 }
418 }
419
420 regs.cr1().modify(|w| {
421 w.set_spe(false);
422 });
423
424 self.clear();
425 }
426
427 /// Split the driver into a Reader/Writer pair.
428 /// Useful for splitting the reader/writer functionality across tasks or
429 /// for calling the read/write methods in parallel.
430 pub fn split<'s>(&'s mut self) -> Result<(Reader<'s, 'd, W>, Writer<'s, 'd, W>), Error> {
431 match (&mut self.rx_ring_buffer, &mut self.tx_ring_buffer) {
432 (None, _) => Err(Error::NotAReceiver),
433 (_, None) => Err(Error::NotATransmitter),
434 (Some(rx_ring), Some(tx_ring)) => Ok((Reader(rx_ring), Writer(tx_ring))),
435 }
273 } 436 }
274 437
275 /// Transfer audio data in place. 438 /// Read data from the I2S ringbuffer.
276 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 439 /// SAI is always receiving data in the background. This function pops already-received data from the buffer.
277 self._peri.transfer_in_place(data).await 440 /// If there’s less than data.len() data in the buffer, this waits until there is.
441 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
442 match &mut self.rx_ring_buffer {
443 Some(ring) => Reader(ring).read(data).await,
444 _ => Err(Error::NotAReceiver),
445 }
446 }
447
448 /// Write data to the I2S ringbuffer.
449 /// This appends the data to the buffer and returns immediately. The data will be transmitted in the background.
450 /// If thfre’s no space in the buffer, this waits until there is.
451 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
452 match &mut self.tx_ring_buffer {
453 Some(ring) => Writer(ring).write(data).await,
454 _ => Err(Error::NotATransmitter),
455 }
456 }
457
458 /// Write data directly to the raw I2S ringbuffer.
459 /// This can be used to fill the buffer before starting the DMA transfer.
460 pub async fn write_immediate(&mut self, data: &[W]) -> Result<(usize, usize), Error> {
461 match &mut self.tx_ring_buffer {
462 Some(ring) => Ok(ring.write_immediate(data)?),
463 _ => return Err(Error::NotATransmitter),
464 }
278 } 465 }
279 466
280 fn new_inner<T: Instance>( 467 fn new_inner<T: Instance>(
281 peri: impl Peripheral<P = T> + 'd, 468 peri: Peri<'d, T>,
282 txsd: Option<PeripheralRef<'d, AnyPin>>, 469 txsd: Option<Peri<'d, AnyPin>>,
283 rxsd: Option<PeripheralRef<'d, AnyPin>>, 470 rxsd: Option<Peri<'d, AnyPin>>,
284 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 471 ws: Peri<'d, impl WsPin<T>>,
285 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 472 ck: Peri<'d, impl CkPin<T>>,
286 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 473 mck: Option<Peri<'d, AnyPin>>,
287 txdma: Option<ChannelAndRequest<'d>>, 474 txdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
288 rxdma: Option<ChannelAndRequest<'d>>, 475 rxdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>,
289 freq: Hertz, 476 freq: Hertz,
290 config: Config, 477 config: Config,
291 function: Function, 478 function: Function,
292 ) -> Self { 479 ) -> Self {
293 into_ref!(ws, ck, mck);
294
295 ws.set_as_af(ws.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 480 ws.set_as_af(ws.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
296 ck.set_as_af(ck.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 481 ck.set_as_af(ck.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
297 mck.set_as_af(mck.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
298 482
299 let mut spi_cfg = SpiConfig::default(); 483 let spi = Spi::new_internal(peri, None, None, {
300 spi_cfg.frequency = freq; 484 let mut config = SpiConfig::default();
301 485 config.frequency = freq;
302 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg); 486 config
487 });
303 488
304 let regs = T::info().regs; 489 let regs = T::info().regs;
305 490
306 // TODO move i2s to the new mux infra. 491 #[cfg(all(rcc_f4, not(stm32f410)))]
307 //#[cfg(all(rcc_f4, not(stm32f410)))] 492 let pclk = unsafe { crate::rcc::get_freqs() }.plli2s1_r.to_hertz().unwrap();
308 //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap(); 493 #[cfg(not(all(rcc_f4, not(stm32f410))))]
309 //#[cfg(stm32f410)]
310 let pclk = T::frequency(); 494 let pclk = T::frequency();
311 495
312 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); 496 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
@@ -376,36 +560,43 @@ impl<'d> I2S<'d> {
376 w.set_chlen(config.format.chlen()); 560 w.set_chlen(config.format.chlen());
377 561
378 w.set_i2scfg(match (config.mode, function) { 562 w.set_i2scfg(match (config.mode, function) {
379 (Mode::Master, Function::Transmit) => I2scfg::MASTERTX, 563 (Mode::Master, Function::Transmit) => I2scfg::MASTER_TX,
380 (Mode::Master, Function::Receive) => I2scfg::MASTERRX, 564 (Mode::Master, Function::Receive) => I2scfg::MASTER_RX,
381 #[cfg(spi_v3)] 565 #[cfg(spi_v3)]
382 (Mode::Master, Function::FullDuplex) => I2scfg::MASTERFULLDUPLEX, 566 (Mode::Master, Function::FullDuplex) => I2scfg::MASTER_FULL_DUPLEX,
383 (Mode::Slave, Function::Transmit) => I2scfg::SLAVETX, 567 (Mode::Slave, Function::Transmit) => I2scfg::SLAVE_TX,
384 (Mode::Slave, Function::Receive) => I2scfg::SLAVERX, 568 (Mode::Slave, Function::Receive) => I2scfg::SLAVE_RX,
385 #[cfg(spi_v3)] 569 #[cfg(spi_v3)]
386 (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVEFULLDUPLEX, 570 (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVE_FULL_DUPLEX,
387 }); 571 });
388 572
389 #[cfg(any(spi_v1, spi_f1))] 573 #[cfg(any(spi_v1, spi_f1))]
390 w.set_i2se(true); 574 w.set_i2se(true);
391 }); 575 });
392 576
393 #[cfg(spi_v3)] 577 let mut opts = TransferOptions::default();
394 regs.cr1().modify(|w| w.set_spe(true)); 578 opts.half_transfer_ir = true;
395 } 579
396 580 Self {
397 Self { 581 mode: config.mode,
398 _peri: spi, 582 spi,
399 txsd: txsd.map(|w| w.map_into()), 583 txsd: txsd.map(|w| w.into()),
400 rxsd: rxsd.map(|w| w.map_into()), 584 rxsd: rxsd.map(|w| w.into()),
401 ws: Some(ws.map_into()), 585 ws: Some(ws.into()),
402 ck: Some(ck.map_into()), 586 ck: Some(ck.into()),
403 mck: Some(mck.map_into()), 587 mck: mck.map(|w| w.into()),
588 tx_ring_buffer: txdma.map(|(ch, buf)| unsafe {
589 WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts)
590 }),
591 rx_ring_buffer: rxdma.map(|(ch, buf)| unsafe {
592 ReadableRingBuffer::new(ch.channel, ch.request, regs.rx_ptr(), buf, opts)
593 }),
594 }
404 } 595 }
405 } 596 }
406} 597}
407 598
408impl<'d> Drop for I2S<'d> { 599impl<'d, W: Word> Drop for I2S<'d, W> {
409 fn drop(&mut self) { 600 fn drop(&mut self) {
410 self.txsd.as_ref().map(|x| x.set_as_disconnected()); 601 self.txsd.as_ref().map(|x| x.set_as_disconnected());
411 self.rxsd.as_ref().map(|x| x.set_as_disconnected()); 602 self.rxsd.as_ref().map(|x| x.set_as_disconnected());
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 6c8347311..20cd20dca 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -229,11 +229,9 @@ struct State {
229 229
230impl State { 230impl State {
231 const fn new() -> Self { 231 const fn new() -> Self {
232 const WAKER: AtomicWaker = AtomicWaker::new();
233
234 Self { 232 Self {
235 rx_wakers: [WAKER; 6], 233 rx_wakers: [const { AtomicWaker::new() }; 6],
236 tx_wakers: [WAKER; 6], 234 tx_wakers: [const { AtomicWaker::new() }; 6],
237 } 235 }
238 } 236 }
239 237
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 12ebbae2d..973acc9bb 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -68,6 +68,8 @@ pub mod dac;
68pub mod dcmi; 68pub mod dcmi;
69#[cfg(dsihost)] 69#[cfg(dsihost)]
70pub mod dsihost; 70pub mod dsihost;
71#[cfg(dts)]
72pub mod dts;
71#[cfg(eth)] 73#[cfg(eth)]
72pub mod eth; 74pub mod eth;
73#[cfg(feature = "exti")] 75#[cfg(feature = "exti")]
@@ -81,6 +83,8 @@ pub mod hash;
81pub mod hrtim; 83pub mod hrtim;
82#[cfg(hsem)] 84#[cfg(hsem)]
83pub mod hsem; 85pub mod hsem;
86#[cfg(hspi)]
87pub mod hspi;
84#[cfg(i2c)] 88#[cfg(i2c)]
85pub mod i2c; 89pub mod i2c;
86#[cfg(any(all(spi_v1, rcc_f4), spi_v3))] 90#[cfg(any(all(spi_v1, rcc_f4), spi_v3))]
@@ -89,6 +93,8 @@ pub mod i2s;
89pub mod ipcc; 93pub mod ipcc;
90#[cfg(feature = "low-power")] 94#[cfg(feature = "low-power")]
91pub mod low_power; 95pub mod low_power;
96#[cfg(lptim)]
97pub mod lptim;
92#[cfg(ltdc)] 98#[cfg(ltdc)]
93pub mod ltdc; 99pub mod ltdc;
94#[cfg(opamp)] 100#[cfg(opamp)]
@@ -105,6 +111,8 @@ pub mod rtc;
105pub mod sai; 111pub mod sai;
106#[cfg(sdmmc)] 112#[cfg(sdmmc)]
107pub mod sdmmc; 113pub mod sdmmc;
114#[cfg(spdifrx)]
115pub mod spdifrx;
108#[cfg(spi)] 116#[cfg(spi)]
109pub mod spi; 117pub mod spi;
110#[cfg(tsc)] 118#[cfg(tsc)]
@@ -119,6 +127,8 @@ pub mod usart;
119pub mod usb; 127pub mod usb;
120#[cfg(iwdg)] 128#[cfg(iwdg)]
121pub mod wdg; 129pub mod wdg;
130#[cfg(xspi)]
131pub mod xspi;
122 132
123// This must go last, so that it sees all the impl_foo! macros defined earlier. 133// This must go last, so that it sees all the impl_foo! macros defined earlier.
124pub(crate) mod _generated { 134pub(crate) mod _generated {
@@ -153,39 +163,63 @@ pub use crate::_generated::interrupt;
153/// ```rust,ignore 163/// ```rust,ignore
154/// use embassy_stm32::{bind_interrupts, i2c, peripherals}; 164/// use embassy_stm32::{bind_interrupts, i2c, peripherals};
155/// 165///
156/// bind_interrupts!(struct Irqs { 166/// bind_interrupts!(
157/// I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>; 167/// /// Binds the I2C interrupts.
158/// I2C2_3 => i2c::EventInterruptHandler<peripherals::I2C2>, i2c::ErrorInterruptHandler<peripherals::I2C2>, 168/// struct Irqs {
159/// i2c::EventInterruptHandler<peripherals::I2C3>, i2c::ErrorInterruptHandler<peripherals::I2C3>; 169/// I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
160/// }); 170/// I2C2_3 => i2c::EventInterruptHandler<peripherals::I2C2>, i2c::ErrorInterruptHandler<peripherals::I2C2>,
171/// i2c::EventInterruptHandler<peripherals::I2C3>, i2c::ErrorInterruptHandler<peripherals::I2C3>;
172/// }
173/// );
161/// ``` 174/// ```
162 175
163// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. 176// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
164#[macro_export] 177#[macro_export]
165macro_rules! bind_interrupts { 178macro_rules! bind_interrupts {
166 ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { 179 ($(#[$outer:meta])* $vis:vis struct $name:ident {
180 $(
181 $(#[$inner:meta])*
182 $(#[cfg($cond_irq:meta)])?
183 $irq:ident => $(
184 $(#[cfg($cond_handler:meta)])?
185 $handler:ty
186 ),*;
187 )*
188 }) => {
167 #[derive(Copy, Clone)] 189 #[derive(Copy, Clone)]
190 $(#[$outer])*
168 $vis struct $name; 191 $vis struct $name;
169 192
170 $( 193 $(
171 #[allow(non_snake_case)] 194 #[allow(non_snake_case)]
172 #[no_mangle] 195 #[no_mangle]
196 $(#[cfg($cond_irq)])?
197 $(#[$inner])*
173 unsafe extern "C" fn $irq() { 198 unsafe extern "C" fn $irq() {
174 $( 199 $(
200 $(#[cfg($cond_handler)])?
175 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); 201 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
202
176 )* 203 )*
177 } 204 }
178 205
179 $( 206 $(#[cfg($cond_irq)])?
180 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} 207 $crate::bind_interrupts!(@inner
181 )* 208 $(
209 $(#[cfg($cond_handler)])?
210 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
211 )*
212 );
182 )* 213 )*
183 }; 214 };
215 (@inner $($t:tt)*) => {
216 $($t)*
217 }
184} 218}
185 219
186// Reexports 220// Reexports
187pub use _generated::{peripherals, Peripherals}; 221pub use _generated::{peripherals, Peripherals};
188pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 222pub use embassy_hal_internal::{Peri, PeripheralType};
189#[cfg(feature = "unstable-pac")] 223#[cfg(feature = "unstable-pac")]
190pub use stm32_metapac as pac; 224pub use stm32_metapac as pac;
191#[cfg(not(feature = "unstable-pac"))] 225#[cfg(not(feature = "unstable-pac"))]
@@ -197,6 +231,7 @@ pub use crate::pac::NVIC_PRIO_BITS;
197 231
198/// `embassy-stm32` global configuration. 232/// `embassy-stm32` global configuration.
199#[non_exhaustive] 233#[non_exhaustive]
234#[derive(Clone, Copy)]
200pub struct Config { 235pub struct Config {
201 /// RCC config. 236 /// RCC config.
202 pub rcc: rcc::Config, 237 pub rcc: rcc::Config,
@@ -215,6 +250,10 @@ pub struct Config {
215 #[cfg(any(stm32l4, stm32l5, stm32u5))] 250 #[cfg(any(stm32l4, stm32l5, stm32u5))]
216 pub enable_independent_io_supply: bool, 251 pub enable_independent_io_supply: bool,
217 252
253 /// On the U5 series all analog peripherals are powered by a separate supply.
254 #[cfg(stm32u5)]
255 pub enable_independent_analog_supply: bool,
256
218 /// BDMA interrupt priority. 257 /// BDMA interrupt priority.
219 /// 258 ///
220 /// Defaults to P0 (highest). 259 /// Defaults to P0 (highest).
@@ -254,6 +293,8 @@ impl Default for Config {
254 enable_debug_during_sleep: true, 293 enable_debug_during_sleep: true,
255 #[cfg(any(stm32l4, stm32l5, stm32u5))] 294 #[cfg(any(stm32l4, stm32l5, stm32u5))]
256 enable_independent_io_supply: true, 295 enable_independent_io_supply: true,
296 #[cfg(stm32u5)]
297 enable_independent_analog_supply: true,
257 #[cfg(bdma)] 298 #[cfg(bdma)]
258 bdma_interrupt_priority: Priority::P0, 299 bdma_interrupt_priority: Priority::P0,
259 #[cfg(dma)] 300 #[cfg(dma)]
@@ -293,6 +334,9 @@ mod dual_core {
293 /// It cannot be initialized by the user. The intended use is: 334 /// It cannot be initialized by the user. The intended use is:
294 /// 335 ///
295 /// ``` 336 /// ```
337 /// use core::mem::MaybeUninit;
338 /// use embassy_stm32::{init_secondary, SharedData};
339 ///
296 /// #[link_section = ".ram_d3"] 340 /// #[link_section = ".ram_d3"]
297 /// static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); 341 /// static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
298 /// 342 ///
@@ -300,9 +344,11 @@ mod dual_core {
300 /// ``` 344 /// ```
301 /// 345 ///
302 /// This static must be placed in the same position for both cores. How and where this is done is left to the user. 346 /// This static must be placed in the same position for both cores. How and where this is done is left to the user.
347 #[repr(C)]
303 pub struct SharedData { 348 pub struct SharedData {
304 init_flag: AtomicUsize, 349 init_flag: AtomicUsize,
305 clocks: UnsafeCell<MaybeUninit<Clocks>>, 350 clocks: UnsafeCell<MaybeUninit<Clocks>>,
351 config: UnsafeCell<MaybeUninit<SharedConfig>>,
306 } 352 }
307 353
308 unsafe impl Sync for SharedData {} 354 unsafe impl Sync for SharedData {}
@@ -322,9 +368,16 @@ mod dual_core {
322 pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals { 368 pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
323 let shared_data = unsafe { shared_data.assume_init_ref() }; 369 let shared_data = unsafe { shared_data.assume_init_ref() };
324 370
371 // Write the flag as soon as possible. Reading this flag uninitialized in the `init_secondary`
372 // is maybe unsound? Unclear. If it is indeed unsound, writing it sooner doesn't fix it all,
373 // but improves the odds of it going right
374 shared_data.init_flag.store(0, Ordering::SeqCst);
375
325 rcc::set_freqs_ptr(shared_data.clocks.get()); 376 rcc::set_freqs_ptr(shared_data.clocks.get());
326 let p = init_hw(config); 377 let p = init_hw(config);
327 378
379 unsafe { *shared_data.config.get() }.write(config.into());
380
328 shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst); 381 shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);
329 382
330 p 383 p
@@ -372,15 +425,63 @@ mod dual_core {
372 fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals { 425 fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals {
373 rcc::set_freqs_ptr(shared_data.clocks.get()); 426 rcc::set_freqs_ptr(shared_data.clocks.get());
374 427
428 let config = unsafe { (*shared_data.config.get()).assume_init() };
429
375 // We use different timers on the different cores, so we have to still initialize one here 430 // We use different timers on the different cores, so we have to still initialize one here
376 #[cfg(feature = "_time-driver")]
377 critical_section::with(|cs| { 431 critical_section::with(|cs| {
432 unsafe {
433 dma::init(
434 cs,
435 #[cfg(bdma)]
436 config.bdma_interrupt_priority,
437 #[cfg(dma)]
438 config.dma_interrupt_priority,
439 #[cfg(gpdma)]
440 config.gpdma_interrupt_priority,
441 )
442 }
443
444 #[cfg(feature = "_time-driver")]
378 // must be after rcc init 445 // must be after rcc init
379 time_driver::init(cs); 446 time_driver::init(cs);
380 }); 447 });
381 448
382 Peripherals::take() 449 Peripherals::take()
383 } 450 }
451
452 #[repr(C)]
453 #[derive(Clone, Copy)]
454 struct SharedConfig {
455 #[cfg(bdma)]
456 bdma_interrupt_priority: Priority,
457 #[cfg(dma)]
458 dma_interrupt_priority: Priority,
459 #[cfg(gpdma)]
460 gpdma_interrupt_priority: Priority,
461 }
462
463 impl From<Config> for SharedConfig {
464 fn from(value: Config) -> Self {
465 let Config {
466 #[cfg(bdma)]
467 bdma_interrupt_priority,
468 #[cfg(dma)]
469 dma_interrupt_priority,
470 #[cfg(gpdma)]
471 gpdma_interrupt_priority,
472 ..
473 } = value;
474
475 SharedConfig {
476 #[cfg(bdma)]
477 bdma_interrupt_priority,
478 #[cfg(dma)]
479 dma_interrupt_priority,
480 #[cfg(gpdma)]
481 gpdma_interrupt_priority,
482 }
483 }
484 }
384} 485}
385 486
386#[cfg(feature = "_dual-core")] 487#[cfg(feature = "_dual-core")]
@@ -397,7 +498,7 @@ fn init_hw(config: Config) -> Peripherals {
397 cr.set_stop(config.enable_debug_during_sleep); 498 cr.set_stop(config.enable_debug_during_sleep);
398 cr.set_standby(config.enable_debug_during_sleep); 499 cr.set_standby(config.enable_debug_during_sleep);
399 } 500 }
400 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))] 501 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))]
401 { 502 {
402 cr.set_dbg_stop(config.enable_debug_during_sleep); 503 cr.set_dbg_stop(config.enable_debug_during_sleep);
403 cr.set_dbg_standby(config.enable_debug_during_sleep); 504 cr.set_dbg_standby(config.enable_debug_during_sleep);
@@ -444,6 +545,20 @@ fn init_hw(config: Config) -> Peripherals {
444 crate::pac::PWR.svmcr().modify(|w| { 545 crate::pac::PWR.svmcr().modify(|w| {
445 w.set_io2sv(config.enable_independent_io_supply); 546 w.set_io2sv(config.enable_independent_io_supply);
446 }); 547 });
548 if config.enable_independent_analog_supply {
549 crate::pac::PWR.svmcr().modify(|w| {
550 w.set_avm1en(true);
551 });
552 while !crate::pac::PWR.svmsr().read().vdda1rdy() {}
553 crate::pac::PWR.svmcr().modify(|w| {
554 w.set_asv(true);
555 });
556 } else {
557 crate::pac::PWR.svmcr().modify(|w| {
558 w.set_avm1en(false);
559 w.set_avm2en(false);
560 });
561 }
447 } 562 }
448 563
449 // dead battery functionality is still present on these 564 // dead battery functionality is still present on these
@@ -491,17 +606,7 @@ fn init_hw(config: Config) -> Peripherals {
491 #[cfg(feature = "exti")] 606 #[cfg(feature = "exti")]
492 exti::init(cs); 607 exti::init(cs);
493 608
494 rcc::init(config.rcc); 609 rcc::init_rcc(cs, config.rcc);
495
496 // must be after rcc init
497 #[cfg(feature = "_time-driver")]
498 time_driver::init(cs);
499
500 #[cfg(feature = "low-power")]
501 {
502 crate::rcc::REFCOUNT_STOP2 = 0;
503 crate::rcc::REFCOUNT_STOP1 = 0;
504 }
505 } 610 }
506 611
507 p 612 p
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 604bdf416..7734365f1 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -51,6 +51,9 @@
51//! } 51//! }
52//! ``` 52//! ```
53 53
54// TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.`
55#![allow(static_mut_refs)]
56
54use core::arch::asm; 57use core::arch::asm;
55use core::marker::PhantomData; 58use core::marker::PhantomData;
56use core::sync::atomic::{compiler_fence, Ordering}; 59use core::sync::atomic::{compiler_fence, Ordering};
@@ -67,6 +70,7 @@ use crate::rtc::Rtc;
67 70
68static mut EXECUTOR: Option<Executor> = None; 71static mut EXECUTOR: Option<Executor> = None;
69 72
73#[cfg(not(stm32u0))]
70foreach_interrupt! { 74foreach_interrupt! {
71 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 75 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
72 #[interrupt] 76 #[interrupt]
@@ -77,6 +81,17 @@ foreach_interrupt! {
77 }; 81 };
78} 82}
79 83
84#[cfg(stm32u0)]
85foreach_interrupt! {
86 (RTC, rtc, $block:ident, TAMP, $irq:ident) => {
87 #[interrupt]
88 #[allow(non_snake_case)]
89 unsafe fn $irq() {
90 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
91 }
92 };
93}
94
80#[allow(dead_code)] 95#[allow(dead_code)]
81pub(crate) unsafe fn on_wakeup_irq() { 96pub(crate) unsafe fn on_wakeup_irq() {
82 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 97 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
@@ -109,10 +124,10 @@ pub enum StopMode {
109 Stop2, 124 Stop2,
110} 125}
111 126
112#[cfg(stm32l5)] 127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))]
113use stm32_metapac::pwr::vals::Lpms; 128use stm32_metapac::pwr::vals::Lpms;
114 129
115#[cfg(stm32l5)] 130#[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))]
116impl Into<Lpms> for StopMode { 131impl Into<Lpms> for StopMode {
117 fn into(self) -> Lpms { 132 fn into(self) -> Lpms {
118 match self { 133 match self {
@@ -152,7 +167,9 @@ impl Executor {
152 time_driver: get_driver(), 167 time_driver: get_driver(),
153 }); 168 });
154 169
155 EXECUTOR.as_mut().unwrap() 170 let executor = EXECUTOR.as_mut().unwrap();
171
172 executor
156 }) 173 })
157 } 174 }
158 175
@@ -181,7 +198,7 @@ impl Executor {
181 198
182 #[allow(unused_variables)] 199 #[allow(unused_variables)]
183 fn configure_stop(&mut self, stop_mode: StopMode) { 200 fn configure_stop(&mut self, stop_mode: StopMode) {
184 #[cfg(stm32l5)] 201 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))]
185 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 202 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
186 #[cfg(stm32h5)] 203 #[cfg(stm32h5)]
187 crate::pac::PWR.pmcr().modify(|v| { 204 crate::pac::PWR.pmcr().modify(|v| {
@@ -238,11 +255,12 @@ impl Executor {
238 /// 255 ///
239 /// This function never returns. 256 /// This function never returns.
240 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 257 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
241 init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); 258 let executor = unsafe { EXECUTOR.as_mut().unwrap() };
259 init(executor.inner.spawner());
242 260
243 loop { 261 loop {
244 unsafe { 262 unsafe {
245 EXECUTOR.as_mut().unwrap().inner.poll(); 263 executor.inner.poll();
246 self.configure_pwr(); 264 self.configure_pwr();
247 asm!("wfe"); 265 asm!("wfe");
248 }; 266 };
diff --git a/embassy-stm32/src/lptim/channel.rs b/embassy-stm32/src/lptim/channel.rs
new file mode 100644
index 000000000..17fc2fb86
--- /dev/null
+++ b/embassy-stm32/src/lptim/channel.rs
@@ -0,0 +1,18 @@
1/// Timer channel.
2#[derive(Clone, Copy)]
3pub enum Channel {
4 /// Channel 1.
5 Ch1,
6 /// Channel 2.
7 Ch2,
8}
9
10impl Channel {
11 /// Get the channel index (0..1)
12 pub fn index(&self) -> usize {
13 match self {
14 Channel::Ch1 => 0,
15 Channel::Ch2 => 1,
16 }
17 }
18}
diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs
new file mode 100644
index 000000000..e0ddba1c7
--- /dev/null
+++ b/embassy-stm32/src/lptim/mod.rs
@@ -0,0 +1,49 @@
1//! Low-power timer (LPTIM)
2
3pub mod pwm;
4pub mod timer;
5
6use crate::rcc::RccPeripheral;
7
8/// Timer channel.
9#[cfg(any(lptim_v2a, lptim_v2b))]
10mod channel;
11#[cfg(any(lptim_v2a, lptim_v2b))]
12pub use channel::Channel;
13use embassy_hal_internal::PeripheralType;
14
15pin_trait!(OutputPin, BasicInstance);
16pin_trait!(Channel1Pin, BasicInstance);
17pin_trait!(Channel2Pin, BasicInstance);
18
19pub(crate) trait SealedInstance: RccPeripheral {
20 fn regs() -> crate::pac::lptim::Lptim;
21}
22pub(crate) trait SealedBasicInstance: RccPeripheral {}
23
24/// LPTIM basic instance trait.
25#[allow(private_bounds)]
26pub trait BasicInstance: PeripheralType + SealedBasicInstance + 'static {}
27
28/// LPTIM instance trait.
29#[allow(private_bounds)]
30pub trait Instance: BasicInstance + SealedInstance + 'static {}
31
32foreach_interrupt! {
33 ($inst:ident, lptim, LPTIM, GLOBAL, $irq:ident) => {
34 impl SealedInstance for crate::peripherals::$inst {
35 fn regs() -> crate::pac::lptim::Lptim {
36 crate::pac::$inst
37 }
38 }
39 impl SealedBasicInstance for crate::peripherals::$inst {
40 }
41 impl BasicInstance for crate::peripherals::$inst {}
42 impl Instance for crate::peripherals::$inst {}
43 };
44 ($inst:ident, lptim, LPTIM_BASIC, GLOBAL, $irq:ident) => {
45 impl SealedBasicInstance for crate::peripherals::$inst {
46 }
47 impl BasicInstance for crate::peripherals::$inst {}
48 };
49}
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
new file mode 100644
index 000000000..2f2d7ba01
--- /dev/null
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -0,0 +1,198 @@
1//! PWM driver.
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::Peri;
6
7use super::timer::Timer;
8#[cfg(not(any(lptim_v2a, lptim_v2b)))]
9use super::OutputPin;
10#[cfg(any(lptim_v2a, lptim_v2b))]
11use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin};
12use super::{BasicInstance, Instance};
13#[cfg(gpio_v2)]
14use crate::gpio::Pull;
15use crate::gpio::{AfType, AnyPin, OutputType, Speed};
16use crate::time::Hertz;
17
18/// Output marker type.
19pub enum Output {}
20/// Channel 1 marker type.
21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
24
25/// PWM pin wrapper.
26///
27/// This wraps a pin to make it usable with PWM.
28pub struct PwmPin<'d, T, C> {
29 _pin: Peri<'d, AnyPin>,
30 phantom: PhantomData<(T, C)>,
31}
32
33/// PWM pin config
34///
35/// This configures the pwm pin settings
36pub struct PwmPinConfig {
37 /// PWM Pin output type
38 pub output_type: OutputType,
39 /// PWM Pin speed
40 pub speed: Speed,
41 /// PWM Pin pull type
42 #[cfg(gpio_v2)]
43 pub pull: Pull,
44}
45
46macro_rules! channel_impl {
47 ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => {
48 impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> {
49 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
50 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
51 critical_section::with(|_| {
52 pin.set_low();
53 pin.set_as_af(
54 pin.af_num(),
55 AfType::output(OutputType::PushPull, Speed::VeryHigh),
56 );
57 });
58 PwmPin {
59 _pin: pin.into(),
60 phantom: PhantomData,
61 }
62 }
63 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")]
64 pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T>>, pin_config: PwmPinConfig) -> Self {
65 critical_section::with(|_| {
66 pin.set_low();
67 pin.set_as_af(
68 pin.af_num(),
69 #[cfg(gpio_v1)]
70 AfType::output(pin_config.output_type, pin_config.speed),
71 #[cfg(gpio_v2)]
72 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
73 );
74 });
75 PwmPin {
76 _pin: pin.into(),
77 phantom: PhantomData,
78 }
79 }
80 }
81 };
82}
83
84#[cfg(not(any(lptim_v2a, lptim_v2b)))]
85channel_impl!(new, new_with_config, Output, OutputPin);
86#[cfg(any(lptim_v2a, lptim_v2b))]
87channel_impl!(new_ch1, new_ch1_with_config, Ch1, Channel1Pin);
88#[cfg(any(lptim_v2a, lptim_v2b))]
89channel_impl!(new_ch2, new_ch2_with_config, Ch2, Channel2Pin);
90
91/// PWM driver.
92pub struct Pwm<'d, T: Instance> {
93 inner: Timer<'d, T>,
94}
95
96#[cfg(not(any(lptim_v2a, lptim_v2b)))]
97impl<'d, T: Instance> Pwm<'d, T> {
98 /// Create a new PWM driver.
99 pub fn new(tim: Peri<'d, T>, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self {
100 Self::new_inner(tim, freq)
101 }
102
103 /// Set the duty.
104 ///
105 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
106 pub fn set_duty(&mut self, duty: u16) {
107 assert!(duty <= self.get_max_duty());
108 self.inner.set_compare_value(duty)
109 }
110
111 /// Get the duty.
112 ///
113 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
114 pub fn get_duty(&self) -> u16 {
115 self.inner.get_compare_value()
116 }
117
118 fn post_init(&mut self) {}
119}
120
121#[cfg(any(lptim_v2a, lptim_v2b))]
122impl<'d, T: Instance> Pwm<'d, T> {
123 /// Create a new PWM driver.
124 pub fn new(
125 tim: Peri<'d, T>,
126 _ch1_pin: Option<PwmPin<'d, T, Ch1>>,
127 _ch2_pin: Option<PwmPin<'d, T, Ch2>>,
128 freq: Hertz,
129 ) -> Self {
130 Self::new_inner(tim, freq)
131 }
132
133 /// Enable the given channel.
134 pub fn enable(&mut self, channel: Channel) {
135 self.inner.enable_channel(channel, true);
136 }
137
138 /// Disable the given channel.
139 pub fn disable(&mut self, channel: Channel) {
140 self.inner.enable_channel(channel, false);
141 }
142
143 /// Check whether given channel is enabled
144 pub fn is_enabled(&self, channel: Channel) -> bool {
145 self.inner.get_channel_enable_state(channel)
146 }
147
148 /// Set the duty for a given channel.
149 ///
150 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
151 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
152 assert!(duty <= self.get_max_duty());
153 self.inner.set_compare_value(channel, duty)
154 }
155
156 /// Get the duty for a given channel.
157 ///
158 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
159 pub fn get_duty(&self, channel: Channel) -> u16 {
160 self.inner.get_compare_value(channel)
161 }
162
163 fn post_init(&mut self) {
164 [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| {
165 self.inner.set_channel_direction(channel, ChannelDirection::OutputPwm);
166 });
167 }
168}
169
170impl<'d, T: Instance> Pwm<'d, T> {
171 fn new_inner(tim: Peri<'d, T>, freq: Hertz) -> Self {
172 let mut this = Self { inner: Timer::new(tim) };
173
174 this.inner.enable();
175 this.set_frequency(freq);
176
177 this.post_init();
178
179 this.inner.continuous_mode_start();
180
181 this
182 }
183
184 /// Set PWM frequency.
185 ///
186 /// Note: when you call this, the max duty value changes, so you will have to
187 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
188 pub fn set_frequency(&mut self, frequency: Hertz) {
189 self.inner.set_frequency(frequency);
190 }
191
192 /// Get max duty value.
193 ///
194 /// This value depends on the configured frequency and the timer's clock rate from RCC.
195 pub fn get_max_duty(&self) -> u16 {
196 self.inner.get_max_compare_value() + 1
197 }
198}
diff --git a/embassy-stm32/src/lptim/timer/channel_direction.rs b/embassy-stm32/src/lptim/timer/channel_direction.rs
new file mode 100644
index 000000000..e4af8f45f
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/channel_direction.rs
@@ -0,0 +1,18 @@
1use crate::pac::lptim::vals;
2
3/// Direction of a low-power timer channel
4pub enum ChannelDirection {
5 /// Use channel as a PWM output
6 OutputPwm,
7 /// Use channel as an input capture
8 InputCapture,
9}
10
11impl From<ChannelDirection> for vals::Ccsel {
12 fn from(direction: ChannelDirection) -> Self {
13 match direction {
14 ChannelDirection::OutputPwm => vals::Ccsel::OUTPUT_COMPARE,
15 ChannelDirection::InputCapture => vals::Ccsel::INPUT_CAPTURE,
16 }
17 }
18}
diff --git a/embassy-stm32/src/lptim/timer/mod.rs b/embassy-stm32/src/lptim/timer/mod.rs
new file mode 100644
index 000000000..a629be62b
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/mod.rs
@@ -0,0 +1,131 @@
1//! Low-level timer driver.
2mod prescaler;
3
4use embassy_hal_internal::Peri;
5
6#[cfg(any(lptim_v2a, lptim_v2b))]
7use super::channel::Channel;
8#[cfg(any(lptim_v2a, lptim_v2b))]
9mod channel_direction;
10#[cfg(any(lptim_v2a, lptim_v2b))]
11pub use channel_direction::ChannelDirection;
12use prescaler::Prescaler;
13
14use super::Instance;
15use crate::rcc;
16use crate::time::Hertz;
17
18/// Low-level timer driver.
19pub struct Timer<'d, T: Instance> {
20 _tim: Peri<'d, T>,
21}
22
23impl<'d, T: Instance> Timer<'d, T> {
24 /// Create a new timer driver.
25 pub fn new(tim: Peri<'d, T>) -> Self {
26 rcc::enable_and_reset::<T>();
27
28 Self { _tim: tim }
29 }
30
31 /// Enable the timer.
32 pub fn enable(&self) {
33 T::regs().cr().modify(|w| w.set_enable(true));
34 }
35
36 /// Disable the timer.
37 pub fn disable(&self) {
38 T::regs().cr().modify(|w| w.set_enable(false));
39 }
40
41 /// Start the timer in single pulse mode.
42 pub fn single_mode_start(&self) {
43 T::regs().cr().modify(|w| w.set_sngstrt(true));
44 }
45
46 /// Start the timer in continuous mode.
47 pub fn continuous_mode_start(&self) {
48 T::regs().cr().modify(|w| w.set_cntstrt(true));
49 }
50
51 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
52 pub fn set_frequency(&self, frequency: Hertz) {
53 let f = frequency.0;
54 assert!(f > 0);
55
56 let pclk_f = T::frequency().0;
57
58 let pclk_ticks_per_timer_period = pclk_f / f;
59
60 let psc = Prescaler::from_ticks(pclk_ticks_per_timer_period);
61 let arr = psc.scale_down(pclk_ticks_per_timer_period);
62
63 T::regs().cfgr().modify(|r| r.set_presc((&psc).into()));
64 T::regs().arr().modify(|r| r.set_arr(arr.into()));
65 }
66
67 /// Get the timer frequency.
68 pub fn get_frequency(&self) -> Hertz {
69 let pclk_f = T::frequency();
70 let arr = T::regs().arr().read().arr();
71 let psc = Prescaler::from(T::regs().cfgr().read().presc());
72
73 pclk_f / psc.scale_up(arr)
74 }
75
76 /// Get the clock frequency of the timer (before prescaler is applied).
77 pub fn get_clock_frequency(&self) -> Hertz {
78 T::frequency()
79 }
80
81 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
82 pub fn get_max_compare_value(&self) -> u16 {
83 T::regs().arr().read().arr()
84 }
85}
86
87#[cfg(any(lptim_v2a, lptim_v2b))]
88impl<'d, T: Instance> Timer<'d, T> {
89 /// Enable/disable a channel.
90 pub fn enable_channel(&self, channel: Channel, enable: bool) {
91 T::regs().ccmr(0).modify(|w| {
92 w.set_cce(channel.index(), enable);
93 });
94 }
95
96 /// Get enable/disable state of a channel
97 pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
98 T::regs().ccmr(0).read().cce(channel.index())
99 }
100
101 /// Set compare value for a channel.
102 pub fn set_compare_value(&self, channel: Channel, value: u16) {
103 T::regs().ccr(channel.index()).modify(|w| w.set_ccr(value));
104 }
105
106 /// Get compare value for a channel.
107 pub fn get_compare_value(&self, channel: Channel) -> u16 {
108 T::regs().ccr(channel.index()).read().ccr()
109 }
110
111 /// Set channel direction.
112 #[cfg(any(lptim_v2a, lptim_v2b))]
113 pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) {
114 T::regs()
115 .ccmr(0)
116 .modify(|w| w.set_ccsel(channel.index(), direction.into()));
117 }
118}
119
120#[cfg(not(any(lptim_v2a, lptim_v2b)))]
121impl<'d, T: Instance> Timer<'d, T> {
122 /// Set compare value for a channel.
123 pub fn set_compare_value(&self, value: u16) {
124 T::regs().cmp().modify(|w| w.set_cmp(value));
125 }
126
127 /// Get compare value for a channel.
128 pub fn get_compare_value(&self) -> u16 {
129 T::regs().cmp().read().cmp()
130 }
131}
diff --git a/embassy-stm32/src/lptim/timer/prescaler.rs b/embassy-stm32/src/lptim/timer/prescaler.rs
new file mode 100644
index 000000000..5d2326faf
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/prescaler.rs
@@ -0,0 +1,90 @@
1//! Low-level timer driver.
2
3use crate::pac::lptim::vals;
4
5pub enum Prescaler {
6 Div1,
7 Div2,
8 Div4,
9 Div8,
10 Div16,
11 Div32,
12 Div64,
13 Div128,
14}
15
16impl From<&Prescaler> for vals::Presc {
17 fn from(prescaler: &Prescaler) -> Self {
18 match prescaler {
19 Prescaler::Div1 => vals::Presc::DIV1,
20 Prescaler::Div2 => vals::Presc::DIV2,
21 Prescaler::Div4 => vals::Presc::DIV4,
22 Prescaler::Div8 => vals::Presc::DIV8,
23 Prescaler::Div16 => vals::Presc::DIV16,
24 Prescaler::Div32 => vals::Presc::DIV32,
25 Prescaler::Div64 => vals::Presc::DIV64,
26 Prescaler::Div128 => vals::Presc::DIV128,
27 }
28 }
29}
30
31impl From<vals::Presc> for Prescaler {
32 fn from(prescaler: vals::Presc) -> Self {
33 match prescaler {
34 vals::Presc::DIV1 => Prescaler::Div1,
35 vals::Presc::DIV2 => Prescaler::Div2,
36 vals::Presc::DIV4 => Prescaler::Div4,
37 vals::Presc::DIV8 => Prescaler::Div8,
38 vals::Presc::DIV16 => Prescaler::Div16,
39 vals::Presc::DIV32 => Prescaler::Div32,
40 vals::Presc::DIV64 => Prescaler::Div64,
41 vals::Presc::DIV128 => Prescaler::Div128,
42 }
43 }
44}
45
46impl From<&Prescaler> for u32 {
47 fn from(prescaler: &Prescaler) -> Self {
48 match prescaler {
49 Prescaler::Div1 => 1,
50 Prescaler::Div2 => 2,
51 Prescaler::Div4 => 4,
52 Prescaler::Div8 => 8,
53 Prescaler::Div16 => 16,
54 Prescaler::Div32 => 32,
55 Prescaler::Div64 => 64,
56 Prescaler::Div128 => 128,
57 }
58 }
59}
60
61impl From<u32> for Prescaler {
62 fn from(prescaler: u32) -> Self {
63 match prescaler {
64 1 => Prescaler::Div1,
65 2 => Prescaler::Div2,
66 4 => Prescaler::Div4,
67 8 => Prescaler::Div8,
68 16 => Prescaler::Div16,
69 32 => Prescaler::Div32,
70 64 => Prescaler::Div64,
71 128 => Prescaler::Div128,
72 _ => unreachable!(),
73 }
74 }
75}
76
77impl Prescaler {
78 pub fn from_ticks(ticks: u32) -> Self {
79 // We need to scale down to a 16-bit range
80 (ticks >> 16).next_power_of_two().into()
81 }
82
83 pub fn scale_down(&self, ticks: u32) -> u16 {
84 (ticks / u32::from(self)).try_into().unwrap()
85 }
86
87 pub fn scale_up(&self, ticks: u16) -> u32 {
88 u32::from(self) * ticks as u32
89 }
90}
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
index 4c5239971..0f6ef569c 100644
--- a/embassy-stm32/src/ltdc.rs
+++ b/embassy-stm32/src/ltdc.rs
@@ -6,7 +6,7 @@ use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::PeripheralType;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11use stm32_metapac::ltdc::regs::Dccr; 11use stm32_metapac::ltdc::regs::Dccr;
12use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr}; 12use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr};
@@ -14,7 +14,7 @@ use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr};
14use crate::gpio::{AfType, OutputType, Speed}; 14use crate::gpio::{AfType, OutputType, Speed};
15use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
16use crate::interrupt::{self}; 16use crate::interrupt::{self};
17use crate::{peripherals, rcc, Peripheral}; 17use crate::{peripherals, rcc, Peri};
18 18
19static LTDC_WAKER: AtomicWaker = AtomicWaker::new(); 19static LTDC_WAKER: AtomicWaker = AtomicWaker::new();
20 20
@@ -83,7 +83,7 @@ pub enum PolarityActive {
83 83
84/// LTDC driver. 84/// LTDC driver.
85pub struct Ltdc<'d, T: Instance> { 85pub struct Ltdc<'d, T: Instance> {
86 _peri: PeripheralRef<'d, T>, 86 _peri: Peri<'d, T>,
87} 87}
88 88
89/// LTDC interrupt handler. 89/// LTDC interrupt handler.
@@ -178,47 +178,45 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
178impl<'d, T: Instance> Ltdc<'d, T> { 178impl<'d, T: Instance> Ltdc<'d, T> {
179 // Create a new LTDC driver without specifying color and control pins. This is typically used if you want to drive a display though a DsiHost 179 // Create a new LTDC driver without specifying color and control pins. This is typically used if you want to drive a display though a DsiHost
180 /// Note: Full-Duplex modes are not supported at this time 180 /// Note: Full-Duplex modes are not supported at this time
181 pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self { 181 pub fn new(peri: Peri<'d, T>) -> Self {
182 Self::setup_clocks(); 182 Self::setup_clocks();
183 into_ref!(peri);
184 Self { _peri: peri } 183 Self { _peri: peri }
185 } 184 }
186 185
187 /// Create a new LTDC driver. 8 pins per color channel for blue, green and red 186 /// Create a new LTDC driver. 8 pins per color channel for blue, green and red
188 #[allow(clippy::too_many_arguments)] 187 #[allow(clippy::too_many_arguments)]
189 pub fn new_with_pins( 188 pub fn new_with_pins(
190 peri: impl Peripheral<P = T> + 'd, 189 peri: Peri<'d, T>,
191 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 190 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
192 clk: impl Peripheral<P = impl ClkPin<T>> + 'd, 191 clk: Peri<'d, impl ClkPin<T>>,
193 hsync: impl Peripheral<P = impl HsyncPin<T>> + 'd, 192 hsync: Peri<'d, impl HsyncPin<T>>,
194 vsync: impl Peripheral<P = impl VsyncPin<T>> + 'd, 193 vsync: Peri<'d, impl VsyncPin<T>>,
195 b0: impl Peripheral<P = impl B0Pin<T>> + 'd, 194 b0: Peri<'d, impl B0Pin<T>>,
196 b1: impl Peripheral<P = impl B1Pin<T>> + 'd, 195 b1: Peri<'d, impl B1Pin<T>>,
197 b2: impl Peripheral<P = impl B2Pin<T>> + 'd, 196 b2: Peri<'d, impl B2Pin<T>>,
198 b3: impl Peripheral<P = impl B3Pin<T>> + 'd, 197 b3: Peri<'d, impl B3Pin<T>>,
199 b4: impl Peripheral<P = impl B4Pin<T>> + 'd, 198 b4: Peri<'d, impl B4Pin<T>>,
200 b5: impl Peripheral<P = impl B5Pin<T>> + 'd, 199 b5: Peri<'d, impl B5Pin<T>>,
201 b6: impl Peripheral<P = impl B6Pin<T>> + 'd, 200 b6: Peri<'d, impl B6Pin<T>>,
202 b7: impl Peripheral<P = impl B7Pin<T>> + 'd, 201 b7: Peri<'d, impl B7Pin<T>>,
203 g0: impl Peripheral<P = impl G0Pin<T>> + 'd, 202 g0: Peri<'d, impl G0Pin<T>>,
204 g1: impl Peripheral<P = impl G1Pin<T>> + 'd, 203 g1: Peri<'d, impl G1Pin<T>>,
205 g2: impl Peripheral<P = impl G2Pin<T>> + 'd, 204 g2: Peri<'d, impl G2Pin<T>>,
206 g3: impl Peripheral<P = impl G3Pin<T>> + 'd, 205 g3: Peri<'d, impl G3Pin<T>>,
207 g4: impl Peripheral<P = impl G4Pin<T>> + 'd, 206 g4: Peri<'d, impl G4Pin<T>>,
208 g5: impl Peripheral<P = impl G5Pin<T>> + 'd, 207 g5: Peri<'d, impl G5Pin<T>>,
209 g6: impl Peripheral<P = impl G6Pin<T>> + 'd, 208 g6: Peri<'d, impl G6Pin<T>>,
210 g7: impl Peripheral<P = impl G7Pin<T>> + 'd, 209 g7: Peri<'d, impl G7Pin<T>>,
211 r0: impl Peripheral<P = impl R0Pin<T>> + 'd, 210 r0: Peri<'d, impl R0Pin<T>>,
212 r1: impl Peripheral<P = impl R1Pin<T>> + 'd, 211 r1: Peri<'d, impl R1Pin<T>>,
213 r2: impl Peripheral<P = impl R2Pin<T>> + 'd, 212 r2: Peri<'d, impl R2Pin<T>>,
214 r3: impl Peripheral<P = impl R3Pin<T>> + 'd, 213 r3: Peri<'d, impl R3Pin<T>>,
215 r4: impl Peripheral<P = impl R4Pin<T>> + 'd, 214 r4: Peri<'d, impl R4Pin<T>>,
216 r5: impl Peripheral<P = impl R5Pin<T>> + 'd, 215 r5: Peri<'d, impl R5Pin<T>>,
217 r6: impl Peripheral<P = impl R6Pin<T>> + 'd, 216 r6: Peri<'d, impl R6Pin<T>>,
218 r7: impl Peripheral<P = impl R7Pin<T>> + 'd, 217 r7: Peri<'d, impl R7Pin<T>>,
219 ) -> Self { 218 ) -> Self {
220 Self::setup_clocks(); 219 Self::setup_clocks();
221 into_ref!(peri);
222 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 220 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh));
223 new_pin!(hsync, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 221 new_pin!(hsync, AfType::output(OutputType::PushPull, Speed::VeryHigh));
224 new_pin!(vsync, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 222 new_pin!(vsync, AfType::output(OutputType::PushPull, Speed::VeryHigh));
@@ -261,23 +259,23 @@ impl<'d, T: Instance> Ltdc<'d, T> {
261 // configure the HS, VS, DE and PC polarity 259 // configure the HS, VS, DE and PC polarity
262 ltdc.gcr().modify(|w| { 260 ltdc.gcr().modify(|w| {
263 w.set_hspol(match config.h_sync_polarity { 261 w.set_hspol(match config.h_sync_polarity {
264 PolarityActive::ActiveHigh => Hspol::ACTIVEHIGH, 262 PolarityActive::ActiveHigh => Hspol::ACTIVE_HIGH,
265 PolarityActive::ActiveLow => Hspol::ACTIVELOW, 263 PolarityActive::ActiveLow => Hspol::ACTIVE_LOW,
266 }); 264 });
267 265
268 w.set_vspol(match config.v_sync_polarity { 266 w.set_vspol(match config.v_sync_polarity {
269 PolarityActive::ActiveHigh => Vspol::ACTIVEHIGH, 267 PolarityActive::ActiveHigh => Vspol::ACTIVE_HIGH,
270 PolarityActive::ActiveLow => Vspol::ACTIVELOW, 268 PolarityActive::ActiveLow => Vspol::ACTIVE_LOW,
271 }); 269 });
272 270
273 w.set_depol(match config.data_enable_polarity { 271 w.set_depol(match config.data_enable_polarity {
274 PolarityActive::ActiveHigh => Depol::ACTIVEHIGH, 272 PolarityActive::ActiveHigh => Depol::ACTIVE_HIGH,
275 PolarityActive::ActiveLow => Depol::ACTIVELOW, 273 PolarityActive::ActiveLow => Depol::ACTIVE_LOW,
276 }); 274 });
277 275
278 w.set_pcpol(match config.pixel_clock_polarity { 276 w.set_pcpol(match config.pixel_clock_polarity {
279 PolarityEdge::RisingEdge => Pcpol::RISINGEDGE, 277 PolarityEdge::RisingEdge => Pcpol::RISING_EDGE,
280 PolarityEdge::FallingEdge => Pcpol::FALLINGEDGE, 278 PolarityEdge::FallingEdge => Pcpol::FALLING_EDGE,
281 }); 279 });
282 }); 280 });
283 281
@@ -395,7 +393,10 @@ impl<'d, T: Instance> Ltdc<'d, T> {
395 // framebuffer pitch and line length 393 // framebuffer pitch and line length
396 layer.cfblr().modify(|w| { 394 layer.cfblr().modify(|w| {
397 w.set_cfbp(width * bytes_per_pixel); 395 w.set_cfbp(width * bytes_per_pixel);
396 #[cfg(not(stm32u5))]
398 w.set_cfbll(width * bytes_per_pixel + 7); 397 w.set_cfbll(width * bytes_per_pixel + 7);
398 #[cfg(stm32u5)]
399 w.set_cfbll(width * bytes_per_pixel + 3);
399 }); 400 });
400 401
401 // framebuffer line number 402 // framebuffer line number
@@ -526,7 +527,7 @@ trait SealedInstance: crate::rcc::SealedRccPeripheral {
526 527
527/// LTDC instance trait. 528/// LTDC instance trait.
528#[allow(private_bounds)] 529#[allow(private_bounds)]
529pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 530pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send {
530 /// Interrupt for this LTDC instance. 531 /// Interrupt for this LTDC instance.
531 type Interrupt: interrupt::typelevel::Interrupt; 532 type Interrupt: interrupt::typelevel::Interrupt;
532} 533}
diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs
index ae53deb08..7526bb180 100644
--- a/embassy-stm32/src/macros.rs
+++ b/embassy-stm32/src/macros.rs
@@ -14,7 +14,7 @@ macro_rules! peri_trait {
14 14
15 /// Peripheral instance trait. 15 /// Peripheral instance trait.
16 #[allow(private_bounds)] 16 #[allow(private_bounds)]
17 pub trait Instance: crate::Peripheral<P = Self> + SealedInstance + crate::rcc::RccPeripheral { 17 pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral {
18 $($( 18 $($(
19 /// Interrupt for this peripheral. 19 /// Interrupt for this peripheral.
20 type $irq: crate::interrupt::typelevel::Interrupt; 20 type $irq: crate::interrupt::typelevel::Interrupt;
@@ -60,6 +60,17 @@ macro_rules! pin_trait_impl {
60 }; 60 };
61} 61}
62 62
63#[allow(unused_macros)]
64macro_rules! sel_trait_impl {
65 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $sel:expr) => {
66 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin {
67 fn sel(&self) -> u8 {
68 $sel
69 }
70 }
71 };
72}
73
63// ==================== 74// ====================
64 75
65macro_rules! dma_trait { 76macro_rules! dma_trait {
@@ -85,12 +96,24 @@ macro_rules! dma_trait_impl {
85 }; 96 };
86} 97}
87 98
99#[allow(unused)]
100macro_rules! new_dma_nonopt {
101 ($name:ident) => {{
102 let dma = $name;
103 let request = dma.request();
104 crate::dma::ChannelAndRequest {
105 channel: dma.into(),
106 request,
107 }
108 }};
109}
110
88macro_rules! new_dma { 111macro_rules! new_dma {
89 ($name:ident) => {{ 112 ($name:ident) => {{
90 let dma = $name.into_ref(); 113 let dma = $name;
91 let request = dma.request(); 114 let request = dma.request();
92 Some(crate::dma::ChannelAndRequest { 115 Some(crate::dma::ChannelAndRequest {
93 channel: dma.map_into(), 116 channel: dma.into(),
94 request, 117 request,
95 }) 118 })
96 }}; 119 }};
@@ -98,8 +121,8 @@ macro_rules! new_dma {
98 121
99macro_rules! new_pin { 122macro_rules! new_pin {
100 ($name:ident, $af_type:expr) => {{ 123 ($name:ident, $af_type:expr) => {{
101 let pin = $name.into_ref(); 124 let pin = $name;
102 pin.set_as_af(pin.af_num(), $af_type); 125 pin.set_as_af(pin.af_num(), $af_type);
103 Some(pin.map_into()) 126 Some(pin.into())
104 }}; 127 }};
105} 128}
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index c86c18e22..2eb2e61c1 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -1,40 +1,48 @@
1//! Operational Amplifier (OPAMP) 1//! Operational Amplifier (OPAMP)
2#![macro_use] 2#![macro_use]
3 3
4use embassy_hal_internal::{into_ref, PeripheralRef}; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::pac::opamp::vals::*; 6use crate::pac::opamp::vals::*;
7use crate::Peripheral; 7use crate::Peri;
8
9/// Performs a busy-wait delay for a specified number of microseconds.
10#[cfg(opamp_g4)]
11fn blocking_delay_ms(ms: u32) {
12 #[cfg(feature = "time")]
13 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
14 #[cfg(not(feature = "time"))]
15 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms);
16}
8 17
9/// Gain 18/// Gain
10#[allow(missing_docs)] 19#[allow(missing_docs)]
11#[derive(Clone, Copy)] 20#[derive(Clone, Copy)]
12pub enum OpAmpGain { 21pub enum OpAmpGain {
13 Mul1,
14 Mul2, 22 Mul2,
15 Mul4, 23 Mul4,
16 Mul8, 24 Mul8,
17 Mul16, 25 Mul16,
26 #[cfg(opamp_g4)]
27 Mul32,
28 #[cfg(opamp_g4)]
29 Mul64,
30}
31
32#[cfg(opamp_g4)]
33enum OpAmpDifferentialPair {
34 P,
35 N,
18} 36}
19 37
20/// Speed 38/// Speed
21#[allow(missing_docs)] 39#[allow(missing_docs)]
22#[derive(Clone, Copy)] 40#[derive(Clone, Copy, PartialEq)]
23pub enum OpAmpSpeed { 41pub enum OpAmpSpeed {
24 Normal, 42 Normal,
25 HighSpeed, 43 HighSpeed,
26} 44}
27 45
28#[cfg(opamp_g4)]
29impl From<OpAmpSpeed> for crate::pac::opamp::vals::Opahsm {
30 fn from(v: OpAmpSpeed) -> Self {
31 match v {
32 OpAmpSpeed::Normal => crate::pac::opamp::vals::Opahsm::NORMAL,
33 OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGHSPEED,
34 }
35 }
36}
37
38/// OpAmp external outputs, wired to a GPIO pad. 46/// OpAmp external outputs, wired to a GPIO pad.
39/// 47///
40/// This struct can also be used as an ADC input. 48/// This struct can also be used as an ADC input.
@@ -52,19 +60,17 @@ pub struct OpAmpInternalOutput<'d, T: Instance> {
52 60
53/// OpAmp driver. 61/// OpAmp driver.
54pub struct OpAmp<'d, T: Instance> { 62pub struct OpAmp<'d, T: Instance> {
55 _inner: PeripheralRef<'d, T>, 63 _inner: Peri<'d, T>,
56} 64}
57 65
58impl<'d, T: Instance> OpAmp<'d, T> { 66impl<'d, T: Instance> OpAmp<'d, T> {
59 /// Create a new driver instance. 67 /// Create a new driver instance.
60 /// 68 ///
61 /// Does not enable the opamp, but does set the speed mode on some families. 69 /// Does not enable the opamp, but does set the speed mode on some families.
62 pub fn new(opamp: impl Peripheral<P = T> + 'd, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { 70 pub fn new(opamp: Peri<'d, T>, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self {
63 into_ref!(opamp);
64
65 #[cfg(opamp_g4)] 71 #[cfg(opamp_g4)]
66 T::regs().csr().modify(|w| { 72 T::regs().csr().modify(|w| {
67 w.set_opahsm(speed.into()); 73 w.set_opahsm(speed == OpAmpSpeed::HighSpeed);
68 }); 74 });
69 75
70 Self { _inner: opamp } 76 Self { _inner: opamp }
@@ -82,35 +88,81 @@ impl<'d, T: Instance> OpAmp<'d, T> {
82 /// [`OpAmpOutput`] is dropped. 88 /// [`OpAmpOutput`] is dropped.
83 pub fn buffer_ext( 89 pub fn buffer_ext(
84 &mut self, 90 &mut self,
85 in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>, 91 in_pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>,
86 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>, 92 out_pin: Peri<'_, impl OutputPin<T> + crate::gpio::Pin>,
93 ) -> OpAmpOutput<'_, T> {
94 in_pin.set_as_analog();
95 out_pin.set_as_analog();
96
97 #[cfg(opamp_g4)]
98 let vm_sel = VmSel::OUTPUT;
99 #[cfg(not(opamp_g4))]
100 let vm_sel = VmSel::from_bits(0b11);
101
102 T::regs().csr().modify(|w| {
103 w.set_vp_sel(VpSel::from_bits(in_pin.channel()));
104 w.set_vm_sel(vm_sel);
105 #[cfg(opamp_g4)]
106 w.set_opaintoen(false);
107 w.set_opampen(true);
108 });
109
110 OpAmpOutput { _inner: self }
111 }
112
113 /// Configure the OpAmp as a PGA for the provided input pin,
114 /// outputting to the provided output pin, and enable the opamp.
115 ///
116 /// The input pin is configured for analogue mode but not consumed,
117 /// so it may subsequently be used for ADC or comparator inputs.
118 ///
119 /// The output pin is held within the returned [`OpAmpOutput`] struct,
120 /// preventing it being used elsewhere. The `OpAmpOutput` can then be
121 /// directly used as an ADC input. The opamp will be disabled when the
122 /// [`OpAmpOutput`] is dropped.
123 pub fn pga_ext(
124 &mut self,
125 in_pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>,
126 out_pin: Peri<'_, impl OutputPin<T> + crate::gpio::Pin>,
87 gain: OpAmpGain, 127 gain: OpAmpGain,
88 ) -> OpAmpOutput<'_, T> { 128 ) -> OpAmpOutput<'_, T> {
89 into_ref!(in_pin);
90 into_ref!(out_pin);
91 in_pin.set_as_analog(); 129 in_pin.set_as_analog();
92 out_pin.set_as_analog(); 130 out_pin.set_as_analog();
93 131
94 // PGA_GAIN value may have different meaning in different MCU serials, use with caution. 132 #[cfg(opamp_g4)]
95 let (vm_sel, pga_gain) = match gain { 133 let vm_sel = VmSel::PGA;
96 OpAmpGain::Mul1 => (0b11, 0b00), 134 #[cfg(not(opamp_g4))]
97 OpAmpGain::Mul2 => (0b10, 0b00), 135 let vm_sel = VmSel::from_bits(0b10);
98 OpAmpGain::Mul4 => (0b10, 0b01), 136
99 OpAmpGain::Mul8 => (0b10, 0b10), 137 #[cfg(opamp_g4)]
100 OpAmpGain::Mul16 => (0b10, 0b11), 138 let pga_gain = match gain {
139 OpAmpGain::Mul2 => PgaGain::GAIN2,
140 OpAmpGain::Mul4 => PgaGain::GAIN4,
141 OpAmpGain::Mul8 => PgaGain::GAIN8,
142 OpAmpGain::Mul16 => PgaGain::GAIN16,
143 OpAmpGain::Mul32 => PgaGain::GAIN32,
144 OpAmpGain::Mul64 => PgaGain::GAIN64,
101 }; 145 };
146 #[cfg(not(opamp_g4))]
147 let pga_gain = PgaGain::from_bits(match gain {
148 OpAmpGain::Mul2 => 0b00,
149 OpAmpGain::Mul4 => 0b01,
150 OpAmpGain::Mul8 => 0b10,
151 OpAmpGain::Mul16 => 0b11,
152 });
102 153
103 T::regs().csr().modify(|w| { 154 T::regs().csr().modify(|w| {
104 w.set_vp_sel(VpSel::from_bits(in_pin.channel())); 155 w.set_vp_sel(VpSel::from_bits(in_pin.channel()));
105 w.set_vm_sel(VmSel::from_bits(vm_sel)); 156 w.set_vm_sel(vm_sel);
106 w.set_pga_gain(PgaGain::from_bits(pga_gain)); 157 w.set_pga_gain(pga_gain);
107 #[cfg(opamp_g4)] 158 #[cfg(opamp_g4)]
108 w.set_opaintoen(Opaintoen::OUTPUTPIN); 159 w.set_opaintoen(false);
109 w.set_opampen(true); 160 w.set_opampen(true);
110 }); 161 });
111 162
112 OpAmpOutput { _inner: self } 163 OpAmpOutput { _inner: self }
113 } 164 }
165
114 /// Configure the OpAmp as a buffer for the DAC it is connected to, 166 /// Configure the OpAmp as a buffer for the DAC it is connected to,
115 /// outputting to the provided output pin, and enable the opamp. 167 /// outputting to the provided output pin, and enable the opamp.
116 /// 168 ///
@@ -119,11 +171,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
119 /// directly used as an ADC input. The opamp will be disabled when the 171 /// directly used as an ADC input. The opamp will be disabled when the
120 /// [`OpAmpOutput`] is dropped. 172 /// [`OpAmpOutput`] is dropped.
121 #[cfg(opamp_g4)] 173 #[cfg(opamp_g4)]
122 pub fn buffer_dac( 174 pub fn buffer_dac(&mut self, out_pin: Peri<'_, impl OutputPin<T> + crate::gpio::Pin>) -> OpAmpOutput<'_, T> {
123 &mut self,
124 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
125 ) -> OpAmpOutput<'_, T> {
126 into_ref!(out_pin);
127 out_pin.set_as_analog(); 175 out_pin.set_as_analog();
128 176
129 T::regs().csr().modify(|w| { 177 T::regs().csr().modify(|w| {
@@ -131,7 +179,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
131 179
132 w.set_vm_sel(VmSel::OUTPUT); 180 w.set_vm_sel(VmSel::OUTPUT);
133 w.set_vp_sel(VpSel::DAC3_CH1); 181 w.set_vp_sel(VpSel::DAC3_CH1);
134 w.set_opaintoen(Opaintoen::OUTPUTPIN); 182 w.set_opaintoen(false);
135 w.set_opampen(true); 183 w.set_opampen(true);
136 }); 184 });
137 185
@@ -149,32 +197,259 @@ impl<'d, T: Instance> OpAmp<'d, T> {
149 #[cfg(opamp_g4)] 197 #[cfg(opamp_g4)]
150 pub fn buffer_int( 198 pub fn buffer_int(
151 &mut self, 199 &mut self,
152 pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>, 200 pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>,
201 ) -> OpAmpInternalOutput<'_, T> {
202 pin.set_as_analog();
203
204 T::regs().csr().modify(|w| {
205 w.set_vp_sel(VpSel::from_bits(pin.channel()));
206 w.set_vm_sel(VmSel::OUTPUT);
207 #[cfg(opamp_g4)]
208 w.set_opaintoen(true);
209 w.set_opampen(true);
210 });
211
212 OpAmpInternalOutput { _inner: self }
213 }
214
215 /// Configure the OpAmp as a PGA for the provided input pin,
216 /// with the output only used internally, and enable the opamp.
217 ///
218 /// The input pin is configured for analogue mode but not consumed,
219 /// so it may be subsequently used for ADC or comparator inputs.
220 ///
221 /// The returned `OpAmpInternalOutput` struct may be used as an ADC input.
222 /// The opamp output will be disabled when it is dropped.
223 #[cfg(opamp_g4)]
224 pub fn pga_int(
225 &mut self,
226 pin: Peri<'_, impl NonInvertingPin<T> + crate::gpio::Pin>,
153 gain: OpAmpGain, 227 gain: OpAmpGain,
154 ) -> OpAmpInternalOutput<'_, T> { 228 ) -> OpAmpInternalOutput<'_, T> {
155 into_ref!(pin);
156 pin.set_as_analog(); 229 pin.set_as_analog();
157 230
158 // PGA_GAIN value may have different meaning in different MCU serials, use with caution. 231 let pga_gain = match gain {
159 let (vm_sel, pga_gain) = match gain { 232 OpAmpGain::Mul2 => PgaGain::GAIN2,
160 OpAmpGain::Mul1 => (0b11, 0b00), 233 OpAmpGain::Mul4 => PgaGain::GAIN4,
161 OpAmpGain::Mul2 => (0b10, 0b00), 234 OpAmpGain::Mul8 => PgaGain::GAIN8,
162 OpAmpGain::Mul4 => (0b10, 0b01), 235 OpAmpGain::Mul16 => PgaGain::GAIN16,
163 OpAmpGain::Mul8 => (0b10, 0b10), 236 OpAmpGain::Mul32 => PgaGain::GAIN32,
164 OpAmpGain::Mul16 => (0b10, 0b11), 237 OpAmpGain::Mul64 => PgaGain::GAIN64,
165 }; 238 };
166 239
167 T::regs().csr().modify(|w| { 240 T::regs().csr().modify(|w| {
168 use crate::pac::opamp::vals::*;
169 w.set_vp_sel(VpSel::from_bits(pin.channel())); 241 w.set_vp_sel(VpSel::from_bits(pin.channel()));
170 w.set_vm_sel(VmSel::from_bits(vm_sel)); 242 w.set_vm_sel(VmSel::PGA);
171 w.set_pga_gain(PgaGain::from_bits(pga_gain)); 243 w.set_pga_gain(pga_gain);
172 w.set_opaintoen(Opaintoen::ADCCHANNEL); 244 w.set_opaintoen(true);
245 w.set_opampen(true);
246 });
247
248 OpAmpInternalOutput { _inner: self }
249 }
250
251 /// Configure the OpAmp as a standalone DAC with the inverting input
252 /// connected to the provided pin, and the output is connected
253 /// internally to an ADC channel.
254 ///
255 /// The input pin is configured for analogue mode but not consumed,
256 /// so it may be subsequently used for ADC or comparator inputs.
257 ///
258 /// The returned `OpAmpInternalOutput` struct may be used as an ADC
259 /// input. The opamp output will be disabled when it is dropped.
260 #[cfg(opamp_g4)]
261 pub fn standalone_dac_int(
262 &mut self,
263 m_pin: Peri<'_, impl InvertingPin<T> + crate::gpio::Pin>,
264 ) -> OpAmpInternalOutput<'_, T> {
265 m_pin.set_as_analog();
266
267 T::regs().csr().modify(|w| {
268 use crate::pac::opamp::vals::*;
269 w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx
270 w.set_vm_sel(VmSel::from_bits(m_pin.channel()));
271 w.set_opaintoen(true);
173 w.set_opampen(true); 272 w.set_opampen(true);
174 }); 273 });
175 274
176 OpAmpInternalOutput { _inner: self } 275 OpAmpInternalOutput { _inner: self }
177 } 276 }
277
278 /// Configure the OpAmp as a standalone DAC with the inverting input
279 /// connected to the provided pin, and the output connected to the
280 /// provided pin.
281 ///
282 /// The input pin is configured for analogue mode but not consumed,
283 /// so it may be subsequently used for ADC or comparator inputs.
284 ///
285 /// The output pin is held within the returned [`OpAmpOutput`] struct,
286 /// preventing it being used elsewhere. The opamp will be disabled when
287 /// the [`OpAmpOutput`] is dropped.
288 #[cfg(opamp_g4)]
289 pub fn standalone_dac_ext(
290 &mut self,
291 m_pin: Peri<'_, impl InvertingPin<T> + crate::gpio::Pin>,
292 out_pin: Peri<'_, impl OutputPin<T> + crate::gpio::Pin>,
293 ) -> OpAmpOutput<'_, T> {
294 m_pin.set_as_analog();
295 out_pin.set_as_analog();
296
297 T::regs().csr().modify(|w| {
298 use crate::pac::opamp::vals::*;
299 w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx
300 w.set_vm_sel(VmSel::from_bits(m_pin.channel()));
301 w.set_opaintoen(false);
302 w.set_opampen(true);
303 });
304
305 OpAmpOutput { _inner: self }
306 }
307
308 /// Configure the OpAmp in standalone mode with the non-inverting input
309 /// connected to the provided `p_pin`, the inverting input connected to
310 /// the `m_pin`, and output to the provided `out_pin`.
311 ///
312 /// The input pins are configured for analogue mode but not consumed,
313 /// allowing their subsequent use for ADC or comparator inputs.
314 ///
315 /// The output pin is held within the returned [`OpAmpOutput`] struct,
316 /// preventing it being used elsewhere. The opamp will be disabled when
317 /// the [`OpAmpOutput`] is dropped.
318 #[cfg(opamp_g4)]
319 pub fn standalone_ext(
320 &mut self,
321 p_pin: Peri<'d, impl NonInvertingPin<T> + crate::gpio::Pin>,
322 m_pin: Peri<'d, impl InvertingPin<T> + crate::gpio::Pin>,
323 out_pin: Peri<'d, impl OutputPin<T> + crate::gpio::Pin>,
324 ) -> OpAmpOutput<'_, T> {
325 p_pin.set_as_analog();
326 m_pin.set_as_analog();
327 out_pin.set_as_analog();
328
329 T::regs().csr().modify(|w| {
330 use crate::pac::opamp::vals::*;
331 w.set_vp_sel(VpSel::from_bits(p_pin.channel()));
332 w.set_vm_sel(VmSel::from_bits(m_pin.channel()));
333 w.set_opaintoen(false);
334 w.set_opampen(true);
335 });
336
337 OpAmpOutput { _inner: self }
338 }
339
340 /// Configure the OpAmp in standalone mode with the non-inverting input
341 /// connected to the provided `p_pin`, the inverting input connected to
342 /// the `m_pin`, and output is connected to the DAC.
343 ///
344 /// The input pins are configured for analogue mode but not consumed,
345 /// allowing their subsequent use for ADC or comparator inputs.
346 ///
347 /// The returned `OpAmpOutput` struct may be used as an ADC
348 /// input. The opamp output will be disabled when it is dropped.
349 #[cfg(opamp_g4)]
350 pub fn standalone_int(
351 &mut self,
352 p_pin: Peri<'d, impl NonInvertingPin<T> + crate::gpio::Pin>,
353 m_pin: Peri<'d, impl InvertingPin<T> + crate::gpio::Pin>,
354 ) -> OpAmpOutput<'_, T> {
355 p_pin.set_as_analog();
356 m_pin.set_as_analog();
357
358 T::regs().csr().modify(|w| {
359 use crate::pac::opamp::vals::*;
360 w.set_vp_sel(VpSel::from_bits(p_pin.channel()));
361 w.set_vm_sel(VmSel::from_bits(m_pin.channel()));
362 w.set_opaintoen(true);
363 w.set_opampen(true);
364 });
365
366 OpAmpOutput { _inner: self }
367 }
368
369 /// Calibrates the operational amplifier.
370 ///
371 /// This function enables the opamp and sets the user trim mode for calibration.
372 /// Depending on the speed mode of the opamp, it calibrates the differential pair inputs.
373 /// For normal speed, both the P and N differential pairs are calibrated,
374 /// while for high-speed mode, only the P differential pair is calibrated.
375 ///
376 /// Calibrating a differential pair requires waiting 12ms in the worst case (binary method).
377 #[cfg(opamp_g4)]
378 pub fn calibrate(&mut self) {
379 T::regs().csr().modify(|w| {
380 w.set_opampen(true);
381 w.set_calon(true);
382 w.set_usertrim(true);
383 });
384
385 if T::regs().csr().read().opahsm() {
386 self.calibrate_differential_pair(OpAmpDifferentialPair::P);
387 } else {
388 self.calibrate_differential_pair(OpAmpDifferentialPair::P);
389 self.calibrate_differential_pair(OpAmpDifferentialPair::N);
390 }
391
392 T::regs().csr().modify(|w| {
393 w.set_calon(false);
394 w.set_opampen(false);
395 });
396 }
397
398 /// Calibrate differential pair.
399 ///
400 /// The calibration is done by trying different offset values and
401 /// measuring the outcal bit.
402 ///
403 /// The calibration range is from 0 to 31.
404 ///
405 /// The result is stored in the OPAMP_CSR register.
406 #[cfg(opamp_g4)]
407 fn calibrate_differential_pair(&mut self, pair: OpAmpDifferentialPair) {
408 let mut low = 0;
409 let mut high = 31;
410
411 let calsel = match pair {
412 OpAmpDifferentialPair::P => Calsel::PERCENT10,
413 OpAmpDifferentialPair::N => Calsel::PERCENT90,
414 };
415
416 T::regs().csr().modify(|w| {
417 w.set_calsel(calsel);
418 });
419
420 while low <= high {
421 let mid = (low + high) / 2;
422
423 T::regs().csr().modify(|w| match pair {
424 OpAmpDifferentialPair::P => {
425 #[cfg(feature = "defmt")]
426 defmt::debug!("opamp p calibration. offset: {}", mid);
427 w.set_trimoffsetp(mid);
428 }
429 OpAmpDifferentialPair::N => {
430 #[cfg(feature = "defmt")]
431 defmt::debug!("opamp n calibration. offset: {}", mid);
432 w.set_trimoffsetn(mid);
433 }
434 });
435
436 // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize
437 // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7
438 blocking_delay_ms(2);
439
440 if !T::regs().csr().read().calout() {
441 if mid == 0 {
442 break;
443 }
444 high = mid - 1;
445 } else {
446 if mid == 31 {
447 break;
448 }
449 low = mid + 1;
450 }
451 }
452 }
178} 453}
179 454
180impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { 455impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> {
@@ -211,7 +486,7 @@ pub(crate) trait SealedOutputPin<T: Instance> {}
211 486
212/// Opamp instance trait. 487/// Opamp instance trait.
213#[allow(private_bounds)] 488#[allow(private_bounds)]
214pub trait Instance: SealedInstance + 'static {} 489pub trait Instance: SealedInstance + PeripheralType + 'static {}
215/// Non-inverting pin trait. 490/// Non-inverting pin trait.
216#[allow(private_bounds)] 491#[allow(private_bounds)]
217pub trait NonInvertingPin<T: Instance>: SealedNonInvertingPin<T> {} 492pub trait NonInvertingPin<T: Instance>: SealedNonInvertingPin<T> {}
@@ -251,10 +526,12 @@ foreach_peripheral!(
251 impl_opamp_external_output!(OPAMP2, ADC2, 3); 526 impl_opamp_external_output!(OPAMP2, ADC2, 3);
252 }; 527 };
253 (opamp, OPAMP3) => { 528 (opamp, OPAMP3) => {
529 impl_opamp_external_output!(OPAMP3, ADC1, 12);
254 impl_opamp_external_output!(OPAMP3, ADC3, 1); 530 impl_opamp_external_output!(OPAMP3, ADC3, 1);
255 }; 531 };
256 // OPAMP4 only in STM32G4 Cat 3 devices 532 // OPAMP4 only in STM32G4 Cat 3 devices
257 (opamp, OPAMP4) => { 533 (opamp, OPAMP4) => {
534 impl_opamp_external_output!(OPAMP4, ADC1, 11);
258 impl_opamp_external_output!(OPAMP4, ADC4, 3); 535 impl_opamp_external_output!(OPAMP4, ADC4, 3);
259 }; 536 };
260 // OPAMP5 only in STM32G4 Cat 3 devices 537 // OPAMP5 only in STM32G4 Cat 3 devices
@@ -264,6 +541,7 @@ foreach_peripheral!(
264 // OPAMP6 only in STM32G4 Cat 3/4 devices 541 // OPAMP6 only in STM32G4 Cat 3/4 devices
265 (opamp, OPAMP6) => { 542 (opamp, OPAMP6) => {
266 impl_opamp_external_output!(OPAMP6, ADC1, 14); 543 impl_opamp_external_output!(OPAMP6, ADC1, 14);
544 impl_opamp_external_output!(OPAMP6, ADC2, 14);
267 }; 545 };
268); 546);
269 547
@@ -345,6 +623,18 @@ macro_rules! impl_opamp_vp_pin {
345} 623}
346 624
347#[allow(unused_macros)] 625#[allow(unused_macros)]
626macro_rules! impl_opamp_vn_pin {
627 ($inst:ident, $pin:ident, $ch:expr) => {
628 impl crate::opamp::InvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
629 impl crate::opamp::SealedInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
630 fn channel(&self) -> u8 {
631 $ch
632 }
633 }
634 };
635}
636
637#[allow(unused_macros)]
348macro_rules! impl_opamp_vout_pin { 638macro_rules! impl_opamp_vout_pin {
349 ($inst:ident, $pin:ident) => { 639 ($inst:ident, $pin:ident) => {
350 impl crate::opamp::OutputPin<peripherals::$inst> for crate::peripherals::$pin {} 640 impl crate::opamp::OutputPin<peripherals::$inst> for crate::peripherals::$pin {}
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index 289bfa672..74edfd5e4 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -8,7 +8,7 @@ pub mod enums;
8use core::marker::PhantomData; 8use core::marker::PhantomData;
9 9
10use embassy_embedded_hal::{GetConfig, SetConfig}; 10use embassy_embedded_hal::{GetConfig, SetConfig};
11use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::PeripheralType;
12pub use enums::*; 12pub use enums::*;
13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; 13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits};
14 14
@@ -16,8 +16,10 @@ use crate::dma::{word, ChannelAndRequest};
16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
17use crate::mode::{Async, Blocking, Mode as PeriMode}; 17use crate::mode::{Async, Blocking, Mode as PeriMode};
18use crate::pac::octospi::{vals, Octospi as Regs}; 18use crate::pac::octospi::{vals, Octospi as Regs};
19#[cfg(octospim_v1)]
20use crate::pac::octospim::Octospim;
19use crate::rcc::{self, RccPeripheral}; 21use crate::rcc::{self, RccPeripheral};
20use crate::{peripherals, Peripheral}; 22use crate::{peripherals, Peri};
21 23
22/// OPSI driver config. 24/// OPSI driver config.
23#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
@@ -50,7 +52,7 @@ pub struct Config {
50 /// Enables the transaction boundary feature and defines the boundary to release 52 /// Enables the transaction boundary feature and defines the boundary to release
51 /// the chip select 53 /// the chip select
52 pub chip_select_boundary: u8, 54 pub chip_select_boundary: u8,
53 /// Enbales the delay block bypass so the sampling is not affected by the delay block 55 /// Enables the delay block bypass so the sampling is not affected by the delay block
54 pub delay_block_bypass: bool, 56 pub delay_block_bypass: bool,
55 /// Enables communication regulation feature. Chip select is released when the other 57 /// Enables communication regulation feature. Chip select is released when the other
56 /// OctoSpi requests access to the bus 58 /// OctoSpi requests access to the bus
@@ -158,18 +160,18 @@ pub enum OspiError {
158 160
159/// OSPI driver. 161/// OSPI driver.
160pub struct Ospi<'d, T: Instance, M: PeriMode> { 162pub struct Ospi<'d, T: Instance, M: PeriMode> {
161 _peri: PeripheralRef<'d, T>, 163 _peri: Peri<'d, T>,
162 sck: Option<PeripheralRef<'d, AnyPin>>, 164 sck: Option<Peri<'d, AnyPin>>,
163 d0: Option<PeripheralRef<'d, AnyPin>>, 165 d0: Option<Peri<'d, AnyPin>>,
164 d1: Option<PeripheralRef<'d, AnyPin>>, 166 d1: Option<Peri<'d, AnyPin>>,
165 d2: Option<PeripheralRef<'d, AnyPin>>, 167 d2: Option<Peri<'d, AnyPin>>,
166 d3: Option<PeripheralRef<'d, AnyPin>>, 168 d3: Option<Peri<'d, AnyPin>>,
167 d4: Option<PeripheralRef<'d, AnyPin>>, 169 d4: Option<Peri<'d, AnyPin>>,
168 d5: Option<PeripheralRef<'d, AnyPin>>, 170 d5: Option<Peri<'d, AnyPin>>,
169 d6: Option<PeripheralRef<'d, AnyPin>>, 171 d6: Option<Peri<'d, AnyPin>>,
170 d7: Option<PeripheralRef<'d, AnyPin>>, 172 d7: Option<Peri<'d, AnyPin>>,
171 nss: Option<PeripheralRef<'d, AnyPin>>, 173 nss: Option<Peri<'d, AnyPin>>,
172 dqs: Option<PeripheralRef<'d, AnyPin>>, 174 dqs: Option<Peri<'d, AnyPin>>,
173 dma: Option<ChannelAndRequest<'d>>, 175 dma: Option<ChannelAndRequest<'d>>,
174 _phantom: PhantomData<M>, 176 _phantom: PhantomData<M>,
175 config: Config, 177 config: Config,
@@ -177,25 +179,165 @@ pub struct Ospi<'d, T: Instance, M: PeriMode> {
177} 179}
178 180
179impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { 181impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
182 /// Enter memory mode.
183 /// The Input `read_config` is used to configure the read operation in memory mode
184 pub fn enable_memory_mapped_mode(
185 &mut self,
186 read_config: TransferConfig,
187 write_config: TransferConfig,
188 ) -> Result<(), OspiError> {
189 // Use configure command to set read config
190 self.configure_command(&read_config, None)?;
191
192 let reg = T::REGS;
193 while reg.sr().read().busy() {}
194
195 reg.ccr().modify(|r| {
196 r.set_dqse(false);
197 r.set_sioo(true);
198 });
199
200 // Set wrting configurations, there are separate registers for write configurations in memory mapped mode
201 reg.wccr().modify(|w| {
202 w.set_imode(PhaseMode::from_bits(write_config.iwidth.into()));
203 w.set_idtr(write_config.idtr);
204 w.set_isize(SizeInBits::from_bits(write_config.isize.into()));
205
206 w.set_admode(PhaseMode::from_bits(write_config.adwidth.into()));
207 w.set_addtr(write_config.idtr);
208 w.set_adsize(SizeInBits::from_bits(write_config.adsize.into()));
209
210 w.set_dmode(PhaseMode::from_bits(write_config.dwidth.into()));
211 w.set_ddtr(write_config.ddtr);
212
213 w.set_abmode(PhaseMode::from_bits(write_config.abwidth.into()));
214 w.set_dqse(true);
215 });
216
217 reg.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into()));
218
219 // Enable memory mapped mode
220 reg.cr().modify(|r| {
221 r.set_fmode(crate::ospi::vals::FunctionalMode::MEMORY_MAPPED);
222 r.set_tcen(false);
223 });
224 Ok(())
225 }
226
227 /// Quit from memory mapped mode
228 pub fn disable_memory_mapped_mode(&mut self) {
229 let reg = T::REGS;
230
231 reg.cr().modify(|r| {
232 r.set_fmode(crate::ospi::vals::FunctionalMode::INDIRECT_WRITE);
233 r.set_abort(true);
234 r.set_dmaen(false);
235 r.set_en(false);
236 });
237
238 // Clear transfer complete flag
239 reg.fcr().write(|w| w.set_ctcf(true));
240
241 // Re-enable ospi
242 reg.cr().modify(|r| {
243 r.set_en(true);
244 });
245 }
246
180 fn new_inner( 247 fn new_inner(
181 peri: impl Peripheral<P = T> + 'd, 248 peri: Peri<'d, T>,
182 d0: Option<PeripheralRef<'d, AnyPin>>, 249 d0: Option<Peri<'d, AnyPin>>,
183 d1: Option<PeripheralRef<'d, AnyPin>>, 250 d1: Option<Peri<'d, AnyPin>>,
184 d2: Option<PeripheralRef<'d, AnyPin>>, 251 d2: Option<Peri<'d, AnyPin>>,
185 d3: Option<PeripheralRef<'d, AnyPin>>, 252 d3: Option<Peri<'d, AnyPin>>,
186 d4: Option<PeripheralRef<'d, AnyPin>>, 253 d4: Option<Peri<'d, AnyPin>>,
187 d5: Option<PeripheralRef<'d, AnyPin>>, 254 d5: Option<Peri<'d, AnyPin>>,
188 d6: Option<PeripheralRef<'d, AnyPin>>, 255 d6: Option<Peri<'d, AnyPin>>,
189 d7: Option<PeripheralRef<'d, AnyPin>>, 256 d7: Option<Peri<'d, AnyPin>>,
190 sck: Option<PeripheralRef<'d, AnyPin>>, 257 sck: Option<Peri<'d, AnyPin>>,
191 nss: Option<PeripheralRef<'d, AnyPin>>, 258 nss: Option<Peri<'d, AnyPin>>,
192 dqs: Option<PeripheralRef<'d, AnyPin>>, 259 dqs: Option<Peri<'d, AnyPin>>,
193 dma: Option<ChannelAndRequest<'d>>, 260 dma: Option<ChannelAndRequest<'d>>,
194 config: Config, 261 config: Config,
195 width: OspiWidth, 262 width: OspiWidth,
196 dual_quad: bool, 263 dual_quad: bool,
197 ) -> Self { 264 ) -> Self {
198 into_ref!(peri); 265 #[cfg(octospim_v1)]
266 {
267 // RCC for octospim should be enabled before writing register
268 #[cfg(stm32l4)]
269 crate::pac::RCC.ahb2smenr().modify(|w| w.set_octospimsmen(true));
270 #[cfg(stm32u5)]
271 crate::pac::RCC.ahb2enr1().modify(|w| w.set_octospimen(true));
272 #[cfg(not(any(stm32l4, stm32u5)))]
273 crate::pac::RCC.ahb3enr().modify(|w| w.set_iomngren(true));
274
275 // Disable OctoSPI peripheral first
276 T::REGS.cr().modify(|w| {
277 w.set_en(false);
278 });
279
280 // OctoSPI IO Manager has been enabled before
281 T::OCTOSPIM_REGS.cr().modify(|w| {
282 w.set_muxen(false);
283 w.set_req2ack_time(0xff);
284 });
285
286 // Clear config
287 T::OCTOSPIM_REGS.p1cr().modify(|w| {
288 w.set_clksrc(false);
289 w.set_dqssrc(false);
290 w.set_ncssrc(false);
291 w.set_clken(false);
292 w.set_dqsen(false);
293 w.set_ncsen(false);
294 w.set_iolsrc(0);
295 w.set_iohsrc(0);
296 });
297
298 T::OCTOSPIM_REGS.p1cr().modify(|w| {
299 let octospi_src = if T::OCTOSPI_IDX == 1 { false } else { true };
300 w.set_ncsen(true);
301 w.set_ncssrc(octospi_src);
302 w.set_clken(true);
303 w.set_clksrc(octospi_src);
304 if dqs.is_some() {
305 w.set_dqsen(true);
306 w.set_dqssrc(octospi_src);
307 }
308
309 // Set OCTOSPIM IOL and IOH according to the index of OCTOSPI instance
310 if T::OCTOSPI_IDX == 1 {
311 w.set_iolen(true);
312 w.set_iolsrc(0);
313 // Enable IOH in octo and dual quad mode
314 if let OspiWidth::OCTO = width {
315 w.set_iohen(true);
316 w.set_iohsrc(0b01);
317 } else if dual_quad {
318 w.set_iohen(true);
319 w.set_iohsrc(0b00);
320 } else {
321 w.set_iohen(false);
322 w.set_iohsrc(0b00);
323 }
324 } else {
325 w.set_iolen(true);
326 w.set_iolsrc(0b10);
327 // Enable IOH in octo and dual quad mode
328 if let OspiWidth::OCTO = width {
329 w.set_iohen(true);
330 w.set_iohsrc(0b11);
331 } else if dual_quad {
332 w.set_iohen(true);
333 w.set_iohsrc(0b10);
334 } else {
335 w.set_iohen(false);
336 w.set_iohsrc(0b00);
337 }
338 }
339 });
340 }
199 341
200 // System configuration 342 // System configuration
201 rcc::enable_and_reset::<T>(); 343 rcc::enable_and_reset::<T>();
@@ -228,7 +370,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
228 }); 370 });
229 371
230 T::REGS.cr().modify(|w| { 372 T::REGS.cr().modify(|w| {
231 w.set_fthres(vals::Threshold(config.fifo_threshold.into())); 373 w.set_fthres(vals::Threshold::from_bits(config.fifo_threshold.into()));
232 }); 374 });
233 375
234 // Wait for busy flag to clear 376 // Wait for busy flag to clear
@@ -244,7 +386,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
244 386
245 T::REGS.tcr().modify(|w| { 387 T::REGS.tcr().modify(|w| {
246 w.set_sshift(match config.sample_shifting { 388 w.set_sshift(match config.sample_shifting {
247 true => vals::SampleShift::HALFCYCLE, 389 true => vals::SampleShift::HALF_CYCLE,
248 false => vals::SampleShift::NONE, 390 false => vals::SampleShift::NONE,
249 }); 391 });
250 w.set_dhqc(config.delay_hold_quarter_cycle); 392 w.set_dhqc(config.delay_hold_quarter_cycle);
@@ -376,7 +518,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
376 } 518 }
377 519
378 /// Function used to control or configure the target device without data transfer 520 /// Function used to control or configure the target device without data transfer
379 pub async fn command(&mut self, command: &TransferConfig) -> Result<(), OspiError> { 521 pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), OspiError> {
380 // Wait for peripheral to be free 522 // Wait for peripheral to be free
381 while T::REGS.sr().read().busy() {} 523 while T::REGS.sr().read().busy() {}
382 524
@@ -412,7 +554,9 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
412 let current_instruction = T::REGS.ir().read().instruction(); 554 let current_instruction = T::REGS.ir().read().instruction();
413 555
414 // For a indirect read transaction, the transaction begins when the instruction/address is set 556 // For a indirect read transaction, the transaction begins when the instruction/address is set
415 T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); 557 T::REGS
558 .cr()
559 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_READ));
416 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { 560 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE {
417 T::REGS.ir().write(|v| v.set_instruction(current_instruction)); 561 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
418 } else { 562 } else {
@@ -447,7 +591,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
447 591
448 T::REGS 592 T::REGS
449 .cr() 593 .cr()
450 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); 594 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
451 595
452 for idx in 0..buf.len() { 596 for idx in 0..buf.len() {
453 while !T::REGS.sr().read().ftf() {} 597 while !T::REGS.sr().read().ftf() {}
@@ -497,7 +641,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
497 }); 641 });
498 642
499 T::REGS.cr().modify(|w| { 643 T::REGS.cr().modify(|w| {
500 w.set_fthres(vals::Threshold(config.fifo_threshold.into())); 644 w.set_fthres(vals::Threshold::from_bits(config.fifo_threshold.into()));
501 }); 645 });
502 646
503 // Wait for busy flag to clear 647 // Wait for busy flag to clear
@@ -509,7 +653,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
509 653
510 T::REGS.tcr().modify(|w| { 654 T::REGS.tcr().modify(|w| {
511 w.set_sshift(match config.sample_shifting { 655 w.set_sshift(match config.sample_shifting {
512 true => vals::SampleShift::HALFCYCLE, 656 true => vals::SampleShift::HALF_CYCLE,
513 false => vals::SampleShift::NONE, 657 false => vals::SampleShift::NONE,
514 }); 658 });
515 w.set_dhqc(config.delay_hold_quarter_cycle); 659 w.set_dhqc(config.delay_hold_quarter_cycle);
@@ -539,11 +683,11 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
539impl<'d, T: Instance> Ospi<'d, T, Blocking> { 683impl<'d, T: Instance> Ospi<'d, T, Blocking> {
540 /// Create new blocking OSPI driver for a single spi external chip 684 /// Create new blocking OSPI driver for a single spi external chip
541 pub fn new_blocking_singlespi( 685 pub fn new_blocking_singlespi(
542 peri: impl Peripheral<P = T> + 'd, 686 peri: Peri<'d, T>,
543 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 687 sck: Peri<'d, impl SckPin<T>>,
544 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 688 d0: Peri<'d, impl D0Pin<T>>,
545 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 689 d1: Peri<'d, impl D1Pin<T>>,
546 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 690 nss: Peri<'d, impl NSSPin<T>>,
547 config: Config, 691 config: Config,
548 ) -> Self { 692 ) -> Self {
549 Self::new_inner( 693 Self::new_inner(
@@ -571,11 +715,11 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> {
571 715
572 /// Create new blocking OSPI driver for a dualspi external chip 716 /// Create new blocking OSPI driver for a dualspi external chip
573 pub fn new_blocking_dualspi( 717 pub fn new_blocking_dualspi(
574 peri: impl Peripheral<P = T> + 'd, 718 peri: Peri<'d, T>,
575 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 719 sck: Peri<'d, impl SckPin<T>>,
576 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 720 d0: Peri<'d, impl D0Pin<T>>,
577 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 721 d1: Peri<'d, impl D1Pin<T>>,
578 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 722 nss: Peri<'d, impl NSSPin<T>>,
579 config: Config, 723 config: Config,
580 ) -> Self { 724 ) -> Self {
581 Self::new_inner( 725 Self::new_inner(
@@ -603,13 +747,13 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> {
603 747
604 /// Create new blocking OSPI driver for a quadspi external chip 748 /// Create new blocking OSPI driver for a quadspi external chip
605 pub fn new_blocking_quadspi( 749 pub fn new_blocking_quadspi(
606 peri: impl Peripheral<P = T> + 'd, 750 peri: Peri<'d, T>,
607 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 751 sck: Peri<'d, impl SckPin<T>>,
608 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 752 d0: Peri<'d, impl D0Pin<T>>,
609 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 753 d1: Peri<'d, impl D1Pin<T>>,
610 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 754 d2: Peri<'d, impl D2Pin<T>>,
611 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 755 d3: Peri<'d, impl D3Pin<T>>,
612 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 756 nss: Peri<'d, impl NSSPin<T>>,
613 config: Config, 757 config: Config,
614 ) -> Self { 758 ) -> Self {
615 Self::new_inner( 759 Self::new_inner(
@@ -637,17 +781,17 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> {
637 781
638 /// Create new blocking OSPI driver for two quadspi external chips 782 /// Create new blocking OSPI driver for two quadspi external chips
639 pub fn new_blocking_dualquadspi( 783 pub fn new_blocking_dualquadspi(
640 peri: impl Peripheral<P = T> + 'd, 784 peri: Peri<'d, T>,
641 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 785 sck: Peri<'d, impl SckPin<T>>,
642 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 786 d0: Peri<'d, impl D0Pin<T>>,
643 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 787 d1: Peri<'d, impl D1Pin<T>>,
644 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 788 d2: Peri<'d, impl D2Pin<T>>,
645 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 789 d3: Peri<'d, impl D3Pin<T>>,
646 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 790 d4: Peri<'d, impl D4Pin<T>>,
647 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 791 d5: Peri<'d, impl D5Pin<T>>,
648 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 792 d6: Peri<'d, impl D6Pin<T>>,
649 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 793 d7: Peri<'d, impl D7Pin<T>>,
650 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 794 nss: Peri<'d, impl NSSPin<T>>,
651 config: Config, 795 config: Config,
652 ) -> Self { 796 ) -> Self {
653 Self::new_inner( 797 Self::new_inner(
@@ -675,17 +819,17 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> {
675 819
676 /// Create new blocking OSPI driver for octospi external chips 820 /// Create new blocking OSPI driver for octospi external chips
677 pub fn new_blocking_octospi( 821 pub fn new_blocking_octospi(
678 peri: impl Peripheral<P = T> + 'd, 822 peri: Peri<'d, T>,
679 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 823 sck: Peri<'d, impl SckPin<T>>,
680 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 824 d0: Peri<'d, impl D0Pin<T>>,
681 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 825 d1: Peri<'d, impl D1Pin<T>>,
682 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 826 d2: Peri<'d, impl D2Pin<T>>,
683 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 827 d3: Peri<'d, impl D3Pin<T>>,
684 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 828 d4: Peri<'d, impl D4Pin<T>>,
685 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 829 d5: Peri<'d, impl D5Pin<T>>,
686 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 830 d6: Peri<'d, impl D6Pin<T>>,
687 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 831 d7: Peri<'d, impl D7Pin<T>>,
688 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 832 nss: Peri<'d, impl NSSPin<T>>,
689 config: Config, 833 config: Config,
690 ) -> Self { 834 ) -> Self {
691 Self::new_inner( 835 Self::new_inner(
@@ -715,12 +859,12 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> {
715impl<'d, T: Instance> Ospi<'d, T, Async> { 859impl<'d, T: Instance> Ospi<'d, T, Async> {
716 /// Create new blocking OSPI driver for a single spi external chip 860 /// Create new blocking OSPI driver for a single spi external chip
717 pub fn new_singlespi( 861 pub fn new_singlespi(
718 peri: impl Peripheral<P = T> + 'd, 862 peri: Peri<'d, T>,
719 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 863 sck: Peri<'d, impl SckPin<T>>,
720 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 864 d0: Peri<'d, impl D0Pin<T>>,
721 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 865 d1: Peri<'d, impl D1Pin<T>>,
722 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 866 nss: Peri<'d, impl NSSPin<T>>,
723 dma: impl Peripheral<P = impl OctoDma<T>> + 'd, 867 dma: Peri<'d, impl OctoDma<T>>,
724 config: Config, 868 config: Config,
725 ) -> Self { 869 ) -> Self {
726 Self::new_inner( 870 Self::new_inner(
@@ -748,12 +892,12 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
748 892
749 /// Create new blocking OSPI driver for a dualspi external chip 893 /// Create new blocking OSPI driver for a dualspi external chip
750 pub fn new_dualspi( 894 pub fn new_dualspi(
751 peri: impl Peripheral<P = T> + 'd, 895 peri: Peri<'d, T>,
752 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 896 sck: Peri<'d, impl SckPin<T>>,
753 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 897 d0: Peri<'d, impl D0Pin<T>>,
754 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 898 d1: Peri<'d, impl D1Pin<T>>,
755 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 899 nss: Peri<'d, impl NSSPin<T>>,
756 dma: impl Peripheral<P = impl OctoDma<T>> + 'd, 900 dma: Peri<'d, impl OctoDma<T>>,
757 config: Config, 901 config: Config,
758 ) -> Self { 902 ) -> Self {
759 Self::new_inner( 903 Self::new_inner(
@@ -781,14 +925,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
781 925
782 /// Create new blocking OSPI driver for a quadspi external chip 926 /// Create new blocking OSPI driver for a quadspi external chip
783 pub fn new_quadspi( 927 pub fn new_quadspi(
784 peri: impl Peripheral<P = T> + 'd, 928 peri: Peri<'d, T>,
785 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 929 sck: Peri<'d, impl SckPin<T>>,
786 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 930 d0: Peri<'d, impl D0Pin<T>>,
787 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 931 d1: Peri<'d, impl D1Pin<T>>,
788 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 932 d2: Peri<'d, impl D2Pin<T>>,
789 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 933 d3: Peri<'d, impl D3Pin<T>>,
790 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 934 nss: Peri<'d, impl NSSPin<T>>,
791 dma: impl Peripheral<P = impl OctoDma<T>> + 'd, 935 dma: Peri<'d, impl OctoDma<T>>,
792 config: Config, 936 config: Config,
793 ) -> Self { 937 ) -> Self {
794 Self::new_inner( 938 Self::new_inner(
@@ -816,18 +960,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
816 960
817 /// Create new blocking OSPI driver for two quadspi external chips 961 /// Create new blocking OSPI driver for two quadspi external chips
818 pub fn new_dualquadspi( 962 pub fn new_dualquadspi(
819 peri: impl Peripheral<P = T> + 'd, 963 peri: Peri<'d, T>,
820 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 964 sck: Peri<'d, impl SckPin<T>>,
821 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 965 d0: Peri<'d, impl D0Pin<T>>,
822 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 966 d1: Peri<'d, impl D1Pin<T>>,
823 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 967 d2: Peri<'d, impl D2Pin<T>>,
824 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 968 d3: Peri<'d, impl D3Pin<T>>,
825 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 969 d4: Peri<'d, impl D4Pin<T>>,
826 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 970 d5: Peri<'d, impl D5Pin<T>>,
827 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 971 d6: Peri<'d, impl D6Pin<T>>,
828 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 972 d7: Peri<'d, impl D7Pin<T>>,
829 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 973 nss: Peri<'d, impl NSSPin<T>>,
830 dma: impl Peripheral<P = impl OctoDma<T>> + 'd, 974 dma: Peri<'d, impl OctoDma<T>>,
831 config: Config, 975 config: Config,
832 ) -> Self { 976 ) -> Self {
833 Self::new_inner( 977 Self::new_inner(
@@ -855,18 +999,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
855 999
856 /// Create new blocking OSPI driver for octospi external chips 1000 /// Create new blocking OSPI driver for octospi external chips
857 pub fn new_octospi( 1001 pub fn new_octospi(
858 peri: impl Peripheral<P = T> + 'd, 1002 peri: Peri<'d, T>,
859 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 1003 sck: Peri<'d, impl SckPin<T>>,
860 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 1004 d0: Peri<'d, impl D0Pin<T>>,
861 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 1005 d1: Peri<'d, impl D1Pin<T>>,
862 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 1006 d2: Peri<'d, impl D2Pin<T>>,
863 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 1007 d3: Peri<'d, impl D3Pin<T>>,
864 d4: impl Peripheral<P = impl D4Pin<T>> + 'd, 1008 d4: Peri<'d, impl D4Pin<T>>,
865 d5: impl Peripheral<P = impl D5Pin<T>> + 'd, 1009 d5: Peri<'d, impl D5Pin<T>>,
866 d6: impl Peripheral<P = impl D6Pin<T>> + 'd, 1010 d6: Peri<'d, impl D6Pin<T>>,
867 d7: impl Peripheral<P = impl D7Pin<T>> + 'd, 1011 d7: Peri<'d, impl D7Pin<T>>,
868 nss: impl Peripheral<P = impl NSSPin<T>> + 'd, 1012 nss: Peri<'d, impl NSSPin<T>>,
869 dma: impl Peripheral<P = impl OctoDma<T>> + 'd, 1013 dma: Peri<'d, impl OctoDma<T>>,
870 config: Config, 1014 config: Config,
871 ) -> Self { 1015 ) -> Self {
872 Self::new_inner( 1016 Self::new_inner(
@@ -907,7 +1051,9 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
907 let current_instruction = T::REGS.ir().read().instruction(); 1051 let current_instruction = T::REGS.ir().read().instruction();
908 1052
909 // For a indirect read transaction, the transaction begins when the instruction/address is set 1053 // For a indirect read transaction, the transaction begins when the instruction/address is set
910 T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); 1054 T::REGS
1055 .cr()
1056 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_READ));
911 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { 1057 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE {
912 T::REGS.ir().write(|v| v.set_instruction(current_instruction)); 1058 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
913 } else { 1059 } else {
@@ -942,7 +1088,7 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
942 self.configure_command(&transaction, Some(buf.len()))?; 1088 self.configure_command(&transaction, Some(buf.len()))?;
943 T::REGS 1089 T::REGS
944 .cr() 1090 .cr()
945 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); 1091 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
946 1092
947 let transfer = unsafe { 1093 let transfer = unsafe {
948 self.dma 1094 self.dma
@@ -975,7 +1121,9 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
975 let current_instruction = T::REGS.ir().read().instruction(); 1121 let current_instruction = T::REGS.ir().read().instruction();
976 1122
977 // For a indirect read transaction, the transaction begins when the instruction/address is set 1123 // For a indirect read transaction, the transaction begins when the instruction/address is set
978 T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); 1124 T::REGS
1125 .cr()
1126 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_READ));
979 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { 1127 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE {
980 T::REGS.ir().write(|v| v.set_instruction(current_instruction)); 1128 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
981 } else { 1129 } else {
@@ -1010,7 +1158,7 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1010 self.configure_command(&transaction, Some(buf.len()))?; 1158 self.configure_command(&transaction, Some(buf.len()))?;
1011 T::REGS 1159 T::REGS
1012 .cr() 1160 .cr()
1013 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); 1161 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
1014 1162
1015 let transfer = unsafe { 1163 let transfer = unsafe {
1016 self.dma 1164 self.dma
@@ -1056,13 +1204,27 @@ fn finish_dma(regs: Regs) {
1056 }); 1204 });
1057} 1205}
1058 1206
1207#[cfg(octospim_v1)]
1208/// OctoSPI I/O manager instance trait.
1209pub(crate) trait SealedOctospimInstance {
1210 const OCTOSPIM_REGS: Octospim;
1211 const OCTOSPI_IDX: u8;
1212}
1213
1214/// OctoSPI instance trait.
1059pub(crate) trait SealedInstance { 1215pub(crate) trait SealedInstance {
1060 const REGS: Regs; 1216 const REGS: Regs;
1061} 1217}
1062 1218
1063/// OSPI instance trait. 1219/// OSPI instance trait.
1220#[cfg(octospim_v1)]
1221#[allow(private_bounds)]
1222pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + SealedOctospimInstance {}
1223
1224/// OSPI instance trait.
1225#[cfg(not(octospim_v1))]
1064#[allow(private_bounds)] 1226#[allow(private_bounds)]
1065pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} 1227pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {}
1066 1228
1067pin_trait!(SckPin, Instance); 1229pin_trait!(SckPin, Instance);
1068pin_trait!(NckPin, Instance); 1230pin_trait!(NckPin, Instance);
@@ -1078,6 +1240,31 @@ pin_trait!(DQSPin, Instance);
1078pin_trait!(NSSPin, Instance); 1240pin_trait!(NSSPin, Instance);
1079dma_trait!(OctoDma, Instance); 1241dma_trait!(OctoDma, Instance);
1080 1242
1243// Hard-coded the octospi index, for OCTOSPIM
1244#[cfg(octospim_v1)]
1245impl SealedOctospimInstance for peripherals::OCTOSPI1 {
1246 const OCTOSPIM_REGS: Octospim = crate::pac::OCTOSPIM;
1247 const OCTOSPI_IDX: u8 = 1;
1248}
1249
1250#[cfg(all(octospim_v1, peri_octospi2))]
1251impl SealedOctospimInstance for peripherals::OCTOSPI2 {
1252 const OCTOSPIM_REGS: Octospim = crate::pac::OCTOSPIM;
1253 const OCTOSPI_IDX: u8 = 2;
1254}
1255
1256#[cfg(octospim_v1)]
1257foreach_peripheral!(
1258 (octospi, $inst:ident) => {
1259 impl SealedInstance for peripherals::$inst {
1260 const REGS: Regs = crate::pac::$inst;
1261 }
1262
1263 impl Instance for peripherals::$inst {}
1264 };
1265);
1266
1267#[cfg(not(octospim_v1))]
1081foreach_peripheral!( 1268foreach_peripheral!(
1082 (octospi, $inst:ident) => { 1269 (octospi, $inst:ident) => {
1083 impl SealedInstance for peripherals::$inst { 1270 impl SealedInstance for peripherals::$inst {
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index ecade9b1a..9ec4c1b43 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -9,9 +9,9 @@ pub(crate) enum QspiMode {
9 MemoryMapped, 9 MemoryMapped,
10} 10}
11 11
12impl Into<u8> for QspiMode { 12impl From<QspiMode> for u8 {
13 fn into(self) -> u8 { 13 fn from(val: QspiMode) -> Self {
14 match self { 14 match val {
15 QspiMode::IndirectWrite => 0b00, 15 QspiMode::IndirectWrite => 0b00,
16 QspiMode::IndirectRead => 0b01, 16 QspiMode::IndirectRead => 0b01,
17 QspiMode::AutoPolling => 0b10, 17 QspiMode::AutoPolling => 0b10,
@@ -34,9 +34,9 @@ pub enum QspiWidth {
34 QUAD, 34 QUAD,
35} 35}
36 36
37impl Into<u8> for QspiWidth { 37impl From<QspiWidth> for u8 {
38 fn into(self) -> u8 { 38 fn from(val: QspiWidth) -> Self {
39 match self { 39 match val {
40 QspiWidth::NONE => 0b00, 40 QspiWidth::NONE => 0b00,
41 QspiWidth::SING => 0b01, 41 QspiWidth::SING => 0b01,
42 QspiWidth::DUAL => 0b10, 42 QspiWidth::DUAL => 0b10,
@@ -55,9 +55,9 @@ pub enum FlashSelection {
55 Flash2, 55 Flash2,
56} 56}
57 57
58impl Into<bool> for FlashSelection { 58impl From<FlashSelection> for bool {
59 fn into(self) -> bool { 59 fn from(val: FlashSelection) -> Self {
60 match self { 60 match val {
61 FlashSelection::Flash1 => false, 61 FlashSelection::Flash1 => false,
62 FlashSelection::Flash2 => true, 62 FlashSelection::Flash2 => true,
63 } 63 }
@@ -94,9 +94,9 @@ pub enum MemorySize {
94 Other(u8), 94 Other(u8),
95} 95}
96 96
97impl Into<u8> for MemorySize { 97impl From<MemorySize> for u8 {
98 fn into(self) -> u8 { 98 fn from(val: MemorySize) -> Self {
99 match self { 99 match val {
100 MemorySize::_1KiB => 9, 100 MemorySize::_1KiB => 9,
101 MemorySize::_2KiB => 10, 101 MemorySize::_2KiB => 10,
102 MemorySize::_4KiB => 11, 102 MemorySize::_4KiB => 11,
@@ -138,9 +138,9 @@ pub enum AddressSize {
138 _32bit, 138 _32bit,
139} 139}
140 140
141impl Into<u8> for AddressSize { 141impl From<AddressSize> for u8 {
142 fn into(self) -> u8 { 142 fn from(val: AddressSize) -> Self {
143 match self { 143 match val {
144 AddressSize::_8Bit => 0b00, 144 AddressSize::_8Bit => 0b00,
145 AddressSize::_16Bit => 0b01, 145 AddressSize::_16Bit => 0b01,
146 AddressSize::_24bit => 0b10, 146 AddressSize::_24bit => 0b10,
@@ -163,9 +163,9 @@ pub enum ChipSelectHighTime {
163 _8Cycle, 163 _8Cycle,
164} 164}
165 165
166impl Into<u8> for ChipSelectHighTime { 166impl From<ChipSelectHighTime> for u8 {
167 fn into(self) -> u8 { 167 fn from(val: ChipSelectHighTime) -> Self {
168 match self { 168 match val {
169 ChipSelectHighTime::_1Cycle => 0, 169 ChipSelectHighTime::_1Cycle => 0,
170 ChipSelectHighTime::_2Cycle => 1, 170 ChipSelectHighTime::_2Cycle => 1,
171 ChipSelectHighTime::_3Cycle => 2, 171 ChipSelectHighTime::_3Cycle => 2,
@@ -216,9 +216,9 @@ pub enum FIFOThresholdLevel {
216 _32Bytes, 216 _32Bytes,
217} 217}
218 218
219impl Into<u8> for FIFOThresholdLevel { 219impl From<FIFOThresholdLevel> for u8 {
220 fn into(self) -> u8 { 220 fn from(val: FIFOThresholdLevel) -> Self {
221 match self { 221 match val {
222 FIFOThresholdLevel::_1Bytes => 0, 222 FIFOThresholdLevel::_1Bytes => 0,
223 FIFOThresholdLevel::_2Bytes => 1, 223 FIFOThresholdLevel::_2Bytes => 1,
224 FIFOThresholdLevel::_3Bytes => 2, 224 FIFOThresholdLevel::_3Bytes => 2,
@@ -293,9 +293,9 @@ pub enum DummyCycles {
293 _31, 293 _31,
294} 294}
295 295
296impl Into<u8> for DummyCycles { 296impl From<DummyCycles> for u8 {
297 fn into(self) -> u8 { 297 fn from(val: DummyCycles) -> Self {
298 match self { 298 match val {
299 DummyCycles::_0 => 0, 299 DummyCycles::_0 => 0,
300 DummyCycles::_1 => 1, 300 DummyCycles::_1 => 1,
301 DummyCycles::_2 => 2, 301 DummyCycles::_2 => 2,
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 308947e99..0df057c53 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -6,7 +6,7 @@ pub mod enums;
6 6
7use core::marker::PhantomData; 7use core::marker::PhantomData;
8 8
9use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::PeripheralType;
10use enums::*; 10use enums::*;
11 11
12use crate::dma::ChannelAndRequest; 12use crate::dma::ChannelAndRequest;
@@ -14,11 +14,11 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::quadspi::Quadspi as Regs; 15use crate::pac::quadspi::Quadspi as Regs;
16use crate::rcc::{self, RccPeripheral}; 16use crate::rcc::{self, RccPeripheral};
17use crate::{peripherals, Peripheral}; 17use crate::{peripherals, Peri};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
20pub struct TransferConfig { 20pub struct TransferConfig {
21 /// Instraction width (IMODE) 21 /// Instruction width (IMODE)
22 pub iwidth: QspiWidth, 22 pub iwidth: QspiWidth,
23 /// Address width (ADMODE) 23 /// Address width (ADMODE)
24 pub awidth: QspiWidth, 24 pub awidth: QspiWidth,
@@ -75,13 +75,13 @@ impl Default for Config {
75/// QSPI driver. 75/// QSPI driver.
76#[allow(dead_code)] 76#[allow(dead_code)]
77pub struct Qspi<'d, T: Instance, M: PeriMode> { 77pub struct Qspi<'d, T: Instance, M: PeriMode> {
78 _peri: PeripheralRef<'d, T>, 78 _peri: Peri<'d, T>,
79 sck: Option<PeripheralRef<'d, AnyPin>>, 79 sck: Option<Peri<'d, AnyPin>>,
80 d0: Option<PeripheralRef<'d, AnyPin>>, 80 d0: Option<Peri<'d, AnyPin>>,
81 d1: Option<PeripheralRef<'d, AnyPin>>, 81 d1: Option<Peri<'d, AnyPin>>,
82 d2: Option<PeripheralRef<'d, AnyPin>>, 82 d2: Option<Peri<'d, AnyPin>>,
83 d3: Option<PeripheralRef<'d, AnyPin>>, 83 d3: Option<Peri<'d, AnyPin>>,
84 nss: Option<PeripheralRef<'d, AnyPin>>, 84 nss: Option<Peri<'d, AnyPin>>,
85 dma: Option<ChannelAndRequest<'d>>, 85 dma: Option<ChannelAndRequest<'d>>,
86 _phantom: PhantomData<M>, 86 _phantom: PhantomData<M>,
87 config: Config, 87 config: Config,
@@ -89,19 +89,17 @@ pub struct Qspi<'d, T: Instance, M: PeriMode> {
89 89
90impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { 90impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
91 fn new_inner( 91 fn new_inner(
92 peri: impl Peripheral<P = T> + 'd, 92 peri: Peri<'d, T>,
93 d0: Option<PeripheralRef<'d, AnyPin>>, 93 d0: Option<Peri<'d, AnyPin>>,
94 d1: Option<PeripheralRef<'d, AnyPin>>, 94 d1: Option<Peri<'d, AnyPin>>,
95 d2: Option<PeripheralRef<'d, AnyPin>>, 95 d2: Option<Peri<'d, AnyPin>>,
96 d3: Option<PeripheralRef<'d, AnyPin>>, 96 d3: Option<Peri<'d, AnyPin>>,
97 sck: Option<PeripheralRef<'d, AnyPin>>, 97 sck: Option<Peri<'d, AnyPin>>,
98 nss: Option<PeripheralRef<'d, AnyPin>>, 98 nss: Option<Peri<'d, AnyPin>>,
99 dma: Option<ChannelAndRequest<'d>>, 99 dma: Option<ChannelAndRequest<'d>>,
100 config: Config, 100 config: Config,
101 fsel: FlashSelection, 101 fsel: FlashSelection,
102 ) -> Self { 102 ) -> Self {
103 into_ref!(peri);
104
105 rcc::enable_and_reset::<T>(); 103 rcc::enable_and_reset::<T>();
106 104
107 while T::REGS.sr().read().busy() {} 105 while T::REGS.sr().read().busy() {}
@@ -148,7 +146,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
148 } 146 }
149 147
150 /// Do a QSPI command. 148 /// Do a QSPI command.
151 pub fn command(&mut self, transaction: TransferConfig) { 149 pub fn blocking_command(&mut self, transaction: TransferConfig) {
152 #[cfg(not(stm32h7))] 150 #[cfg(not(stm32h7))]
153 T::REGS.cr().modify(|v| v.set_dmaen(false)); 151 T::REGS.cr().modify(|v| v.set_dmaen(false));
154 self.setup_transaction(QspiMode::IndirectWrite, &transaction, None); 152 self.setup_transaction(QspiMode::IndirectWrite, &transaction, None);
@@ -172,7 +170,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
172 }); 170 });
173 171
174 for b in buf { 172 for b in buf {
175 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} 173 while !T::REGS.sr().read().tcf() && (T::REGS.sr().read().flevel() == 0) {}
176 *b = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; 174 *b = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
177 } 175 }
178 176
@@ -201,7 +199,42 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
201 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 199 T::REGS.fcr().modify(|v| v.set_ctcf(true));
202 } 200 }
203 201
202 /// Enable memory map mode
203 pub fn enable_memory_map(&mut self, transaction: &TransferConfig) {
204 T::REGS.fcr().modify(|v| {
205 v.set_csmf(true);
206 v.set_ctcf(true);
207 v.set_ctef(true);
208 v.set_ctof(true);
209 });
210 T::REGS.ccr().write(|v| {
211 v.set_fmode(QspiMode::MemoryMapped.into());
212 v.set_imode(transaction.iwidth.into());
213 v.set_instruction(transaction.instruction);
214 v.set_admode(transaction.awidth.into());
215 v.set_adsize(self.config.address_size.into());
216 v.set_dmode(transaction.dwidth.into());
217 v.set_abmode(QspiWidth::NONE.into());
218 v.set_dcyc(transaction.dummy.into());
219 });
220 }
221
204 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option<usize>) { 222 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option<usize>) {
223 match (transaction.address, transaction.awidth) {
224 (Some(_), QspiWidth::NONE) => panic!("QSPI address can't be sent with an address width of NONE"),
225 (Some(_), _) => {}
226 (None, QspiWidth::NONE) => {}
227 (None, _) => panic!("QSPI address is not set, so the address width should be NONE"),
228 }
229
230 match (data_len, transaction.dwidth) {
231 (Some(0), _) => panic!("QSPI data must be at least one byte"),
232 (Some(_), QspiWidth::NONE) => panic!("QSPI data can't be sent with a data width of NONE"),
233 (Some(_), _) => {}
234 (None, QspiWidth::NONE) => {}
235 (None, _) => panic!("QSPI data is empty, so the data width should be NONE"),
236 }
237
205 T::REGS.fcr().modify(|v| { 238 T::REGS.fcr().modify(|v| {
206 v.set_csmf(true); 239 v.set_csmf(true);
207 v.set_ctcf(true); 240 v.set_ctcf(true);
@@ -237,13 +270,13 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
237impl<'d, T: Instance> Qspi<'d, T, Blocking> { 270impl<'d, T: Instance> Qspi<'d, T, Blocking> {
238 /// Create a new QSPI driver for bank 1, in blocking mode. 271 /// Create a new QSPI driver for bank 1, in blocking mode.
239 pub fn new_blocking_bank1( 272 pub fn new_blocking_bank1(
240 peri: impl Peripheral<P = T> + 'd, 273 peri: Peri<'d, T>,
241 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, 274 d0: Peri<'d, impl BK1D0Pin<T>>,
242 d1: impl Peripheral<P = impl BK1D1Pin<T>> + 'd, 275 d1: Peri<'d, impl BK1D1Pin<T>>,
243 d2: impl Peripheral<P = impl BK1D2Pin<T>> + 'd, 276 d2: Peri<'d, impl BK1D2Pin<T>>,
244 d3: impl Peripheral<P = impl BK1D3Pin<T>> + 'd, 277 d3: Peri<'d, impl BK1D3Pin<T>>,
245 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 278 sck: Peri<'d, impl SckPin<T>>,
246 nss: impl Peripheral<P = impl BK1NSSPin<T>> + 'd, 279 nss: Peri<'d, impl BK1NSSPin<T>>,
247 config: Config, 280 config: Config,
248 ) -> Self { 281 ) -> Self {
249 Self::new_inner( 282 Self::new_inner(
@@ -265,13 +298,13 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
265 298
266 /// Create a new QSPI driver for bank 2, in blocking mode. 299 /// Create a new QSPI driver for bank 2, in blocking mode.
267 pub fn new_blocking_bank2( 300 pub fn new_blocking_bank2(
268 peri: impl Peripheral<P = T> + 'd, 301 peri: Peri<'d, T>,
269 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, 302 d0: Peri<'d, impl BK2D0Pin<T>>,
270 d1: impl Peripheral<P = impl BK2D1Pin<T>> + 'd, 303 d1: Peri<'d, impl BK2D1Pin<T>>,
271 d2: impl Peripheral<P = impl BK2D2Pin<T>> + 'd, 304 d2: Peri<'d, impl BK2D2Pin<T>>,
272 d3: impl Peripheral<P = impl BK2D3Pin<T>> + 'd, 305 d3: Peri<'d, impl BK2D3Pin<T>>,
273 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 306 sck: Peri<'d, impl SckPin<T>>,
274 nss: impl Peripheral<P = impl BK2NSSPin<T>> + 'd, 307 nss: Peri<'d, impl BK2NSSPin<T>>,
275 config: Config, 308 config: Config,
276 ) -> Self { 309 ) -> Self {
277 Self::new_inner( 310 Self::new_inner(
@@ -295,14 +328,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
295impl<'d, T: Instance> Qspi<'d, T, Async> { 328impl<'d, T: Instance> Qspi<'d, T, Async> {
296 /// Create a new QSPI driver for bank 1. 329 /// Create a new QSPI driver for bank 1.
297 pub fn new_bank1( 330 pub fn new_bank1(
298 peri: impl Peripheral<P = T> + 'd, 331 peri: Peri<'d, T>,
299 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, 332 d0: Peri<'d, impl BK1D0Pin<T>>,
300 d1: impl Peripheral<P = impl BK1D1Pin<T>> + 'd, 333 d1: Peri<'d, impl BK1D1Pin<T>>,
301 d2: impl Peripheral<P = impl BK1D2Pin<T>> + 'd, 334 d2: Peri<'d, impl BK1D2Pin<T>>,
302 d3: impl Peripheral<P = impl BK1D3Pin<T>> + 'd, 335 d3: Peri<'d, impl BK1D3Pin<T>>,
303 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 336 sck: Peri<'d, impl SckPin<T>>,
304 nss: impl Peripheral<P = impl BK1NSSPin<T>> + 'd, 337 nss: Peri<'d, impl BK1NSSPin<T>>,
305 dma: impl Peripheral<P = impl QuadDma<T>> + 'd, 338 dma: Peri<'d, impl QuadDma<T>>,
306 config: Config, 339 config: Config,
307 ) -> Self { 340 ) -> Self {
308 Self::new_inner( 341 Self::new_inner(
@@ -324,14 +357,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
324 357
325 /// Create a new QSPI driver for bank 2. 358 /// Create a new QSPI driver for bank 2.
326 pub fn new_bank2( 359 pub fn new_bank2(
327 peri: impl Peripheral<P = T> + 'd, 360 peri: Peri<'d, T>,
328 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, 361 d0: Peri<'d, impl BK2D0Pin<T>>,
329 d1: impl Peripheral<P = impl BK2D1Pin<T>> + 'd, 362 d1: Peri<'d, impl BK2D1Pin<T>>,
330 d2: impl Peripheral<P = impl BK2D2Pin<T>> + 'd, 363 d2: Peri<'d, impl BK2D2Pin<T>>,
331 d3: impl Peripheral<P = impl BK2D3Pin<T>> + 'd, 364 d3: Peri<'d, impl BK2D3Pin<T>>,
332 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 365 sck: Peri<'d, impl SckPin<T>>,
333 nss: impl Peripheral<P = impl BK2NSSPin<T>> + 'd, 366 nss: Peri<'d, impl BK2NSSPin<T>>,
334 dma: impl Peripheral<P = impl QuadDma<T>> + 'd, 367 dma: Peri<'d, impl QuadDma<T>>,
335 config: Config, 368 config: Config,
336 ) -> Self { 369 ) -> Self {
337 Self::new_inner( 370 Self::new_inner(
@@ -353,6 +386,21 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
353 386
354 /// Blocking read data, using DMA. 387 /// Blocking read data, using DMA.
355 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { 388 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) {
389 let transfer = self.start_read_transfer(transaction, buf);
390 transfer.blocking_wait();
391 }
392
393 /// Async read data, using DMA.
394 pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) {
395 let transfer = self.start_read_transfer(transaction, buf);
396 transfer.await;
397 }
398
399 fn start_read_transfer<'a>(
400 &'a mut self,
401 transaction: TransferConfig,
402 buf: &'a mut [u8],
403 ) -> crate::dma::Transfer<'a> {
356 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); 404 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
357 405
358 T::REGS.ccr().modify(|v| { 406 T::REGS.ccr().modify(|v| {
@@ -373,12 +421,22 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
373 // STM32H7 does not have dmaen 421 // STM32H7 does not have dmaen
374 #[cfg(not(stm32h7))] 422 #[cfg(not(stm32h7))]
375 T::REGS.cr().modify(|v| v.set_dmaen(true)); 423 T::REGS.cr().modify(|v| v.set_dmaen(true));
376 424 transfer
377 transfer.blocking_wait();
378 } 425 }
379 426
380 /// Blocking write data, using DMA. 427 /// Blocking write data, using DMA.
381 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { 428 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) {
429 let transfer = self.start_write_transfer(transaction, buf);
430 transfer.blocking_wait();
431 }
432
433 /// Async write data, using DMA.
434 pub async fn write_dma(&mut self, buf: &[u8], transaction: TransferConfig) {
435 let transfer = self.start_write_transfer(transaction, buf);
436 transfer.await;
437 }
438
439 fn start_write_transfer<'a>(&'a mut self, transaction: TransferConfig, buf: &'a [u8]) -> crate::dma::Transfer<'a> {
382 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); 440 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
383 441
384 T::REGS.ccr().modify(|v| { 442 T::REGS.ccr().modify(|v| {
@@ -395,8 +453,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
395 // STM32H7 does not have dmaen 453 // STM32H7 does not have dmaen
396 #[cfg(not(stm32h7))] 454 #[cfg(not(stm32h7))]
397 T::REGS.cr().modify(|v| v.set_dmaen(true)); 455 T::REGS.cr().modify(|v| v.set_dmaen(true));
398 456 transfer
399 transfer.blocking_wait();
400 } 457 }
401} 458}
402 459
@@ -406,7 +463,7 @@ trait SealedInstance {
406 463
407/// QSPI instance trait. 464/// QSPI instance trait.
408#[allow(private_bounds)] 465#[allow(private_bounds)]
409pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} 466pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {}
410 467
411pin_trait!(SckPin, Instance); 468pin_trait!(SckPin, Instance);
412pin_trait!(BK1D0Pin, Instance); 469pin_trait!(BK1D0Pin, Instance);
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index 4e9c18594..e2c704405 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -16,9 +16,13 @@ pub enum LseMode {
16 Bypass, 16 Bypass,
17} 17}
18 18
19#[derive(Clone, Copy)]
19pub struct LseConfig { 20pub struct LseConfig {
20 pub frequency: Hertz, 21 pub frequency: Hertz,
21 pub mode: LseMode, 22 pub mode: LseMode,
23 /// If peripherals other than RTC/TAMP or RCC functions need the lse this bit must be set
24 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))]
25 pub peripherals_clocked: bool,
22} 26}
23 27
24#[allow(dead_code)] 28#[allow(dead_code)]
@@ -41,8 +45,8 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
41 match value { 45 match value {
42 #[cfg(not(stm32h5))] // ES0565: LSE Low drive mode is not functional 46 #[cfg(not(stm32h5))] // ES0565: LSE Low drive mode is not functional
43 LseDrive::Low => Lsedrv::LOW, 47 LseDrive::Low => Lsedrv::LOW,
44 LseDrive::MediumLow => Lsedrv::MEDIUMLOW, 48 LseDrive::MediumLow => Lsedrv::MEDIUM_LOW,
45 LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, 49 LseDrive::MediumHigh => Lsedrv::MEDIUM_HIGH,
46 LseDrive::High => Lsedrv::HIGH, 50 LseDrive::High => Lsedrv::HIGH,
47 } 51 }
48 } 52 }
@@ -80,6 +84,7 @@ fn bdcr() -> Reg<Bdcr, RW> {
80 return crate::pac::RCC.csr1(); 84 return crate::pac::RCC.csr1();
81} 85}
82 86
87#[derive(Clone, Copy)]
83pub struct LsConfig { 88pub struct LsConfig {
84 pub rtc: RtcClockSource, 89 pub rtc: RtcClockSource,
85 pub lsi: bool, 90 pub lsi: bool,
@@ -87,12 +92,25 @@ pub struct LsConfig {
87} 92}
88 93
89impl LsConfig { 94impl LsConfig {
95 /// Creates an [`LsConfig`] using the LSI when possible.
96 pub const fn new() -> Self {
97 // on L5, just the fact that LSI is enabled makes things crash.
98 // TODO: investigate.
99
100 #[cfg(not(stm32l5))]
101 return Self::default_lsi();
102 #[cfg(stm32l5)]
103 return Self::off();
104 }
105
90 pub const fn default_lse() -> Self { 106 pub const fn default_lse() -> Self {
91 Self { 107 Self {
92 rtc: RtcClockSource::LSE, 108 rtc: RtcClockSource::LSE,
93 lse: Some(LseConfig { 109 lse: Some(LseConfig {
94 frequency: Hertz(32_768), 110 frequency: Hertz(32_768),
95 mode: LseMode::Oscillator(LseDrive::MediumHigh), 111 mode: LseMode::Oscillator(LseDrive::MediumHigh),
112 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))]
113 peripherals_clocked: false,
96 }), 114 }),
97 lsi: false, 115 lsi: false,
98 } 116 }
@@ -117,13 +135,7 @@ impl LsConfig {
117 135
118impl Default for LsConfig { 136impl Default for LsConfig {
119 fn default() -> Self { 137 fn default() -> Self {
120 // on L5, just the fact that LSI is enabled makes things crash. 138 Self::new()
121 // TODO: investigate.
122
123 #[cfg(not(stm32l5))]
124 return Self::default_lsi();
125 #[cfg(stm32l5)]
126 return Self::off();
127 } 139 }
128} 140}
129 141
@@ -146,6 +158,15 @@ impl LsConfig {
146 }, 158 },
147 None => (false, false, None), 159 None => (false, false, None),
148 }; 160 };
161 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))]
162 let lse_sysen = if let Some(lse) = self.lse {
163 Some(lse.peripherals_clocked)
164 } else {
165 None
166 };
167 #[cfg(rcc_u0)]
168 let lse_sysen = Some(lse_en);
169
149 _ = lse_drv; // not all chips have it. 170 _ = lse_drv; // not all chips have it.
150 171
151 // Disable backup domain write protection 172 // Disable backup domain write protection
@@ -186,6 +207,10 @@ impl LsConfig {
186 } 207 }
187 ok &= reg.lseon() == lse_en; 208 ok &= reg.lseon() == lse_en;
188 ok &= reg.lsebyp() == lse_byp; 209 ok &= reg.lsebyp() == lse_byp;
210 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
211 if let Some(lse_sysen) = lse_sysen {
212 ok &= reg.lsesysen() == lse_sysen;
213 }
189 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] 214 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
190 if let Some(lse_drv) = lse_drv { 215 if let Some(lse_drv) = lse_drv {
191 ok &= reg.lsedrv() == lse_drv.into(); 216 ok &= reg.lsedrv() == lse_drv.into();
@@ -233,6 +258,17 @@ impl LsConfig {
233 }); 258 });
234 259
235 while !bdcr().read().lserdy() {} 260 while !bdcr().read().lserdy() {}
261
262 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
263 if let Some(lse_sysen) = lse_sysen {
264 bdcr().modify(|w| {
265 w.set_lsesysen(lse_sysen);
266 });
267
268 if lse_sysen {
269 while !bdcr().read().lsesysrdy() {}
270 }
271 }
236 } 272 }
237 273
238 if self.rtc != RtcClockSource::DISABLE { 274 if self.rtc != RtcClockSource::DISABLE {
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 5adf37941..cac2a9149 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -3,6 +3,7 @@ pub use crate::pac::rcc::vals::{
3 Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Hsikerdiv as HsiKerDiv, Ppre as APBPrescaler, Sw as Sysclk, 3 Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Hsikerdiv as HsiKerDiv, Ppre as APBPrescaler, Sw as Sysclk,
4}; 4};
5use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
6use crate::rcc::LSI_FREQ;
6use crate::time::Hertz; 7use crate::time::Hertz;
7 8
8/// HSI speed 9/// HSI speed
@@ -37,6 +38,7 @@ pub struct Hsi {
37 38
38/// Clocks configutation 39/// Clocks configutation
39#[non_exhaustive] 40#[non_exhaustive]
41#[derive(Clone, Copy)]
40pub struct Config { 42pub struct Config {
41 /// HSI Configuration 43 /// HSI Configuration
42 pub hsi: Option<Hsi>, 44 pub hsi: Option<Hsi>,
@@ -57,9 +59,8 @@ pub struct Config {
57 pub mux: super::mux::ClockMux, 59 pub mux: super::mux::ClockMux,
58} 60}
59 61
60impl Default for Config { 62impl Config {
61 #[inline] 63 pub const fn new() -> Self {
62 fn default() -> Config {
63 Config { 64 Config {
64 hsi: Some(Hsi { 65 hsi: Some(Hsi {
65 sys_div: HsiSysDiv::DIV4, 66 sys_div: HsiSysDiv::DIV4,
@@ -69,12 +70,18 @@ impl Default for Config {
69 sys: Sysclk::HSISYS, 70 sys: Sysclk::HSISYS,
70 ahb_pre: AHBPrescaler::DIV1, 71 ahb_pre: AHBPrescaler::DIV1,
71 apb1_pre: APBPrescaler::DIV1, 72 apb1_pre: APBPrescaler::DIV1,
72 ls: Default::default(), 73 ls: crate::rcc::LsConfig::new(),
73 mux: Default::default(), 74 mux: super::mux::ClockMux::default(),
74 } 75 }
75 } 76 }
76} 77}
77 78
79impl Default for Config {
80 fn default() -> Config {
81 Self::new()
82 }
83}
84
78pub(crate) unsafe fn init(config: Config) { 85pub(crate) unsafe fn init(config: Config) {
79 // Turn on the HSI 86 // Turn on the HSI
80 match config.hsi { 87 match config.hsi {
@@ -109,8 +116,8 @@ pub(crate) unsafe fn init(config: Config) {
109 } 116 }
110 Some(hse) => { 117 Some(hse) => {
111 match hse.mode { 118 match hse.mode {
112 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), 119 HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)),
113 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), 120 HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)),
114 } 121 }
115 122
116 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); 123 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
@@ -120,20 +127,27 @@ pub(crate) unsafe fn init(config: Config) {
120 } 127 }
121 }; 128 };
122 129
130 let rtc = config.ls.init();
131
123 let sys = match config.sys { 132 let sys = match config.sys {
124 Sysclk::HSISYS => unwrap!(hsisys), 133 Sysclk::HSISYS => unwrap!(hsisys),
125 Sysclk::HSE => unwrap!(hse), 134 Sysclk::HSE => unwrap!(hse),
135 Sysclk::LSI => {
136 assert!(config.ls.lsi);
137 LSI_FREQ
138 }
139 Sysclk::LSE => unwrap!(config.ls.lse).frequency,
126 _ => unreachable!(), 140 _ => unreachable!(),
127 }; 141 };
128 142
129 assert!(max::SYSCLK.contains(&sys)); 143 rcc_assert!(max::SYSCLK.contains(&sys));
130 144
131 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. 145 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
132 let hclk = sys / config.ahb_pre; 146 let hclk = sys / config.ahb_pre;
133 assert!(max::HCLK.contains(&hclk)); 147 rcc_assert!(max::HCLK.contains(&hclk));
134 148
135 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); 149 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
136 assert!(max::PCLK.contains(&pclk1)); 150 rcc_assert!(max::PCLK.contains(&pclk1));
137 151
138 let latency = match hclk.0 { 152 let latency = match hclk.0 {
139 ..=24_000_000 => Latency::WS0, 153 ..=24_000_000 => Latency::WS0,
@@ -161,8 +175,6 @@ pub(crate) unsafe fn init(config: Config) {
161 RCC.cr().modify(|w| w.set_hsion(false)); 175 RCC.cr().modify(|w| w.set_hsion(false));
162 } 176 }
163 177
164 let rtc = config.ls.init();
165
166 config.mux.init(); 178 config.mux.init();
167 179
168 set_clocks!( 180 set_clocks!(
@@ -179,6 +191,9 @@ pub(crate) unsafe fn init(config: Config) {
179 lsi: None, 191 lsi: None,
180 lse: None, 192 lse: None,
181 ); 193 );
194
195 RCC.ccipr()
196 .modify(|w| w.set_adc1sel(stm32_metapac::rcc::vals::Adcsel::SYS));
182} 197}
183 198
184mod max { 199mod max {
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 63dc27bdd..1155b6acd 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -4,11 +4,13 @@ pub use crate::pac::rcc::vals::Adcpre as ADCPrescaler;
4#[cfg(stm32f3)] 4#[cfg(stm32f3)]
5pub use crate::pac::rcc::vals::Adcpres as AdcPllPrescaler; 5pub use crate::pac::rcc::vals::Adcpres as AdcPllPrescaler;
6use crate::pac::rcc::vals::Pllsrc; 6use crate::pac::rcc::vals::Pllsrc;
7#[cfg(stm32f1)] 7#[cfg(all(stm32f1, not(stm32f107)))]
8pub use crate::pac::rcc::vals::Pllxtpre as PllPreDiv; 8pub use crate::pac::rcc::vals::Pllxtpre as PllPreDiv;
9#[cfg(any(stm32f0, stm32f3))] 9#[cfg(any(stm32f0, stm32f3))]
10pub use crate::pac::rcc::vals::Prediv as PllPreDiv; 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}; 11pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Sw as Sysclk};
12#[cfg(stm32f107)]
13pub use crate::pac::rcc::vals::{I2s2src, Pll2mul as Pll2Mul, Prediv1 as PllPreDiv, Prediv1src, Usbpre as UsbPre};
12use crate::pac::{FLASH, RCC}; 14use crate::pac::{FLASH, RCC};
13use crate::time::Hertz; 15use crate::time::Hertz;
14 16
@@ -37,6 +39,8 @@ pub enum PllSource {
37 HSI, 39 HSI,
38 #[cfg(rcc_f0v4)] 40 #[cfg(rcc_f0v4)]
39 HSI48, 41 HSI48,
42 #[cfg(stm32f107)]
43 PLL2,
40} 44}
41 45
42#[derive(Clone, Copy)] 46#[derive(Clone, Copy)]
@@ -52,6 +56,12 @@ pub struct Pll {
52 pub mul: PllMul, 56 pub mul: PllMul,
53} 57}
54 58
59#[cfg(stm32f107)]
60#[derive(Clone, Copy)]
61pub struct Pll2Or3 {
62 pub mul: Pll2Mul,
63}
64
55#[cfg(all(stm32f3, not(rcc_f37)))] 65#[cfg(all(stm32f3, not(rcc_f37)))]
56#[derive(Clone, Copy)] 66#[derive(Clone, Copy)]
57pub enum AdcClockSource { 67pub enum AdcClockSource {
@@ -76,6 +86,7 @@ pub enum HrtimClockSource {
76 86
77/// Clocks configutation 87/// Clocks configutation
78#[non_exhaustive] 88#[non_exhaustive]
89#[derive(Clone, Copy)]
79pub struct Config { 90pub struct Config {
80 pub hsi: bool, 91 pub hsi: bool,
81 pub hse: Option<Hse>, 92 pub hse: Option<Hse>,
@@ -84,6 +95,12 @@ pub struct Config {
84 pub sys: Sysclk, 95 pub sys: Sysclk,
85 96
86 pub pll: Option<Pll>, 97 pub pll: Option<Pll>,
98 #[cfg(stm32f107)]
99 pub pll2: Option<Pll2Or3>,
100 #[cfg(stm32f107)]
101 pub pll3: Option<Pll2Or3>,
102 #[cfg(stm32f107)]
103 pub prediv2: PllPreDiv,
87 104
88 pub ahb_pre: AHBPrescaler, 105 pub ahb_pre: AHBPrescaler,
89 pub apb1_pre: APBPrescaler, 106 pub apb1_pre: APBPrescaler,
@@ -98,26 +115,39 @@ pub struct Config {
98 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))] 115 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
99 pub adc34: AdcClockSource, 116 pub adc34: AdcClockSource,
100 117
118 #[cfg(stm32f107)]
119 pub i2s2_src: I2s2src,
120 #[cfg(stm32f107)]
121 pub i2s3_src: I2s2src,
122
101 /// Per-peripheral kernel clock selection muxes 123 /// Per-peripheral kernel clock selection muxes
102 pub mux: super::mux::ClockMux, 124 pub mux: super::mux::ClockMux,
103 125
104 pub ls: super::LsConfig, 126 pub ls: super::LsConfig,
105} 127}
106 128
107impl Default for Config { 129impl Config {
108 fn default() -> Self { 130 pub const fn new() -> Self {
109 Self { 131 Self {
110 hsi: true, 132 hsi: true,
111 hse: None, 133 hse: None,
112 #[cfg(crs)] 134 #[cfg(crs)]
113 hsi48: Some(Default::default()), 135 hsi48: Some(crate::rcc::Hsi48Config::new()),
114 sys: Sysclk::HSI, 136 sys: Sysclk::HSI,
115 pll: None, 137 pll: None,
138
139 #[cfg(stm32f107)]
140 pll2: None,
141 #[cfg(stm32f107)]
142 pll3: None,
143 #[cfg(stm32f107)]
144 prediv2: PllPreDiv::DIV1,
145
116 ahb_pre: AHBPrescaler::DIV1, 146 ahb_pre: AHBPrescaler::DIV1,
117 apb1_pre: APBPrescaler::DIV1, 147 apb1_pre: APBPrescaler::DIV1,
118 #[cfg(not(stm32f0))] 148 #[cfg(not(stm32f0))]
119 apb2_pre: APBPrescaler::DIV1, 149 apb2_pre: APBPrescaler::DIV1,
120 ls: Default::default(), 150 ls: crate::rcc::LsConfig::new(),
121 151
122 #[cfg(stm32f1)] 152 #[cfg(stm32f1)]
123 // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz) 153 // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz)
@@ -128,11 +158,22 @@ impl Default for Config {
128 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))] 158 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
129 adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), 159 adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
130 160
131 mux: Default::default(), 161 #[cfg(stm32f107)]
162 i2s2_src: I2s2src::SYS,
163 #[cfg(stm32f107)]
164 i2s3_src: I2s2src::SYS,
165
166 mux: super::mux::ClockMux::default(),
132 } 167 }
133 } 168 }
134} 169}
135 170
171impl Default for Config {
172 fn default() -> Self {
173 Self::new()
174 }
175}
176
136/// Initialize and Set the clock frequencies 177/// Initialize and Set the clock frequencies
137pub(crate) unsafe fn init(config: Config) { 178pub(crate) unsafe fn init(config: Config) {
138 // Turn on the HSI 179 // Turn on the HSI
@@ -157,8 +198,8 @@ pub(crate) unsafe fn init(config: Config) {
157 } 198 }
158 Some(hse) => { 199 Some(hse) => {
159 match hse.mode { 200 match hse.mode {
160 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), 201 HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)),
161 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), 202 HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)),
162 } 203 }
163 204
164 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); 205 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
@@ -174,6 +215,28 @@ pub(crate) unsafe fn init(config: Config) {
174 #[cfg(not(crs))] 215 #[cfg(not(crs))]
175 let hsi48: Option<Hertz> = None; 216 let hsi48: Option<Hertz> = None;
176 217
218 // PLL2 and PLL3
219 // Configure this before PLL since PLL2 can be the source for PLL.
220 #[cfg(stm32f107)]
221 {
222 // Common prediv for PLL2 and PLL3
223 RCC.cfgr2().modify(|w| w.set_prediv2(config.prediv2));
224
225 // Configure PLL2
226 if let Some(pll2) = config.pll2 {
227 RCC.cfgr2().modify(|w| w.set_pll2mul(pll2.mul));
228 RCC.cr().modify(|w| w.set_pll2on(true));
229 while !RCC.cr().read().pll2rdy() {}
230 }
231
232 // Configure PLL3
233 if let Some(pll3) = config.pll3 {
234 RCC.cfgr2().modify(|w| w.set_pll3mul(pll3.mul));
235 RCC.cr().modify(|w| w.set_pll3on(true));
236 while !RCC.cr().read().pll3rdy() {}
237 }
238 }
239
177 // Enable PLL 240 // Enable PLL
178 let pll = config.pll.map(|pll| { 241 let pll = config.pll.map(|pll| {
179 let (src_val, src_freq) = match pll.src { 242 let (src_val, src_freq) = match pll.src {
@@ -186,21 +249,44 @@ pub(crate) unsafe fn init(config: Config) {
186 } 249 }
187 (Pllsrc::HSI_DIV2, unwrap!(hsi)) 250 (Pllsrc::HSI_DIV2, unwrap!(hsi))
188 } 251 }
189 PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), 252 PllSource::HSE => {
253 #[cfg(stm32f107)]
254 RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::HSE));
255
256 (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse))
257 }
190 #[cfg(rcc_f0v4)] 258 #[cfg(rcc_f0v4)]
191 PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), 259 PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)),
260 #[cfg(stm32f107)]
261 PllSource::PLL2 => {
262 if config.pll2.is_none() {
263 panic!("if PLL source is PLL2, Config::pll2 must also be set.");
264 }
265 RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::PLL2));
266
267 let pll2 = unwrap!(config.pll2);
268 let in_freq = hse.unwrap() / config.prediv2;
269 let pll2freq = in_freq * pll2.mul;
270
271 (Pllsrc::HSE_DIV_PREDIV, pll2freq)
272 }
192 }; 273 };
193 let in_freq = src_freq / pll.prediv; 274 let in_freq = src_freq / pll.prediv;
194 assert!(max::PLL_IN.contains(&in_freq)); 275
276 rcc_assert!(max::PLL_IN.contains(&in_freq));
195 let out_freq = in_freq * pll.mul; 277 let out_freq = in_freq * pll.mul;
196 assert!(max::PLL_OUT.contains(&out_freq)); 278 rcc_assert!(max::PLL_OUT.contains(&out_freq));
197 279
198 #[cfg(not(stm32f1))] 280 #[cfg(not(stm32f1))]
199 RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); 281 RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv));
282
283 #[cfg(stm32f107)]
284 RCC.cfgr2().modify(|w| w.set_prediv1(pll.prediv));
285
200 RCC.cfgr().modify(|w| { 286 RCC.cfgr().modify(|w| {
201 w.set_pllmul(pll.mul); 287 w.set_pllmul(pll.mul);
202 w.set_pllsrc(src_val); 288 w.set_pllsrc(src_val);
203 #[cfg(stm32f1)] 289 #[cfg(all(stm32f1, not(stm32f107)))]
204 w.set_pllxtpre(pll.prediv); 290 w.set_pllxtpre(pll.prediv);
205 }); 291 });
206 RCC.cr().modify(|w| w.set_pllon(true)); 292 RCC.cr().modify(|w| w.set_pllon(true));
@@ -209,10 +295,7 @@ pub(crate) unsafe fn init(config: Config) {
209 out_freq 295 out_freq
210 }); 296 });
211 297
212 #[cfg(stm32f3)] 298 #[cfg(any(rcc_f1, rcc_f1cl, stm32f3, stm32f107))]
213 let pll_mul_2 = pll.map(|pll| pll * 2u32);
214
215 #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))]
216 let usb = match pll { 299 let usb = match pll {
217 Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5), 300 Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5),
218 Some(Hertz(48_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1), 301 Some(Hertz(48_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1),
@@ -228,6 +311,9 @@ pub(crate) unsafe fn init(config: Config) {
228 Sysclk::HSI => unwrap!(hsi), 311 Sysclk::HSI => unwrap!(hsi),
229 Sysclk::HSE => unwrap!(hse), 312 Sysclk::HSE => unwrap!(hse),
230 Sysclk::PLL1_P => unwrap!(pll), 313 Sysclk::PLL1_P => unwrap!(pll),
314 #[cfg(crs)]
315 Sysclk::HSI48 => unwrap!(hsi48),
316 #[cfg(not(crs))]
231 _ => unreachable!(), 317 _ => unreachable!(),
232 }; 318 };
233 319
@@ -238,15 +324,15 @@ pub(crate) unsafe fn init(config: Config) {
238 #[cfg(stm32f0)] 324 #[cfg(stm32f0)]
239 let (pclk2, pclk2_tim) = (pclk1, pclk1_tim); 325 let (pclk2, pclk2_tim) = (pclk1, pclk1_tim);
240 326
241 assert!(max::HCLK.contains(&hclk)); 327 rcc_assert!(max::HCLK.contains(&hclk));
242 assert!(max::PCLK1.contains(&pclk1)); 328 rcc_assert!(max::PCLK1.contains(&pclk1));
243 #[cfg(not(stm32f0))] 329 #[cfg(not(stm32f0))]
244 assert!(max::PCLK2.contains(&pclk2)); 330 rcc_assert!(max::PCLK2.contains(&pclk2));
245 331
246 #[cfg(stm32f1)] 332 #[cfg(stm32f1)]
247 let adc = pclk2 / config.adc_pre; 333 let adc = pclk2 / config.adc_pre;
248 #[cfg(stm32f1)] 334 #[cfg(stm32f1)]
249 assert!(max::ADC.contains(&adc)); 335 rcc_assert!(max::ADC.contains(&adc));
250 336
251 // Set latency based on HCLK frquency 337 // Set latency based on HCLK frquency
252 #[cfg(stm32f0)] 338 #[cfg(stm32f0)]
@@ -289,6 +375,13 @@ pub(crate) unsafe fn init(config: Config) {
289 w.set_adcpre(config.adc_pre); 375 w.set_adcpre(config.adc_pre);
290 }); 376 });
291 377
378 // I2S2 and I2S3
379 #[cfg(stm32f107)]
380 {
381 RCC.cfgr2().modify(|w| w.set_i2s2src(config.i2s2_src));
382 RCC.cfgr2().modify(|w| w.set_i2s3src(config.i2s3_src));
383 }
384
292 // Wait for the new prescalers to kick in 385 // Wait for the new prescalers to kick in
293 // "The clocks are divided with the new prescaler factor from 386 // "The clocks are divided with the new prescaler factor from
294 // 1 to 16 AHB cycles after write" 387 // 1 to 16 AHB cycles after write"
@@ -328,9 +421,9 @@ pub(crate) unsafe fn init(config: Config) {
328 assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); 421 assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1));
329 422
330 let (div, ckmode) = match adcpres { 423 let (div, ckmode) = match adcpres {
331 AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), 424 AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNC_DIV1),
332 AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), 425 AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNC_DIV2),
333 AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), 426 AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNC_DIV4),
334 }; 427 };
335 common.ccr().modify(|w| w.set_ckmode(ckmode)); 428 common.ccr().modify(|w| w.set_ckmode(ckmode));
336 429
@@ -357,9 +450,9 @@ pub(crate) unsafe fn init(config: Config) {
357 assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); 450 assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1));
358 451
359 let (div, ckmode) = match adcpres { 452 let (div, ckmode) = match adcpres {
360 AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), 453 AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNC_DIV1),
361 AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), 454 AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNC_DIV2),
362 AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), 455 AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNC_DIV4),
363 }; 456 };
364 common.ccr().modify(|w| w.set_ckmode(ckmode)); 457 common.ccr().modify(|w| w.set_ckmode(ckmode));
365 458
@@ -393,9 +486,6 @@ pub(crate) unsafe fn init(config: Config) {
393 hsi: hsi, 486 hsi: hsi,
394 hse: hse, 487 hse: hse,
395 pll1_p: pll, 488 pll1_p: pll,
396 #[cfg(stm32f3)]
397 pll1_p_mul_2: pll_mul_2,
398 hsi_div_244: hsi.map(|h| h / 244u32),
399 sys: Some(sys), 489 sys: Some(sys),
400 pclk1: Some(pclk1), 490 pclk1: Some(pclk1),
401 pclk2: Some(pclk2), 491 pclk2: Some(pclk2),
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 61f687d30..8f2e8db5f 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -1,5 +1,7 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2 2
3#[cfg(any(stm32f413, stm32f423, stm32f412))]
4pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource;
3pub use crate::pac::rcc::vals::{ 5pub use crate::pac::rcc::vals::{
4 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, 6 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, 7 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
@@ -63,6 +65,7 @@ pub struct Pll {
63/// Used to calculate flash waitstates. See 65/// Used to calculate flash waitstates. See
64/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency 66/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
65#[cfg(stm32f2)] 67#[cfg(stm32f2)]
68#[derive(Clone, Copy)]
66pub enum VoltageScale { 69pub enum VoltageScale {
67 /// 2.7 to 3.6 V 70 /// 2.7 to 3.6 V
68 Range0, 71 Range0,
@@ -76,12 +79,15 @@ pub enum VoltageScale {
76 79
77/// Configuration of the core clocks 80/// Configuration of the core clocks
78#[non_exhaustive] 81#[non_exhaustive]
82#[derive(Clone, Copy)]
79pub struct Config { 83pub struct Config {
80 pub hsi: bool, 84 pub hsi: bool,
81 pub hse: Option<Hse>, 85 pub hse: Option<Hse>,
82 pub sys: Sysclk, 86 pub sys: Sysclk,
83 87
84 pub pll_src: PllSource, 88 pub pll_src: PllSource,
89 #[cfg(any(stm32f412, stm32f413, stm32f423))]
90 pub external_i2s_clock: Option<Hertz>,
85 91
86 pub pll: Option<Pll>, 92 pub pll: Option<Pll>,
87 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] 93 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
@@ -102,13 +108,15 @@ pub struct Config {
102 pub voltage: VoltageScale, 108 pub voltage: VoltageScale,
103} 109}
104 110
105impl Default for Config { 111impl Config {
106 fn default() -> Self { 112 pub const fn new() -> Self {
107 Self { 113 Self {
108 hsi: true, 114 hsi: true,
109 hse: None, 115 hse: None,
110 sys: Sysclk::HSI, 116 sys: Sysclk::HSI,
111 pll_src: PllSource::HSI, 117 pll_src: PllSource::HSI,
118 #[cfg(any(stm32f412, stm32f413, stm32f423))]
119 external_i2s_clock: None,
112 pll: None, 120 pll: None,
113 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] 121 #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
114 plli2s: None, 122 plli2s: None,
@@ -119,15 +127,21 @@ impl Default for Config {
119 apb1_pre: APBPrescaler::DIV1, 127 apb1_pre: APBPrescaler::DIV1,
120 apb2_pre: APBPrescaler::DIV1, 128 apb2_pre: APBPrescaler::DIV1,
121 129
122 ls: Default::default(), 130 ls: crate::rcc::LsConfig::new(),
123 131
124 #[cfg(stm32f2)] 132 #[cfg(stm32f2)]
125 voltage: VoltageScale::Range3, 133 voltage: VoltageScale::Range3,
126 mux: Default::default(), 134 mux: super::mux::ClockMux::default(),
127 } 135 }
128 } 136 }
129} 137}
130 138
139impl Default for Config {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
131pub(crate) unsafe fn init(config: Config) { 145pub(crate) unsafe fn init(config: Config) {
132 // set VOS to SCALE1, if use PLL 146 // set VOS to SCALE1, if use PLL
133 // TODO: check real clock speed before set VOS 147 // TODO: check real clock speed before set VOS
@@ -168,8 +182,8 @@ pub(crate) unsafe fn init(config: Config) {
168 } 182 }
169 Some(hse) => { 183 Some(hse) => {
170 match hse.mode { 184 match hse.mode {
171 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), 185 HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)),
172 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), 186 HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)),
173 } 187 }
174 188
175 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); 189 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
@@ -183,6 +197,8 @@ pub(crate) unsafe fn init(config: Config) {
183 let pll_input = PllInput { 197 let pll_input = PllInput {
184 hse, 198 hse,
185 hsi, 199 hsi,
200 #[cfg(any(stm32f412, stm32f413, stm32f423))]
201 external: config.external_i2s_clock,
186 source: config.pll_src, 202 source: config.pll_src,
187 }; 203 };
188 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); 204 let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
@@ -203,10 +219,10 @@ pub(crate) unsafe fn init(config: Config) {
203 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); 219 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
204 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); 220 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
205 221
206 assert!(max::SYSCLK.contains(&sys)); 222 rcc_assert!(max::SYSCLK.contains(&sys));
207 assert!(max::HCLK.contains(&hclk)); 223 rcc_assert!(max::HCLK.contains(&hclk));
208 assert!(max::PCLK1.contains(&pclk1)); 224 rcc_assert!(max::PCLK1.contains(&pclk1));
209 assert!(max::PCLK2.contains(&pclk2)); 225 rcc_assert!(max::PCLK2.contains(&pclk2));
210 226
211 let rtc = config.ls.init(); 227 let rtc = config.ls.init();
212 228
@@ -306,7 +322,6 @@ pub(crate) unsafe fn init(config: Config) {
306 #[cfg(dsihost)] 322 #[cfg(dsihost)]
307 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers 323 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers
308 324
309 hsi_div488: hsi.map(|hsi| hsi/488u32),
310 hsi_hse: None, 325 hsi_hse: None,
311 afif: None, 326 afif: None,
312 ); 327 );
@@ -316,6 +331,8 @@ struct PllInput {
316 source: PllSource, 331 source: PllSource,
317 hsi: Option<Hertz>, 332 hsi: Option<Hertz>,
318 hse: Option<Hertz>, 333 hse: Option<Hertz>,
334 #[cfg(any(stm32f412, stm32f413, stm32f423))]
335 external: Option<Hertz>,
319} 336}
320 337
321#[derive(Default)] 338#[derive(Default)]
@@ -360,10 +377,17 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
360 377
361 let Some(pll) = config else { return PllOutput::default() }; 378 let Some(pll) = config else { return PllOutput::default() };
362 379
380 #[cfg(not(any(stm32f412, stm32f413, stm32f423)))]
363 let pll_src = match input.source { 381 let pll_src = match input.source {
364 PllSource::HSE => input.hse, 382 PllSource::HSE => input.hse,
365 PllSource::HSI => input.hsi, 383 PllSource::HSI => input.hsi,
366 }; 384 };
385 #[cfg(any(stm32f412, stm32f413, stm32f423))]
386 let pll_src = match (input.source, input.external) {
387 (PllSource::HSE, None) => input.hse,
388 (PllSource::HSI, None) => input.hsi,
389 (_, Some(ext)) => Some(ext),
390 };
367 391
368 let pll_src = pll_src.unwrap(); 392 let pll_src = pll_src.unwrap();
369 393
@@ -412,6 +436,17 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
412 }), 436 }),
413 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] 437 #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
414 PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { 438 PllInstance::Plli2s => RCC.plli2scfgr().write(|w| {
439 #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
440 w.set_pllm(pll.prediv);
441 #[cfg(any(stm32f412, stm32f413, stm32f423))]
442 {
443 let plli2ssource = match input.external {
444 Some(_) => Plli2sSource::EXTERNAL,
445 None => Plli2sSource::HSE_HSI,
446 };
447 w.set_plli2ssrc(plli2ssource);
448 }
449
415 write_fields!(w); 450 write_fields!(w);
416 }), 451 }),
417 #[cfg(stm32f2)] 452 #[cfg(stm32f2)]
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index c2fa0ca39..ce6398afd 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -1,10 +1,11 @@
1use crate::pac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2pub use crate::pac::pwr::vals::Vos as VoltageRange; 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, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, 4 Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv,
5 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 5 Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
6}; 6};
7use crate::pac::{FLASH, PWR, RCC}; 7use crate::pac::{FLASH, PWR, RCC};
8use crate::rcc::LSI_FREQ;
8use crate::time::Hertz; 9use crate::time::Hertz;
9 10
10/// HSI speed 11/// HSI speed
@@ -28,11 +29,18 @@ pub struct Hse {
28 pub mode: HseMode, 29 pub mode: HseMode,
29} 30}
30 31
32#[derive(Clone, Copy, Eq, PartialEq)]
33pub struct Hsi {
34 /// Division factor for HSISYS clock. Default is 1.
35 pub sys_div: HsiSysDiv,
36}
37
31/// PLL Configuration 38/// PLL Configuration
32/// 39///
33/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output 40/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
34/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate 41/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
35/// frequency ranges for each of these settings. 42/// frequency ranges for each of these settings.
43#[derive(Clone, Copy)]
36pub struct Pll { 44pub struct Pll {
37 /// PLL Source clock selection. 45 /// PLL Source clock selection.
38 pub source: PllSource, 46 pub source: PllSource,
@@ -55,9 +63,10 @@ pub struct Pll {
55 63
56/// Clocks configutation 64/// Clocks configutation
57#[non_exhaustive] 65#[non_exhaustive]
66#[derive(Clone, Copy)]
58pub struct Config { 67pub struct Config {
59 /// HSI Enable 68 /// HSI Configuration
60 pub hsi: bool, 69 pub hsi: Option<Hsi>,
61 70
62 /// HSE Configuration 71 /// HSE Configuration
63 pub hse: Option<Hse>, 72 pub hse: Option<Hse>,
@@ -88,26 +97,33 @@ pub struct Config {
88 pub mux: super::mux::ClockMux, 97 pub mux: super::mux::ClockMux,
89} 98}
90 99
91impl Default for Config { 100impl Config {
92 #[inline] 101 pub const fn new() -> Self {
93 fn default() -> Config {
94 Config { 102 Config {
95 hsi: true, 103 hsi: Some(Hsi {
104 sys_div: HsiSysDiv::DIV1,
105 }),
96 hse: None, 106 hse: None,
97 sys: Sysclk::HSI, 107 sys: Sysclk::HSI,
98 #[cfg(crs)] 108 #[cfg(crs)]
99 hsi48: Some(Default::default()), 109 hsi48: Some(crate::rcc::Hsi48Config::new()),
100 pll: None, 110 pll: None,
101 ahb_pre: AHBPrescaler::DIV1, 111 ahb_pre: AHBPrescaler::DIV1,
102 apb1_pre: APBPrescaler::DIV1, 112 apb1_pre: APBPrescaler::DIV1,
103 low_power_run: false, 113 low_power_run: false,
104 ls: Default::default(), 114 ls: crate::rcc::LsConfig::new(),
105 voltage_range: VoltageRange::RANGE1, 115 voltage_range: VoltageRange::RANGE1,
106 mux: Default::default(), 116 mux: super::mux::ClockMux::default(),
107 } 117 }
108 } 118 }
109} 119}
110 120
121impl Default for Config {
122 fn default() -> Config {
123 Self::new()
124 }
125}
126
111#[derive(Default)] 127#[derive(Default)]
112pub struct PllFreq { 128pub struct PllFreq {
113 pub pll_p: Option<Hertz>, 129 pub pll_p: Option<Hertz>,
@@ -117,7 +133,12 @@ pub struct PllFreq {
117 133
118pub(crate) unsafe fn init(config: Config) { 134pub(crate) unsafe fn init(config: Config) {
119 // Turn on the HSI 135 // Turn on the HSI
120 RCC.cr().modify(|w| w.set_hsion(true)); 136 RCC.cr().modify(|w| {
137 w.set_hsion(true);
138 if let Some(hsi) = config.hsi {
139 w.set_hsidiv(hsi.sys_div);
140 }
141 });
121 while !RCC.cr().read().hsirdy() {} 142 while !RCC.cr().read().hsirdy() {}
122 143
123 // Use the HSI clock as system clock during the actual clock setup 144 // Use the HSI clock as system clock during the actual clock setup
@@ -125,9 +146,9 @@ pub(crate) unsafe fn init(config: Config) {
125 while RCC.cfgr().read().sws() != Sysclk::HSI {} 146 while RCC.cfgr().read().sws() != Sysclk::HSI {}
126 147
127 // Configure HSI 148 // Configure HSI
128 let hsi = match config.hsi { 149 let (hsi, hsisys) = match config.hsi {
129 false => None, 150 None => (None, None),
130 true => Some(HSI_FREQ), 151 Some(hsi) => (Some(HSI_FREQ), Some(HSI_FREQ / hsi.sys_div)),
131 }; 152 };
132 153
133 // Configure HSE 154 // Configure HSE
@@ -138,8 +159,8 @@ pub(crate) unsafe fn init(config: Config) {
138 } 159 }
139 Some(hse) => { 160 Some(hse) => {
140 match hse.mode { 161 match hse.mode {
141 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), 162 HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)),
142 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), 163 HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)),
143 } 164 }
144 165
145 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); 166 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
@@ -167,10 +188,9 @@ pub(crate) unsafe fn init(config: Config) {
167 while RCC.cr().read().pllrdy() {} 188 while RCC.cr().read().pllrdy() {}
168 189
169 let in_freq = src_freq / pll_config.prediv; 190 let in_freq = src_freq / pll_config.prediv;
170 assert!(max::PLL_IN.contains(&in_freq)); 191 rcc_assert!(max::PLL_IN.contains(&in_freq));
171 let internal_freq = in_freq * pll_config.mul; 192 let internal_freq = in_freq * pll_config.mul;
172 193 rcc_assert!(max::PLL_VCO.contains(&internal_freq));
173 assert!(max::PLL_VCO.contains(&internal_freq));
174 194
175 RCC.pllcfgr().write(|w| { 195 RCC.pllcfgr().write(|w| {
176 w.set_plln(pll_config.mul); 196 w.set_plln(pll_config.mul);
@@ -184,7 +204,7 @@ pub(crate) unsafe fn init(config: Config) {
184 w.set_pllpen(true); 204 w.set_pllpen(true);
185 }); 205 });
186 let freq = internal_freq / div_p; 206 let freq = internal_freq / div_p;
187 assert!(max::PLL_P.contains(&freq)); 207 rcc_assert!(max::PLL_P.contains(&freq));
188 freq 208 freq
189 }); 209 });
190 210
@@ -194,7 +214,7 @@ pub(crate) unsafe fn init(config: Config) {
194 w.set_pllqen(true); 214 w.set_pllqen(true);
195 }); 215 });
196 let freq = internal_freq / div_q; 216 let freq = internal_freq / div_q;
197 assert!(max::PLL_Q.contains(&freq)); 217 rcc_assert!(max::PLL_Q.contains(&freq));
198 freq 218 freq
199 }); 219 });
200 220
@@ -204,7 +224,7 @@ pub(crate) unsafe fn init(config: Config) {
204 w.set_pllren(true); 224 w.set_pllren(true);
205 }); 225 });
206 let freq = internal_freq / div_r; 226 let freq = internal_freq / div_r;
207 assert!(max::PLL_R.contains(&freq)); 227 rcc_assert!(max::PLL_R.contains(&freq));
208 freq 228 freq
209 }); 229 });
210 230
@@ -220,21 +240,28 @@ pub(crate) unsafe fn init(config: Config) {
220 }) 240 })
221 .unwrap_or_default(); 241 .unwrap_or_default();
222 242
243 let rtc = config.ls.init();
244
223 let sys = match config.sys { 245 let sys = match config.sys {
224 Sysclk::HSI => unwrap!(hsi), 246 Sysclk::HSI => unwrap!(hsisys),
225 Sysclk::HSE => unwrap!(hse), 247 Sysclk::HSE => unwrap!(hse),
226 Sysclk::PLL1_R => unwrap!(pll.pll_r), 248 Sysclk::PLL1_R => unwrap!(pll.pll_r),
249 Sysclk::LSI => {
250 assert!(config.ls.lsi);
251 LSI_FREQ
252 }
253 Sysclk::LSE => unwrap!(config.ls.lse).frequency,
227 _ => unreachable!(), 254 _ => unreachable!(),
228 }; 255 };
229 256
230 assert!(max::SYSCLK.contains(&sys)); 257 rcc_assert!(max::SYSCLK.contains(&sys));
231 258
232 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. 259 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
233 let hclk = sys / config.ahb_pre; 260 let hclk = sys / config.ahb_pre;
234 assert!(max::HCLK.contains(&hclk)); 261 rcc_assert!(max::HCLK.contains(&hclk));
235 262
236 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); 263 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
237 assert!(max::PCLK.contains(&pclk1)); 264 rcc_assert!(max::PCLK.contains(&pclk1));
238 265
239 let latency = match (config.voltage_range, hclk.0) { 266 let latency = match (config.voltage_range, hclk.0) {
240 (VoltageRange::RANGE1, ..=24_000_000) => Latency::WS0, 267 (VoltageRange::RANGE1, ..=24_000_000) => Latency::WS0,
@@ -263,7 +290,7 @@ pub(crate) unsafe fn init(config: Config) {
263 while RCC.cfgr().read().sws() != config.sys {} 290 while RCC.cfgr().read().sws() != config.sys {}
264 291
265 // Disable HSI if not used 292 // Disable HSI if not used
266 if !config.hsi { 293 if config.hsi.is_none() {
267 RCC.cr().modify(|w| w.set_hsion(false)); 294 RCC.cr().modify(|w| w.set_hsion(false));
268 } 295 }
269 296
@@ -272,8 +299,6 @@ pub(crate) unsafe fn init(config: Config) {
272 PWR.cr1().modify(|w| w.set_lpr(true)); 299 PWR.cr1().modify(|w| w.set_lpr(true));
273 } 300 }
274 301
275 let rtc = config.ls.init();
276
277 config.mux.init(); 302 config.mux.init();
278 303
279 set_clocks!( 304 set_clocks!(
@@ -289,8 +314,6 @@ pub(crate) unsafe fn init(config: Config) {
289 #[cfg(crs)] 314 #[cfg(crs)]
290 hsi48: hsi48, 315 hsi48: hsi48,
291 rtc: rtc, 316 rtc: rtc,
292 hsi_div_8: hsi.map(|h| h / 8u32),
293 hsi_div_488: hsi.map(|h| h / 488u32),
294 317
295 // TODO 318 // TODO
296 lsi: None, 319 lsi: None,
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index c261c0fed..da13e16aa 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -32,6 +32,7 @@ pub struct Hse {
32/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output 32/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
33/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate 33/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
34/// frequency ranges for each of these settings. 34/// frequency ranges for each of these settings.
35#[derive(Clone, Copy)]
35pub struct Pll { 36pub struct Pll {
36 /// PLL Source clock selection. 37 /// PLL Source clock selection.
37 pub source: PllSource, 38 pub source: PllSource,
@@ -54,6 +55,7 @@ pub struct Pll {
54 55
55/// Clocks configutation 56/// Clocks configutation
56#[non_exhaustive] 57#[non_exhaustive]
58#[derive(Clone, Copy)]
57pub struct Config { 59pub struct Config {
58 /// HSI Enable 60 /// HSI Enable
59 pub hsi: bool, 61 pub hsi: bool,
@@ -89,26 +91,31 @@ pub struct Config {
89 pub mux: super::mux::ClockMux, 91 pub mux: super::mux::ClockMux,
90} 92}
91 93
92impl Default for Config { 94impl Config {
93 #[inline] 95 pub const fn new() -> Self {
94 fn default() -> Config {
95 Config { 96 Config {
96 hsi: true, 97 hsi: true,
97 hse: None, 98 hse: None,
98 sys: Sysclk::HSI, 99 sys: Sysclk::HSI,
99 hsi48: Some(Default::default()), 100 hsi48: Some(crate::rcc::Hsi48Config::new()),
100 pll: None, 101 pll: None,
101 ahb_pre: AHBPrescaler::DIV1, 102 ahb_pre: AHBPrescaler::DIV1,
102 apb1_pre: APBPrescaler::DIV1, 103 apb1_pre: APBPrescaler::DIV1,
103 apb2_pre: APBPrescaler::DIV1, 104 apb2_pre: APBPrescaler::DIV1,
104 low_power_run: false, 105 low_power_run: false,
105 ls: Default::default(), 106 ls: crate::rcc::LsConfig::new(),
106 boost: false, 107 boost: false,
107 mux: Default::default(), 108 mux: super::mux::ClockMux::default(),
108 } 109 }
109 } 110 }
110} 111}
111 112
113impl Default for Config {
114 fn default() -> Config {
115 Self::new()
116 }
117}
118
112#[derive(Default)] 119#[derive(Default)]
113pub struct PllFreq { 120pub struct PllFreq {
114 pub pll_p: Option<Hertz>, 121 pub pll_p: Option<Hertz>,
@@ -139,8 +146,8 @@ pub(crate) unsafe fn init(config: Config) {
139 } 146 }
140 Some(hse) => { 147 Some(hse) => {
141 match hse.mode { 148 match hse.mode {
142 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), 149 HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)),
143 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), 150 HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)),
144 } 151 }
145 152
146 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); 153 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
@@ -167,10 +174,10 @@ pub(crate) unsafe fn init(config: Config) {
167 while RCC.cr().read().pllrdy() {} 174 while RCC.cr().read().pllrdy() {}
168 175
169 let in_freq = src_freq / pll_config.prediv; 176 let in_freq = src_freq / pll_config.prediv;
170 assert!(max::PLL_IN.contains(&in_freq)); 177 rcc_assert!(max::PLL_IN.contains(&in_freq));
171 let internal_freq = in_freq * pll_config.mul; 178 let internal_freq = in_freq * pll_config.mul;
172 179
173 assert!(max::PLL_VCO.contains(&internal_freq)); 180 rcc_assert!(max::PLL_VCO.contains(&internal_freq));
174 181
175 RCC.pllcfgr().write(|w| { 182 RCC.pllcfgr().write(|w| {
176 w.set_plln(pll_config.mul); 183 w.set_plln(pll_config.mul);
@@ -184,7 +191,7 @@ pub(crate) unsafe fn init(config: Config) {
184 w.set_pllpen(true); 191 w.set_pllpen(true);
185 }); 192 });
186 let freq = internal_freq / div_p; 193 let freq = internal_freq / div_p;
187 assert!(max::PLL_P.contains(&freq)); 194 rcc_assert!(max::PLL_P.contains(&freq));
188 freq 195 freq
189 }); 196 });
190 197
@@ -194,7 +201,7 @@ pub(crate) unsafe fn init(config: Config) {
194 w.set_pllqen(true); 201 w.set_pllqen(true);
195 }); 202 });
196 let freq = internal_freq / div_q; 203 let freq = internal_freq / div_q;
197 assert!(max::PLL_Q.contains(&freq)); 204 rcc_assert!(max::PLL_Q.contains(&freq));
198 freq 205 freq
199 }); 206 });
200 207
@@ -204,7 +211,7 @@ pub(crate) unsafe fn init(config: Config) {
204 w.set_pllren(true); 211 w.set_pllren(true);
205 }); 212 });
206 let freq = internal_freq / div_r; 213 let freq = internal_freq / div_r;
207 assert!(max::PLL_R.contains(&freq)); 214 rcc_assert!(max::PLL_R.contains(&freq));
208 freq 215 freq
209 }); 216 });
210 217
@@ -227,16 +234,16 @@ pub(crate) unsafe fn init(config: Config) {
227 _ => unreachable!(), 234 _ => unreachable!(),
228 }; 235 };
229 236
230 assert!(max::SYSCLK.contains(&sys)); 237 rcc_assert!(max::SYSCLK.contains(&sys));
231 238
232 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. 239 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
233 let hclk = sys / config.ahb_pre; 240 let hclk = sys / config.ahb_pre;
234 assert!(max::HCLK.contains(&hclk)); 241 rcc_assert!(max::HCLK.contains(&hclk));
235 242
236 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); 243 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
237 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); 244 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
238 assert!(max::PCLK.contains(&pclk2)); 245 rcc_assert!(max::PCLK.contains(&pclk1));
239 assert!(max::PCLK.contains(&pclk2)); 246 rcc_assert!(max::PCLK.contains(&pclk2));
240 247
241 // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) 248 // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!)
242 if config.boost { 249 if config.boost {
@@ -318,6 +325,8 @@ pub(crate) unsafe fn init(config: Config) {
318 hse: hse, 325 hse: hse,
319 hsi48: hsi48, 326 hsi48: hsi48,
320 rtc: rtc, 327 rtc: rtc,
328 lsi: None,
329 lse: None,
321 ); 330 );
322} 331}
323 332
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index e3c7dd158..383f48874 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -34,8 +34,10 @@ pub enum VoltageScale {
34 Scale2, 34 Scale2,
35 Scale3, 35 Scale3,
36} 36}
37#[cfg(any(stm32h7rs))] 37#[cfg(stm32h7rs)]
38pub use crate::pac::pwr::vals::Vos as VoltageScale; 38pub use crate::pac::pwr::vals::Vos as VoltageScale;
39#[cfg(all(stm32h7rs, peri_usb_otg_hs))]
40pub use crate::pac::rcc::vals::{Usbphycsel, Usbrefcksel};
39 41
40#[derive(Clone, Copy, Eq, PartialEq)] 42#[derive(Clone, Copy, Eq, PartialEq)]
41pub enum HseMode { 43pub enum HseMode {
@@ -111,8 +113,8 @@ pub enum TimerPrescaler {
111impl From<TimerPrescaler> for Timpre { 113impl From<TimerPrescaler> for Timpre {
112 fn from(value: TimerPrescaler) -> Self { 114 fn from(value: TimerPrescaler) -> Self {
113 match value { 115 match value {
114 TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, 116 TimerPrescaler::DefaultX2 => Timpre::DEFAULT_X2,
115 TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, 117 TimerPrescaler::DefaultX4 => Timpre::DEFAULT_X4,
116 } 118 }
117 } 119 }
118} 120}
@@ -120,7 +122,7 @@ impl From<TimerPrescaler> for Timpre {
120/// Power supply configuration 122/// Power supply configuration
121/// See RM0433 Rev 4 7.4 123/// See RM0433 Rev 4 7.4
122#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] 124#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))]
123#[derive(PartialEq)] 125#[derive(Clone, Copy, PartialEq)]
124pub enum SupplyConfig { 126pub enum SupplyConfig {
125 /// Default power supply configuration. 127 /// Default power supply configuration.
126 /// V CORE Power Domains are supplied from the LDO according to VOS. 128 /// V CORE Power Domains are supplied from the LDO according to VOS.
@@ -180,6 +182,7 @@ pub enum SMPSSupplyVoltage {
180 182
181/// Configuration of the core clocks 183/// Configuration of the core clocks
182#[non_exhaustive] 184#[non_exhaustive]
185#[derive(Clone, Copy)]
183pub struct Config { 186pub struct Config {
184 pub hsi: Option<HSIPrescaler>, 187 pub hsi: Option<HSIPrescaler>,
185 pub hse: Option<Hse>, 188 pub hse: Option<Hse>,
@@ -215,13 +218,13 @@ pub struct Config {
215 pub mux: super::mux::ClockMux, 218 pub mux: super::mux::ClockMux,
216} 219}
217 220
218impl Default for Config { 221impl Config {
219 fn default() -> Self { 222 pub const fn new() -> Self {
220 Self { 223 Self {
221 hsi: Some(HSIPrescaler::DIV1), 224 hsi: Some(HSIPrescaler::DIV1),
222 hse: None, 225 hse: None,
223 csi: false, 226 csi: false,
224 hsi48: Some(Default::default()), 227 hsi48: Some(crate::rcc::Hsi48Config::new()),
225 sys: Sysclk::HSI, 228 sys: Sysclk::HSI,
226 pll1: None, 229 pll1: None,
227 pll2: None, 230 pll2: None,
@@ -245,16 +248,22 @@ impl Default for Config {
245 voltage_scale: VoltageScale::Scale0, 248 voltage_scale: VoltageScale::Scale0,
246 #[cfg(rcc_h7rs)] 249 #[cfg(rcc_h7rs)]
247 voltage_scale: VoltageScale::HIGH, 250 voltage_scale: VoltageScale::HIGH,
248 ls: Default::default(), 251 ls: crate::rcc::LsConfig::new(),
249 252
250 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] 253 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))]
251 supply_config: SupplyConfig::LDO, 254 supply_config: SupplyConfig::LDO,
252 255
253 mux: Default::default(), 256 mux: super::mux::ClockMux::default(),
254 } 257 }
255 } 258 }
256} 259}
257 260
261impl Default for Config {
262 fn default() -> Self {
263 Self::new()
264 }
265}
266
258pub(crate) unsafe fn init(config: Config) { 267pub(crate) unsafe fn init(config: Config) {
259 #[cfg(any(stm32h7))] 268 #[cfg(any(stm32h7))]
260 let pwr_reg = PWR.cr3(); 269 let pwr_reg = PWR.cr3();
@@ -556,6 +565,27 @@ pub(crate) unsafe fn init(config: Config) {
556 565
557 let rtc = config.ls.init(); 566 let rtc = config.ls.init();
558 567
568 #[cfg(all(stm32h7rs, peri_usb_otg_hs))]
569 let usb_refck = match config.mux.usbphycsel {
570 Usbphycsel::HSE => hse,
571 Usbphycsel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8),
572 Usbphycsel::PLL3_Q => pll3.q,
573 _ => None,
574 };
575 #[cfg(all(stm32h7rs, peri_usb_otg_hs))]
576 let usb_refck_sel = match usb_refck {
577 Some(clk_val) => match clk_val {
578 Hertz(16_000_000) => Usbrefcksel::MHZ16,
579 Hertz(19_200_000) => Usbrefcksel::MHZ19_2,
580 Hertz(20_000_000) => Usbrefcksel::MHZ20,
581 Hertz(24_000_000) => Usbrefcksel::MHZ24,
582 Hertz(26_000_000) => Usbrefcksel::MHZ26,
583 Hertz(32_000_000) => Usbrefcksel::MHZ32,
584 _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val),
585 },
586 None => Usbrefcksel::MHZ24,
587 };
588
559 #[cfg(stm32h7)] 589 #[cfg(stm32h7)]
560 { 590 {
561 RCC.d1cfgr().modify(|w| { 591 RCC.d1cfgr().modify(|w| {
@@ -592,6 +622,11 @@ pub(crate) unsafe fn init(config: Config) {
592 w.set_ppre4(config.apb4_pre); 622 w.set_ppre4(config.apb4_pre);
593 w.set_ppre5(config.apb5_pre); 623 w.set_ppre5(config.apb5_pre);
594 }); 624 });
625
626 #[cfg(peri_usb_otg_hs)]
627 RCC.ahbperckselr().modify(|w| {
628 w.set_usbrefcksel(usb_refck_sel);
629 });
595 } 630 }
596 #[cfg(stm32h5)] 631 #[cfg(stm32h5)]
597 { 632 {
@@ -658,7 +693,6 @@ pub(crate) unsafe fn init(config: Config) {
658 hsi: hsi, 693 hsi: hsi,
659 hsi48: hsi48, 694 hsi48: hsi48,
660 csi: csi, 695 csi: csi,
661 csi_div_122: csi.map(|c| c / 122u32),
662 hse: hse, 696 hse: hse,
663 697
664 lse: None, 698 lse: None,
@@ -697,7 +731,9 @@ pub(crate) unsafe fn init(config: Config) {
697 #[cfg(stm32h7rs)] 731 #[cfg(stm32h7rs)]
698 clk48mohci: None, // TODO 732 clk48mohci: None, // TODO
699 #[cfg(stm32h7rs)] 733 #[cfg(stm32h7rs)]
700 usb: None, // TODO 734 usb: Some(Hertz(48_000_000)),
735 #[cfg(stm32h5)]
736 hse_div_rtcpre: None, // TODO
701 ); 737 );
702} 738}
703 739
@@ -748,7 +784,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
748 ..=3_999_999 => Pllrge::RANGE2, 784 ..=3_999_999 => Pllrge::RANGE2,
749 ..=7_999_999 => Pllrge::RANGE4, 785 ..=7_999_999 => Pllrge::RANGE4,
750 ..=16_000_000 => Pllrge::RANGE8, 786 ..=16_000_000 => Pllrge::RANGE8,
751 x => panic!("pll ref_clk out of range: {} mhz", x), 787 x => panic!("pll ref_clk out of range: {} hz", x),
752 }; 788 };
753 789
754 // The smaller range (150 to 420 MHz) must 790 // The smaller range (150 to 420 MHz) must
@@ -757,18 +793,18 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
757 793
758 let vco_clk = ref_clk * config.mul; 794 let vco_clk = ref_clk * config.mul;
759 let vco_range = if VCO_RANGE.contains(&vco_clk) { 795 let vco_range = if VCO_RANGE.contains(&vco_clk) {
760 Pllvcosel::MEDIUMVCO 796 Pllvcosel::MEDIUM_VCO
761 } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { 797 } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) {
762 Pllvcosel::WIDEVCO 798 Pllvcosel::WIDE_VCO
763 } else { 799 } else {
764 panic!("pll vco_clk out of range: {} hz", vco_clk.0) 800 panic!("pll vco_clk out of range: {}", vco_clk)
765 }; 801 };
766 802
767 let p = config.divp.map(|div| { 803 let p = config.divp.map(|div| {
768 if num == 0 { 804 if num == 0 {
769 // on PLL1, DIVP must be even for most series. 805 // on PLL1, DIVP must be even for most series.
770 // The enum value is 1 less than the divider, so check it's odd. 806 // The enum value is 1 less than the divider, so check it's odd.
771 #[cfg(not(pwr_h7rm0468))] 807 #[cfg(not(any(pwr_h7rm0468, stm32h7rs)))]
772 assert!(div.to_bits() % 2 == 1); 808 assert!(div.to_bits() % 2 == 1);
773 #[cfg(pwr_h7rm0468)] 809 #[cfg(pwr_h7rm0468)]
774 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0); 810 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs
index efabd059f..3ea5c96c9 100644
--- a/embassy-stm32/src/rcc/hsi48.rs
+++ b/embassy-stm32/src/rcc/hsi48.rs
@@ -18,9 +18,15 @@ pub struct Hsi48Config {
18 pub sync_from_usb: bool, 18 pub sync_from_usb: bool,
19} 19}
20 20
21impl Hsi48Config {
22 pub const fn new() -> Self {
23 Self { sync_from_usb: false }
24 }
25}
26
21impl Default for Hsi48Config { 27impl Default for Hsi48Config {
22 fn default() -> Self { 28 fn default() -> Self {
23 Self { sync_from_usb: false } 29 Self::new()
24 } 30 }
25} 31}
26 32
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index e9266c65b..81b89046e 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -5,6 +5,7 @@ use crate::pac::rcc::regs::Cfgr;
5pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; 5pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
6pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk}; 6pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk};
7use crate::pac::{FLASH, RCC}; 7use crate::pac::{FLASH, RCC};
8use crate::rcc::LSI_FREQ;
8use crate::time::Hertz; 9use crate::time::Hertz;
9 10
10/// HSI speed 11/// HSI speed
@@ -30,6 +31,7 @@ pub struct Hse {
30} 31}
31 32
32/// Clocks configuration 33/// Clocks configuration
34#[derive(Clone, Copy)]
33pub struct Config { 35pub struct Config {
34 // base clock sources 36 // base clock sources
35 pub msi: Option<MSIRange>, 37 pub msi: Option<MSIRange>,
@@ -66,9 +68,8 @@ pub struct Config {
66 pub mux: super::mux::ClockMux, 68 pub mux: super::mux::ClockMux,
67} 69}
68 70
69impl Default for Config { 71impl Config {
70 #[inline] 72 pub const fn new() -> Self {
71 fn default() -> Config {
72 Config { 73 Config {
73 hse: None, 74 hse: None,
74 hsi: false, 75 hsi: false,
@@ -88,15 +89,21 @@ impl Default for Config {
88 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] 89 #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
89 pllsai2: None, 90 pllsai2: None,
90 #[cfg(crs)] 91 #[cfg(crs)]
91 hsi48: Some(Default::default()), 92 hsi48: Some(crate::rcc::Hsi48Config::new()),
92 ls: Default::default(), 93 ls: crate::rcc::LsConfig::new(),
93 #[cfg(any(stm32l0, stm32l1))] 94 #[cfg(any(stm32l0, stm32l1))]
94 voltage_scale: VoltageScale::RANGE1, 95 voltage_scale: VoltageScale::RANGE1,
95 mux: Default::default(), 96 mux: super::mux::ClockMux::default(),
96 } 97 }
97 } 98 }
98} 99}
99 100
101impl Default for Config {
102 fn default() -> Config {
103 Self::new()
104 }
105}
106
100#[cfg(stm32wb)] 107#[cfg(stm32wb)]
101pub const WPAN_DEFAULT: Config = Config { 108pub const WPAN_DEFAULT: Config = Config {
102 hse: Some(Hse { 109 hse: Some(Hse {
@@ -181,6 +188,9 @@ pub(crate) unsafe fn init(config: Config) {
181 188
182 let rtc = config.ls.init(); 189 let rtc = config.ls.init();
183 190
191 let lse = config.ls.lse.map(|l| l.frequency);
192 let lsi = config.ls.lsi.then_some(LSI_FREQ);
193
184 let msi = config.msi.map(|range| { 194 let msi = config.msi.map(|range| {
185 msi_enable(range); 195 msi_enable(range);
186 msirange_to_hertz(range) 196 msirange_to_hertz(range)
@@ -391,7 +401,7 @@ pub(crate) unsafe fn init(config: Config) {
391 hsi48: hsi48, 401 hsi48: hsi48,
392 402
393 #[cfg(any(stm32l0, stm32l1))] 403 #[cfg(any(stm32l0, stm32l1))]
394 pll1_vco_div_2: pll.vco.map(|c| c/2u32), 404 pll1_vco: pll.vco,
395 405
396 #[cfg(not(any(stm32l0, stm32l1)))] 406 #[cfg(not(any(stm32l0, stm32l1)))]
397 pll1_p: pll.p, 407 pll1_p: pll.p,
@@ -424,12 +434,12 @@ pub(crate) unsafe fn init(config: Config) {
424 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers 434 dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers
425 435
426 rtc: rtc, 436 rtc: rtc,
437 lse: lse,
438 lsi: lsi,
427 439
428 // TODO 440 // TODO
429 sai1_extclk: None, 441 sai1_extclk: None,
430 sai2_extclk: None, 442 sai2_extclk: None,
431 lsi: None,
432 lse: None,
433 ); 443 );
434} 444}
435 445
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index d1ce14c86..c50e071fb 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -1,6 +1,6 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy_hal_internal::into_ref; 3use embassy_hal_internal::PeripheralType;
4 4
5use crate::gpio::{AfType, OutputType, Speed}; 5use crate::gpio::{AfType, OutputType, Speed};
6#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] 6#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
@@ -32,7 +32,7 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource;
32))] 32))]
33pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; 33pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
34use crate::pac::RCC; 34use crate::pac::RCC;
35use crate::{peripherals, Peripheral}; 35use crate::{peripherals, Peri};
36 36
37#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] 37#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))]
38#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] 38#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
@@ -43,7 +43,7 @@ pub enum McoPrescaler {
43pub(crate) trait SealedMcoInstance {} 43pub(crate) trait SealedMcoInstance {}
44 44
45#[allow(private_bounds)] 45#[allow(private_bounds)]
46pub trait McoInstance: SealedMcoInstance + 'static { 46pub trait McoInstance: PeripheralType + SealedMcoInstance + 'static {
47 type Source; 47 type Source;
48 48
49 #[doc(hidden)] 49 #[doc(hidden)]
@@ -91,14 +91,7 @@ pub struct Mco<'d, T: McoInstance> {
91 91
92impl<'d, T: McoInstance> Mco<'d, T> { 92impl<'d, T: McoInstance> Mco<'d, T> {
93 /// Create a new MCO instance. 93 /// Create a new MCO instance.
94 pub fn new( 94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self {
95 _peri: impl Peripheral<P = T> + 'd,
96 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
97 source: T::Source,
98 prescaler: McoPrescaler,
99 ) -> Self {
100 into_ref!(pin);
101
102 critical_section::with(|_| unsafe { 95 critical_section::with(|_| unsafe {
103 T::_apply_clock_settings(source, prescaler); 96 T::_apply_clock_settings(source, prescaler);
104 pin.set_as_af(pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 97 pin.set_as_af(pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 8022a35a4..c41f81816 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -86,7 +86,7 @@ pub(crate) unsafe fn set_freqs(freqs: Clocks) {
86#[cfg(not(feature = "_dual-core"))] 86#[cfg(not(feature = "_dual-core"))]
87/// Safety: Reads a mutable global. 87/// Safety: Reads a mutable global.
88pub(crate) unsafe fn get_freqs() -> &'static Clocks { 88pub(crate) unsafe fn get_freqs() -> &'static Clocks {
89 CLOCK_FREQS.assume_init_ref() 89 (*core::ptr::addr_of_mut!(CLOCK_FREQS)).assume_init_ref()
90} 90}
91 91
92#[cfg(feature = "_dual-core")] 92#[cfg(feature = "_dual-core")]
@@ -95,8 +95,19 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks {
95 unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref() 95 unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref()
96} 96}
97 97
98/// Get the current clock configuration of the chip.
99pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clocks {
100 // Safety: the existence of a `Peri<RCC>` means that `rcc::init()`
101 // has already been called, so `CLOCK_FREQS` must be initialized.
102 // The clocks could be modified again by `reinit()`, but reinit
103 // (for this reason) requires an exclusive reference to `Peri<RCC>`.
104 unsafe { get_freqs() }
105}
106
98pub(crate) trait SealedRccPeripheral { 107pub(crate) trait SealedRccPeripheral {
99 fn frequency() -> Hertz; 108 fn frequency() -> Hertz;
109 #[allow(dead_code)]
110 fn bus_frequency() -> Hertz;
100 const RCC_INFO: RccInfo; 111 const RCC_INFO: RccInfo;
101} 112}
102 113
@@ -171,7 +182,9 @@ impl RccInfo {
171 // Use .get_mut instead of []-operator so that we control how bounds checks happen. 182 // Use .get_mut instead of []-operator so that we control how bounds checks happen.
172 // Otherwise, core::fmt will be pulled in here in order to format the integer in the 183 // Otherwise, core::fmt will be pulled in here in order to format the integer in the
173 // out-of-bounds error. 184 // out-of-bounds error.
174 if let Some(refcount) = unsafe { crate::_generated::REFCOUNTS.get_mut(refcount_idx) } { 185 if let Some(refcount) =
186 unsafe { (*core::ptr::addr_of_mut!(crate::_generated::REFCOUNTS)).get_mut(refcount_idx) }
187 {
175 *refcount += 1; 188 *refcount += 1;
176 if *refcount > 1 { 189 if *refcount > 1 {
177 return; 190 return;
@@ -235,7 +248,9 @@ impl RccInfo {
235 // Use .get_mut instead of []-operator so that we control how bounds checks happen. 248 // Use .get_mut instead of []-operator so that we control how bounds checks happen.
236 // Otherwise, core::fmt will be pulled in here in order to format the integer in the 249 // Otherwise, core::fmt will be pulled in here in order to format the integer in the
237 // out-of-bounds error. 250 // out-of-bounds error.
238 if let Some(refcount) = unsafe { crate::_generated::REFCOUNTS.get_mut(refcount_idx) } { 251 if let Some(refcount) =
252 unsafe { (*core::ptr::addr_of_mut!(crate::_generated::REFCOUNTS)).get_mut(refcount_idx) }
253 {
239 *refcount -= 1; 254 *refcount -= 1;
240 if *refcount > 0 { 255 if *refcount > 0 {
241 return; 256 return;
@@ -365,3 +380,32 @@ pub fn enable_and_reset<T: RccPeripheral>() {
365pub fn disable<T: RccPeripheral>() { 380pub fn disable<T: RccPeripheral>() {
366 T::RCC_INFO.disable(); 381 T::RCC_INFO.disable();
367} 382}
383
384/// Re-initialize the `embassy-stm32` clock configuration with the provided configuration.
385///
386/// This is useful when you need to alter the CPU clock after configuring peripherals.
387/// For instance, configure an external clock via spi or i2c.
388///
389/// Please not this only re-configures the rcc and the time driver (not GPIO, EXTI, etc).
390///
391/// This should only be called after `init`.
392#[cfg(not(feature = "_dual-core"))]
393pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) {
394 critical_section::with(|cs| init_rcc(cs, config))
395}
396
397pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
398 unsafe {
399 init(config);
400
401 // must be after rcc init
402 #[cfg(feature = "_time-driver")]
403 crate::time_driver::init(_cs);
404
405 #[cfg(feature = "low-power")]
406 {
407 REFCOUNT_STOP2 = 0;
408 REFCOUNT_STOP1 = 0;
409 }
410 }
411}
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index d6331f512..97eb2eb6d 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,10 +1,15 @@
1pub use crate::pac::pwr::vals::Vos as VoltageScale; 1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2#[cfg(all(peri_usb_otg_hs))]
3pub use crate::pac::rcc::vals::Otghssel;
2pub use crate::pac::rcc::vals::{ 4pub use crate::pac::rcc::vals::{
3 Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, 5 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, 6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
5}; 7};
6use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; 8use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge};
9#[cfg(all(peri_usb_otg_hs))]
10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
7use crate::pac::{FLASH, PWR, RCC}; 11use crate::pac::{FLASH, PWR, RCC};
12use crate::rcc::LSI_FREQ;
8use crate::time::Hertz; 13use crate::time::Hertz;
9 14
10/// HSI speed 15/// HSI speed
@@ -59,9 +64,11 @@ pub struct Pll {
59 pub divr: Option<PllDiv>, 64 pub divr: Option<PllDiv>,
60} 65}
61 66
67#[derive(Clone, Copy)]
62pub struct Config { 68pub struct Config {
63 // base clock sources 69 // base clock sources
64 pub msi: Option<MSIRange>, 70 pub msis: Option<MSIRange>,
71 pub msik: Option<MSIRange>,
65 pub hsi: bool, 72 pub hsi: bool,
66 pub hse: Option<Hse>, 73 pub hse: Option<Hse>,
67 pub hsi48: Option<super::Hsi48Config>, 74 pub hsi48: Option<super::Hsi48Config>,
@@ -90,13 +97,14 @@ pub struct Config {
90 pub mux: super::mux::ClockMux, 97 pub mux: super::mux::ClockMux,
91} 98}
92 99
93impl Default for Config { 100impl Config {
94 fn default() -> Self { 101 pub const fn new() -> Self {
95 Self { 102 Self {
96 msi: Some(Msirange::RANGE_4MHZ), 103 msis: Some(Msirange::RANGE_4MHZ),
104 msik: Some(Msirange::RANGE_4MHZ),
97 hse: None, 105 hse: None,
98 hsi: false, 106 hsi: false,
99 hsi48: Some(Default::default()), 107 hsi48: Some(crate::rcc::Hsi48Config::new()),
100 pll1: None, 108 pll1: None,
101 pll2: None, 109 pll2: None,
102 pll3: None, 110 pll3: None,
@@ -106,18 +114,24 @@ impl Default for Config {
106 apb2_pre: APBPrescaler::DIV1, 114 apb2_pre: APBPrescaler::DIV1,
107 apb3_pre: APBPrescaler::DIV1, 115 apb3_pre: APBPrescaler::DIV1,
108 voltage_range: VoltageScale::RANGE1, 116 voltage_range: VoltageScale::RANGE1,
109 ls: Default::default(), 117 ls: crate::rcc::LsConfig::new(),
110 mux: Default::default(), 118 mux: super::mux::ClockMux::default(),
111 } 119 }
112 } 120 }
113} 121}
114 122
123impl Default for Config {
124 fn default() -> Self {
125 Self::new()
126 }
127}
128
115pub(crate) unsafe fn init(config: Config) { 129pub(crate) unsafe fn init(config: Config) {
116 // Set the requested power mode 130 // Set the requested power mode
117 PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); 131 PWR.vosr().modify(|w| w.set_vos(config.voltage_range));
118 while !PWR.vosr().read().vosrdy() {} 132 while !PWR.vosr().read().vosrdy() {}
119 133
120 let msi = config.msi.map(|range| { 134 let msis = config.msis.map(|range| {
121 // Check MSI output per RM0456 § 11.4.10 135 // Check MSI output per RM0456 § 11.4.10
122 match config.voltage_range { 136 match config.voltage_range {
123 VoltageScale::RANGE4 => { 137 VoltageScale::RANGE4 => {
@@ -146,8 +160,36 @@ pub(crate) unsafe fn init(config: Config) {
146 msirange_to_hertz(range) 160 msirange_to_hertz(range)
147 }); 161 });
148 162
163 let msik = config.msik.map(|range| {
164 // Check MSI output per RM0456 § 11.4.10
165 match config.voltage_range {
166 VoltageScale::RANGE4 => {
167 assert!(msirange_to_hertz(range).0 <= 24_000_000);
168 }
169 _ => {}
170 }
171
172 // RM0456 § 11.8.2: spin until MSIS is off or MSIS is ready before setting its range
173 loop {
174 let cr = RCC.cr().read();
175 if cr.msikon() == false || cr.msikrdy() == true {
176 break;
177 }
178 }
179
180 RCC.icscr1().modify(|w| {
181 w.set_msikrange(range);
182 w.set_msirgsel(Msirgsel::ICSCR1);
183 });
184 RCC.cr().modify(|w| {
185 w.set_msikon(true);
186 });
187 while !RCC.cr().read().msikrdy() {}
188 msirange_to_hertz(range)
189 });
190
149 let hsi = config.hsi.then(|| { 191 let hsi = config.hsi.then(|| {
150 RCC.cr().write(|w| w.set_hsion(true)); 192 RCC.cr().modify(|w| w.set_hsion(true));
151 while !RCC.cr().read().hsirdy() {} 193 while !RCC.cr().read().hsirdy() {}
152 194
153 HSI_FREQ 195 HSI_FREQ
@@ -165,7 +207,7 @@ pub(crate) unsafe fn init(config: Config) {
165 } 207 }
166 208
167 // Enable HSE, and wait for it to stabilize 209 // Enable HSE, and wait for it to stabilize
168 RCC.cr().write(|w| { 210 RCC.cr().modify(|w| {
169 w.set_hseon(true); 211 w.set_hseon(true);
170 w.set_hsebyp(hse.mode != HseMode::Oscillator); 212 w.set_hsebyp(hse.mode != HseMode::Oscillator);
171 w.set_hseext(match hse.mode { 213 w.set_hseext(match hse.mode {
@@ -180,7 +222,7 @@ pub(crate) unsafe fn init(config: Config) {
180 222
181 let hsi48 = config.hsi48.map(super::init_hsi48); 223 let hsi48 = config.hsi48.map(super::init_hsi48);
182 224
183 let pll_input = PllInput { hse, hsi, msi }; 225 let pll_input = PllInput { hse, hsi, msi: msis };
184 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); 226 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
185 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); 227 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); 228 let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range);
@@ -188,7 +230,7 @@ pub(crate) unsafe fn init(config: Config) {
188 let sys_clk = match config.sys { 230 let sys_clk = match config.sys {
189 Sysclk::HSE => hse.unwrap(), 231 Sysclk::HSE => hse.unwrap(),
190 Sysclk::HSI => hsi.unwrap(), 232 Sysclk::HSI => hsi.unwrap(),
191 Sysclk::MSIS => msi.unwrap(), 233 Sysclk::MSIS => msis.unwrap(),
192 Sysclk::PLL1_R => pll1.r.unwrap(), 234 Sysclk::PLL1_R => pll1.r.unwrap(),
193 }; 235 };
194 236
@@ -263,6 +305,34 @@ pub(crate) unsafe fn init(config: Config) {
263 305
264 let rtc = config.ls.init(); 306 let rtc = config.ls.init();
265 307
308 #[cfg(all(stm32u5, peri_usb_otg_hs))]
309 let usb_refck = match config.mux.otghssel {
310 Otghssel::HSE => hse,
311 Otghssel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8),
312 Otghssel::PLL1_P => pll1.p,
313 Otghssel::PLL1_P_DIV_2 => pll1.p.map(|pll1p_val| pll1p_val / 2u8),
314 };
315 #[cfg(all(stm32u5, peri_usb_otg_hs))]
316 let usb_refck_sel = match usb_refck {
317 Some(clk_val) => match clk_val {
318 Hertz(16_000_000) => Usbrefcksel::MHZ16,
319 Hertz(19_200_000) => Usbrefcksel::MHZ19_2,
320 Hertz(20_000_000) => Usbrefcksel::MHZ20,
321 Hertz(24_000_000) => Usbrefcksel::MHZ24,
322 Hertz(26_000_000) => Usbrefcksel::MHZ26,
323 Hertz(32_000_000) => Usbrefcksel::MHZ32,
324 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val),
325 },
326 None => Usbrefcksel::MHZ24,
327 };
328 #[cfg(all(stm32u5, peri_usb_otg_hs))]
329 SYSCFG.otghsphycr().modify(|w| {
330 w.set_clksel(usb_refck_sel);
331 });
332
333 let lse = config.ls.lse.map(|l| l.frequency);
334 let lsi = config.ls.lsi.then_some(LSI_FREQ);
335
266 config.mux.init(); 336 config.mux.init();
267 337
268 set_clocks!( 338 set_clocks!(
@@ -275,8 +345,11 @@ pub(crate) unsafe fn init(config: Config) {
275 pclk3: Some(pclk3), 345 pclk3: Some(pclk3),
276 pclk1_tim: Some(pclk1_tim), 346 pclk1_tim: Some(pclk1_tim),
277 pclk2_tim: Some(pclk2_tim), 347 pclk2_tim: Some(pclk2_tim),
348 msik: msik,
278 hsi48: hsi48, 349 hsi48: hsi48,
279 rtc: rtc, 350 rtc: rtc,
351 lse: lse,
352 lsi: lsi,
280 hse: hse, 353 hse: hse,
281 hsi: hsi, 354 hsi: hsi,
282 pll1_p: pll1.p, 355 pll1_p: pll1.p,
@@ -294,12 +367,7 @@ pub(crate) unsafe fn init(config: Config) {
294 367
295 // TODO 368 // TODO
296 audioclk: None, 369 audioclk: None,
297 hsi48_div_2: None,
298 lse: None,
299 lsi: None,
300 msik: None,
301 shsi: None, 370 shsi: None,
302 shsi_div_2: None,
303 ); 371 );
304} 372}
305 373
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 8e1779d7c..b9fc4e423 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -15,6 +15,7 @@ pub struct Hse {
15} 15}
16 16
17/// Clocks configuration 17/// Clocks configuration
18#[derive(Clone, Copy)]
18pub struct Config { 19pub struct Config {
19 // base clock sources 20 // base clock sources
20 pub hsi: bool, 21 pub hsi: bool,
@@ -36,9 +37,8 @@ pub struct Config {
36 pub mux: super::mux::ClockMux, 37 pub mux: super::mux::ClockMux,
37} 38}
38 39
39impl Default for Config { 40impl Config {
40 #[inline] 41 pub const fn new() -> Self {
41 fn default() -> Config {
42 Config { 42 Config {
43 hse: None, 43 hse: None,
44 hsi: true, 44 hsi: true,
@@ -47,13 +47,19 @@ impl Default for Config {
47 apb1_pre: APBPrescaler::DIV1, 47 apb1_pre: APBPrescaler::DIV1,
48 apb2_pre: APBPrescaler::DIV1, 48 apb2_pre: APBPrescaler::DIV1,
49 apb7_pre: APBPrescaler::DIV1, 49 apb7_pre: APBPrescaler::DIV1,
50 ls: Default::default(), 50 ls: crate::rcc::LsConfig::new(),
51 voltage_scale: VoltageScale::RANGE2, 51 voltage_scale: VoltageScale::RANGE2,
52 mux: Default::default(), 52 mux: super::mux::ClockMux::default(),
53 } 53 }
54 } 54 }
55} 55}
56 56
57impl Default for Config {
58 fn default() -> Config {
59 Self::new()
60 }
61}
62
57fn hsi_enable() { 63fn hsi_enable() {
58 RCC.cr().modify(|w| w.set_hsion(true)); 64 RCC.cr().modify(|w| w.set_hsion(true));
59 while !RCC.cr().read().hsirdy() {} 65 while !RCC.cr().read().hsirdy() {}
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 6f4c81c8a..312f343b9 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -5,12 +5,11 @@ use core::future::poll_fn;
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use rand_core::{CryptoRng, RngCore};
11 10
12use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac, peripherals, rcc, Peripheral}; 12use crate::{interrupt, pac, peripherals, rcc, Peri};
14 13
15static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 14static RNG_WAKER: AtomicWaker = AtomicWaker::new();
16 15
@@ -43,17 +42,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
43 42
44/// RNG driver. 43/// RNG driver.
45pub struct Rng<'d, T: Instance> { 44pub struct Rng<'d, T: Instance> {
46 _inner: PeripheralRef<'d, T>, 45 _inner: Peri<'d, T>,
47} 46}
48 47
49impl<'d, T: Instance> Rng<'d, T> { 48impl<'d, T: Instance> Rng<'d, T> {
50 /// Create a new RNG driver. 49 /// Create a new RNG driver.
51 pub fn new( 50 pub fn new(
52 inner: impl Peripheral<P = T> + 'd, 51 inner: Peri<'d, T>,
53 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 52 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
54 ) -> Self { 53 ) -> Self {
55 rcc::enable_and_reset::<T>(); 54 rcc::enable_and_reset::<T>();
56 into_ref!(inner);
57 let mut random = Self { _inner: inner }; 55 let mut random = Self { _inner: inner };
58 random.reset(); 56 random.reset();
59 57
@@ -88,10 +86,10 @@ impl<'d, T: Instance> Rng<'d, T> {
88 reg.set_nistc(pac::rng::vals::Nistc::CUSTOM); 86 reg.set_nistc(pac::rng::vals::Nistc::CUSTOM);
89 // set RNG config "A" according to reference manual 87 // set RNG config "A" according to reference manual
90 // this has to be written within the same write access as setting the CONDRST bit 88 // this has to be written within the same write access as setting the CONDRST bit
91 reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIGA); 89 reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIG_A);
92 reg.set_clkdiv(pac::rng::vals::Clkdiv::NODIV); 90 reg.set_clkdiv(pac::rng::vals::Clkdiv::NO_DIV);
93 reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIGA_B); 91 reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIG_A_B);
94 reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIGA); 92 reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIG_A);
95 reg.set_ced(true); 93 reg.set_ced(true);
96 reg.set_ie(false); 94 reg.set_ie(false);
97 reg.set_rngen(true); 95 reg.set_rngen(true);
@@ -185,10 +183,9 @@ impl<'d, T: Instance> Rng<'d, T> {
185 183
186 Ok(()) 184 Ok(())
187 } 185 }
188}
189 186
190impl<'d, T: Instance> RngCore for Rng<'d, T> { 187 /// Get a random u32
191 fn next_u32(&mut self) -> u32 { 188 pub fn next_u32(&mut self) -> u32 {
192 loop { 189 loop {
193 let sr = T::regs().sr().read(); 190 let sr = T::regs().sr().read();
194 if sr.seis() | sr.ceis() { 191 if sr.seis() | sr.ceis() {
@@ -199,13 +196,15 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> {
199 } 196 }
200 } 197 }
201 198
202 fn next_u64(&mut self) -> u64 { 199 /// Get a random u64
200 pub fn next_u64(&mut self) -> u64 {
203 let mut rand = self.next_u32() as u64; 201 let mut rand = self.next_u32() as u64;
204 rand |= (self.next_u32() as u64) << 32; 202 rand |= (self.next_u32() as u64) << 32;
205 rand 203 rand
206 } 204 }
207 205
208 fn fill_bytes(&mut self, dest: &mut [u8]) { 206 /// Fill a slice with random bytes
207 pub fn fill_bytes(&mut self, dest: &mut [u8]) {
209 for chunk in dest.chunks_mut(4) { 208 for chunk in dest.chunks_mut(4) {
210 let rand = self.next_u32(); 209 let rand = self.next_u32();
211 for (slot, num) in chunk.iter_mut().zip(rand.to_ne_bytes().iter()) { 210 for (slot, num) in chunk.iter_mut().zip(rand.to_ne_bytes().iter()) {
@@ -213,14 +212,53 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> {
213 } 212 }
214 } 213 }
215 } 214 }
215}
216
217impl<'d, T: Instance> Drop for Rng<'d, T> {
218 fn drop(&mut self) {
219 T::regs().cr().modify(|reg| {
220 reg.set_rngen(false);
221 });
222 rcc::disable::<T>();
223 }
224}
225
226impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> {
227 fn next_u32(&mut self) -> u32 {
228 self.next_u32()
229 }
230
231 fn next_u64(&mut self) -> u64 {
232 self.next_u64()
233 }
216 234
217 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 235 fn fill_bytes(&mut self, dest: &mut [u8]) {
236 self.fill_bytes(dest);
237 }
238
239 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
218 self.fill_bytes(dest); 240 self.fill_bytes(dest);
219 Ok(()) 241 Ok(())
220 } 242 }
221} 243}
222 244
223impl<'d, T: Instance> CryptoRng for Rng<'d, T> {} 245impl<'d, T: Instance> rand_core_06::CryptoRng for Rng<'d, T> {}
246
247impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> {
248 fn next_u32(&mut self) -> u32 {
249 self.next_u32()
250 }
251
252 fn next_u64(&mut self) -> u64 {
253 self.next_u64()
254 }
255
256 fn fill_bytes(&mut self, dest: &mut [u8]) {
257 self.fill_bytes(dest);
258 }
259}
260
261impl<'d, T: Instance> rand_core_09::CryptoRng for Rng<'d, T> {}
224 262
225trait SealedInstance { 263trait SealedInstance {
226 fn regs() -> pac::rng::Rng; 264 fn regs() -> pac::rng::Rng;
@@ -228,7 +266,7 @@ trait SealedInstance {
228 266
229/// RNG instance trait. 267/// RNG instance trait.
230#[allow(private_bounds)] 268#[allow(private_bounds)]
231pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 269pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send {
232 /// Interrupt for this RNG instance. 270 /// Interrupt for this RNG instance.
233 type Interrupt: interrupt::typelevel::Interrupt; 271 type Interrupt: interrupt::typelevel::Interrupt;
234} 272}
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index 32732e96e..8b420bb6e 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -3,6 +3,7 @@ use chrono::{Datelike, NaiveDate, Timelike, Weekday};
3 3
4/// Errors regarding the [`DateTime`] struct. 4/// Errors regarding the [`DateTime`] struct.
5#[derive(Clone, Debug, PartialEq, Eq)] 5#[derive(Clone, Debug, PartialEq, Eq)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub enum Error { 7pub enum Error {
7 /// The [DateTime] contains an invalid year value. Must be between `0..=4095`. 8 /// The [DateTime] contains an invalid year value. Must be between `0..=4095`.
8 InvalidYear, 9 InvalidYear,
@@ -21,9 +22,12 @@ pub enum Error {
21 InvalidMinute, 22 InvalidMinute,
22 /// The [DateTime] contains an invalid second value. Must be between `0..=59`. 23 /// The [DateTime] contains an invalid second value. Must be between `0..=59`.
23 InvalidSecond, 24 InvalidSecond,
25 /// The [DateTime] contains an invalid microsecond value. Must be between `0..=999_999`.
26 InvalidMicrosecond,
24} 27}
25 28
26/// Structure containing date and time information 29/// Structure containing date and time information
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub struct DateTime { 31pub struct DateTime {
28 /// 0..4095 32 /// 0..4095
29 year: u16, 33 year: u16,
@@ -39,6 +43,8 @@ pub struct DateTime {
39 minute: u8, 43 minute: u8,
40 /// 0..59 44 /// 0..59
41 second: u8, 45 second: u8,
46 /// 0..999_999
47 usecond: u32,
42} 48}
43 49
44impl DateTime { 50impl DateTime {
@@ -77,6 +83,11 @@ impl DateTime {
77 self.second 83 self.second
78 } 84 }
79 85
86 /// Get the microsecond (0..=999_999)
87 pub const fn microsecond(&self) -> u32 {
88 self.usecond
89 }
90
80 /// Create a new DateTime with the given information. 91 /// Create a new DateTime with the given information.
81 pub fn from( 92 pub fn from(
82 year: u16, 93 year: u16,
@@ -86,6 +97,7 @@ impl DateTime {
86 hour: u8, 97 hour: u8,
87 minute: u8, 98 minute: u8,
88 second: u8, 99 second: u8,
100 usecond: u32,
89 ) -> Result<Self, Error> { 101 ) -> Result<Self, Error> {
90 if year > 4095 { 102 if year > 4095 {
91 Err(Error::InvalidYear) 103 Err(Error::InvalidYear)
@@ -99,6 +111,8 @@ impl DateTime {
99 Err(Error::InvalidMinute) 111 Err(Error::InvalidMinute)
100 } else if second > 59 { 112 } else if second > 59 {
101 Err(Error::InvalidSecond) 113 Err(Error::InvalidSecond)
114 } else if usecond > 999_999 {
115 Err(Error::InvalidMicrosecond)
102 } else { 116 } else {
103 Ok(Self { 117 Ok(Self {
104 year, 118 year,
@@ -108,6 +122,7 @@ impl DateTime {
108 hour, 122 hour,
109 minute, 123 minute,
110 second, 124 second,
125 usecond,
111 }) 126 })
112 } 127 }
113 } 128 }
@@ -124,6 +139,7 @@ impl From<chrono::NaiveDateTime> for DateTime {
124 hour: date_time.hour() as u8, 139 hour: date_time.hour() as u8,
125 minute: date_time.minute() as u8, 140 minute: date_time.minute() as u8,
126 second: date_time.second() as u8, 141 second: date_time.second() as u8,
142 usecond: date_time.and_utc().timestamp_subsec_micros(),
127 } 143 }
128 } 144 }
129} 145}
@@ -133,7 +149,12 @@ impl From<DateTime> for chrono::NaiveDateTime {
133 fn from(date_time: DateTime) -> Self { 149 fn from(date_time: DateTime) -> Self {
134 NaiveDate::from_ymd_opt(date_time.year as i32, date_time.month as u32, date_time.day as u32) 150 NaiveDate::from_ymd_opt(date_time.year as i32, date_time.month as u32, date_time.day as u32)
135 .unwrap() 151 .unwrap()
136 .and_hms_opt(date_time.hour as u32, date_time.minute as u32, date_time.second as u32) 152 .and_hms_micro_opt(
153 date_time.hour as u32,
154 date_time.minute as u32,
155 date_time.second as u32,
156 date_time.usecond,
157 )
137 .unwrap() 158 .unwrap()
138 } 159 }
139} 160}
@@ -141,6 +162,7 @@ impl From<DateTime> for chrono::NaiveDateTime {
141/// A day of the week 162/// A day of the week
142#[repr(u8)] 163#[repr(u8)]
143#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] 164#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
165#[cfg_attr(feature = "defmt", derive(defmt::Format))]
144#[allow(missing_docs)] 166#[allow(missing_docs)]
145pub enum DayOfWeek { 167pub enum DayOfWeek {
146 Monday = 1, 168 Monday = 1,
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index b9aaa63b9..cd075f3de 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -65,7 +65,9 @@ pub(crate) enum WakeupPrescaler {
65 Div16 = 16, 65 Div16 = 16,
66} 66}
67 67
68#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] 68#[cfg(any(
69 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0
70))]
69impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 71impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
70 fn from(val: WakeupPrescaler) -> Self { 72 fn from(val: WakeupPrescaler) -> Self {
71 use crate::pac::rtc::vals::Wucksel; 73 use crate::pac::rtc::vals::Wucksel;
@@ -79,7 +81,9 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
79 } 81 }
80} 82}
81 83
82#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] 84#[cfg(any(
85 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0
86))]
83impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 87impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
84 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 88 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
85 use crate::pac::rtc::vals::Wucksel; 89 use crate::pac::rtc::vals::Wucksel;
@@ -219,12 +223,29 @@ impl Rtc {
219 223
220 pub(crate) fn enable_wakeup_line(&self) { 224 pub(crate) fn enable_wakeup_line(&self) {
221 use crate::interrupt::typelevel::Interrupt; 225 use crate::interrupt::typelevel::Interrupt;
222 use crate::pac::EXTI;
223 226
224 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); 227 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
225 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; 228 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
226 229
227 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 230 #[cfg(not(any(stm32u5, stm32u0)))]
228 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 231 {
232 use crate::pac::EXTI;
233 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
234
235 #[cfg(not(stm32wb))]
236 {
237 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
238 }
239 #[cfg(stm32wb)]
240 {
241 EXTI.cpu(0).imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
242 }
243 }
244 #[cfg(stm32u5)]
245 {
246 use crate::pac::RCC;
247 RCC.srdamr().modify(|w| w.set_rtcapbamen(true));
248 RCC.apb3smenr().modify(|w| w.set_rtcapbsmen(true));
249 }
229 } 250 }
230} 251}
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index fe57cfe66..49f423f37 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -25,17 +25,18 @@ use crate::time::Hertz;
25 ), 25 ),
26 path = "v2.rs" 26 path = "v2.rs"
27)] 27)]
28#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")] 28#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs), path = "v3.rs")]
29mod _version; 29mod _version;
30#[allow(unused_imports)] 30#[allow(unused_imports)]
31pub use _version::*; 31pub use _version::*;
32use embassy_hal_internal::Peripheral;
33 32
34use crate::peripherals::RTC; 33use crate::peripherals::RTC;
34use crate::Peri;
35 35
36/// Errors that can occur on methods on [RtcClock] 36/// Errors that can occur on methods on [RtcClock]
37#[non_exhaustive] 37#[non_exhaustive]
38#[derive(Clone, Debug, PartialEq, Eq)] 38#[derive(Clone, Debug, PartialEq, Eq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39pub enum RtcError { 40pub enum RtcError {
40 /// An invalid DateTime was given or stored on the hardware. 41 /// An invalid DateTime was given or stored on the hardware.
41 InvalidDateTime(DateTimeError), 42 InvalidDateTime(DateTimeError),
@@ -59,7 +60,7 @@ impl RtcTimeProvider {
59 /// 60 ///
60 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. 61 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
61 pub fn now(&self) -> Result<DateTime, RtcError> { 62 pub fn now(&self) -> Result<DateTime, RtcError> {
62 self.read(|dr, tr, _| { 63 self.read(|dr, tr, _ss| {
63 let second = bcd2_to_byte((tr.st(), tr.su())); 64 let second = bcd2_to_byte((tr.st(), tr.su()));
64 let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); 65 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
65 let hour = bcd2_to_byte((tr.ht(), tr.hu())); 66 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
@@ -69,7 +70,17 @@ impl RtcTimeProvider {
69 let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); 70 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
70 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16; 71 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16;
71 72
72 DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) 73 // Calculate second fraction and multiply to microseconds
74 // Formula from RM0410
75 #[cfg(not(rtc_v2f2))]
76 let us = {
77 let prediv = RTC::regs().prer().read().prediv_s() as f32;
78 (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32
79 };
80 #[cfg(rtc_v2f2)]
81 let us = 0;
82
83 DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime)
73 }) 84 })
74 } 85 }
75 86
@@ -140,7 +151,7 @@ pub enum RtcCalibrationCyclePeriod {
140 151
141impl Rtc { 152impl Rtc {
142 /// Create a new RTC instance. 153 /// Create a new RTC instance.
143 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { 154 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self {
144 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 155 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
145 crate::rcc::enable_and_reset::<RTC>(); 156 crate::rcc::enable_and_reset::<RTC>();
146 157
@@ -285,6 +296,7 @@ trait SealedInstance {
285 const BACKUP_REGISTER_COUNT: usize; 296 const BACKUP_REGISTER_COUNT: usize;
286 297
287 #[cfg(feature = "low-power")] 298 #[cfg(feature = "low-power")]
299 #[cfg(not(any(stm32u5, stm32u0)))]
288 const EXTI_WAKEUP_LINE: usize; 300 const EXTI_WAKEUP_LINE: usize;
289 301
290 #[cfg(feature = "low-power")] 302 #[cfg(feature = "low-power")]
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index cdc1cb299..28380a3c0 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -77,7 +77,7 @@ impl super::Rtc {
77 // When the offset is positive (0 to 512), the opposite of 77 // When the offset is positive (0 to 512), the opposite of
78 // the offset (512 - offset) is masked, i.e. for the 78 // the offset (512 - offset) is masked, i.e. for the
79 // maximum offset (512), 0 pulses are masked. 79 // maximum offset (512), 0 pulses are masked.
80 w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ); 80 w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASE_FREQ);
81 w.set_calm(512 - clock_drift as u16); 81 w.set_calm(512 - clock_drift as u16);
82 } else { 82 } else {
83 // Minimum (about -510.7) rounds to -511. 83 // Minimum (about -510.7) rounds to -511.
@@ -86,7 +86,7 @@ impl super::Rtc {
86 // When the offset is negative or zero (-511 to 0), 86 // When the offset is negative or zero (-511 to 0),
87 // the absolute offset is masked, i.e. for the minimum 87 // the absolute offset is masked, i.e. for the minimum
88 // offset (-511), 511 pulses are masked. 88 // offset (-511), 511 pulses are masked.
89 w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE); 89 w.set_calp(stm32_metapac::rtc::vals::Calp::NO_CHANGE);
90 w.set_calm((clock_drift * -1.0) as u16); 90 w.set_calm((clock_drift * -1.0) as u16);
91 } 91 }
92 }); 92 });
@@ -131,10 +131,16 @@ impl SealedInstance for crate::peripherals::RTC {
131 #[cfg(all(feature = "low-power", stm32f4))] 131 #[cfg(all(feature = "low-power", stm32f4))]
132 const EXTI_WAKEUP_LINE: usize = 22; 132 const EXTI_WAKEUP_LINE: usize = 22;
133 133
134 #[cfg(all(feature = "low-power", stm32l4))]
135 const EXTI_WAKEUP_LINE: usize = 20;
136
134 #[cfg(all(feature = "low-power", stm32l0))] 137 #[cfg(all(feature = "low-power", stm32l0))]
135 const EXTI_WAKEUP_LINE: usize = 20; 138 const EXTI_WAKEUP_LINE: usize = 20;
136 139
137 #[cfg(all(feature = "low-power", stm32f4))] 140 #[cfg(all(feature = "low-power", stm32wb))]
141 const EXTI_WAKEUP_LINE: usize = 19;
142
143 #[cfg(all(feature = "low-power", any(stm32f4, stm32l4, stm32wb)))]
138 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 144 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
139 145
140 #[cfg(all(feature = "low-power", stm32l0))] 146 #[cfg(all(feature = "low-power", stm32l0))]
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 02fd5272e..39aa6c5cb 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -12,7 +12,7 @@ impl super::Rtc {
12 self.write(true, |rtc| { 12 self.write(true, |rtc| {
13 rtc.cr().modify(|w| { 13 rtc.cr().modify(|w| {
14 w.set_bypshad(true); 14 w.set_bypshad(true);
15 w.set_fmt(Fmt::TWENTYFOURHOUR); 15 w.set_fmt(Fmt::TWENTY_FOUR_HOUR);
16 w.set_osel(Osel::DISABLED); 16 w.set_osel(Osel::DISABLED);
17 w.set_pol(Pol::HIGH); 17 w.set_pol(Pol::HIGH);
18 }); 18 });
@@ -25,7 +25,7 @@ impl super::Rtc {
25 // TODO: configuration for output pins 25 // TODO: configuration for output pins
26 rtc.cr().modify(|w| { 26 rtc.cr().modify(|w| {
27 w.set_out2en(false); 27 w.set_out2en(false);
28 w.set_tampalrm_type(TampalrmType::PUSHPULL); 28 w.set_tampalrm_type(TampalrmType::PUSH_PULL);
29 w.set_tampalrm_pu(false); 29 w.set_tampalrm_pu(false);
30 }); 30 });
31 }); 31 });
@@ -56,10 +56,10 @@ impl super::Rtc {
56 rtc.calr().write(|w| { 56 rtc.calr().write(|w| {
57 match period { 57 match period {
58 RtcCalibrationCyclePeriod::Seconds8 => { 58 RtcCalibrationCyclePeriod::Seconds8 => {
59 w.set_calw8(Calw8::EIGHTSECONDS); 59 w.set_calw8(Calw8::EIGHT_SECONDS);
60 } 60 }
61 RtcCalibrationCyclePeriod::Seconds16 => { 61 RtcCalibrationCyclePeriod::Seconds16 => {
62 w.set_calw16(Calw16::SIXTEENSECONDS); 62 w.set_calw16(Calw16::SIXTEEN_SECONDS);
63 } 63 }
64 RtcCalibrationCyclePeriod::Seconds32 => { 64 RtcCalibrationCyclePeriod::Seconds32 => {
65 // Set neither `calw8` nor `calw16` to use 32 seconds 65 // Set neither `calw8` nor `calw16` to use 32 seconds
@@ -79,7 +79,7 @@ impl super::Rtc {
79 // When the offset is positive (0 to 512), the opposite of 79 // When the offset is positive (0 to 512), the opposite of
80 // the offset (512 - offset) is masked, i.e. for the 80 // the offset (512 - offset) is masked, i.e. for the
81 // maximum offset (512), 0 pulses are masked. 81 // maximum offset (512), 0 pulses are masked.
82 w.set_calp(Calp::INCREASEFREQ); 82 w.set_calp(Calp::INCREASE_FREQ);
83 w.set_calm(512 - clock_drift as u16); 83 w.set_calm(512 - clock_drift as u16);
84 } else { 84 } else {
85 // Minimum (about -510.7) rounds to -511. 85 // Minimum (about -510.7) rounds to -511.
@@ -88,7 +88,7 @@ impl super::Rtc {
88 // When the offset is negative or zero (-511 to 0), 88 // When the offset is negative or zero (-511 to 0),
89 // the absolute offset is masked, i.e. for the minimum 89 // the absolute offset is masked, i.e. for the minimum
90 // offset (-511), 511 pulses are masked. 90 // offset (-511), 511 pulses are masked.
91 w.set_calp(Calp::NOCHANGE); 91 w.set_calp(Calp::NO_CHANGE);
92 w.set_calm((clock_drift * -1.0) as u16); 92 w.set_calm((clock_drift * -1.0) as u16);
93 } 93 }
94 }); 94 });
@@ -133,12 +133,20 @@ impl SealedInstance for crate::peripherals::RTC {
133 cfg_if::cfg_if!( 133 cfg_if::cfg_if!(
134 if #[cfg(stm32g4)] { 134 if #[cfg(stm32g4)] {
135 const EXTI_WAKEUP_LINE: usize = 20; 135 const EXTI_WAKEUP_LINE: usize = 20;
136 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
137 } else if #[cfg(stm32g0)] { 136 } else if #[cfg(stm32g0)] {
138 const EXTI_WAKEUP_LINE: usize = 19; 137 const EXTI_WAKEUP_LINE: usize = 19;
139 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
140 } else if #[cfg(any(stm32l5, stm32h5))] { 138 } else if #[cfg(any(stm32l5, stm32h5))] {
141 const EXTI_WAKEUP_LINE: usize = 17; 139 const EXTI_WAKEUP_LINE: usize = 17;
140 }
141 );
142
143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!(
145 if #[cfg(stm32g4)] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
149 } else if #[cfg(any(stm32l5, stm32h5, stm32u5))] {
142 type WakeupInterrupt = crate::interrupt::typelevel::RTC; 150 type WakeupInterrupt = crate::interrupt::typelevel::RTC;
143 } 151 }
144 ); 152 );
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index c48d81b5f..0c9c27797 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -4,7 +4,7 @@
4 4
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6 6
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::PeripheralType;
8 8
9pub use crate::dma::word; 9pub use crate::dma::word;
10#[cfg(not(gpdma))] 10#[cfg(not(gpdma))]
@@ -12,7 +12,7 @@ use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptio
12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
13use crate::pac::sai::{vals, Sai as Regs}; 13use crate::pac::sai::{vals, Sai as Regs};
14use crate::rcc::{self, RccPeripheral}; 14use crate::rcc::{self, RccPeripheral};
15use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peri};
16 16
17/// SAI error 17/// SAI error
18#[derive(Debug, PartialEq, Eq, Clone, Copy)] 18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -27,8 +27,14 @@ pub enum Error {
27} 27}
28 28
29#[cfg(not(gpdma))] 29#[cfg(not(gpdma))]
30impl From<ringbuffer::OverrunError> for Error { 30impl From<ringbuffer::Error> for Error {
31 fn from(_: ringbuffer::OverrunError) -> Self { 31 fn from(#[allow(unused)] err: ringbuffer::Error) -> Self {
32 #[cfg(feature = "defmt")]
33 {
34 if err == ringbuffer::Error::DmaUnsynced {
35 defmt::error!("Ringbuffer broken invariants detected!");
36 }
37 }
32 Self::Overrun 38 Self::Overrun
33 } 39 }
34} 40}
@@ -46,12 +52,12 @@ impl Mode {
46 const fn mode(&self, tx_rx: TxRx) -> vals::Mode { 52 const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
47 match tx_rx { 53 match tx_rx {
48 TxRx::Transmitter => match self { 54 TxRx::Transmitter => match self {
49 Mode::Master => vals::Mode::MASTERTX, 55 Mode::Master => vals::Mode::MASTER_TX,
50 Mode::Slave => vals::Mode::SLAVETX, 56 Mode::Slave => vals::Mode::SLAVE_TX,
51 }, 57 },
52 TxRx::Receiver => match self { 58 TxRx::Receiver => match self {
53 Mode::Master => vals::Mode::MASTERRX, 59 Mode::Master => vals::Mode::MASTER_RX,
54 Mode::Slave => vals::Mode::SLAVERX, 60 Mode::Slave => vals::Mode::SLAVE_RX,
55 }, 61 },
56 } 62 }
57 } 63 }
@@ -80,7 +86,7 @@ impl SlotSize {
80 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 86 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
81 const fn slotsz(&self) -> vals::Slotsz { 87 const fn slotsz(&self) -> vals::Slotsz {
82 match self { 88 match self {
83 SlotSize::DataSize => vals::Slotsz::DATASIZE, 89 SlotSize::DataSize => vals::Slotsz::DATA_SIZE,
84 SlotSize::Channel16 => vals::Slotsz::BIT16, 90 SlotSize::Channel16 => vals::Slotsz::BIT16,
85 SlotSize::Channel32 => vals::Slotsz::BIT32, 91 SlotSize::Channel32 => vals::Slotsz::BIT32,
86 } 92 }
@@ -149,8 +155,8 @@ impl MuteValue {
149 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 155 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
150 const fn muteval(&self) -> vals::Muteval { 156 const fn muteval(&self) -> vals::Muteval {
151 match self { 157 match self {
152 MuteValue::Zero => vals::Muteval::SENDZERO, 158 MuteValue::Zero => vals::Muteval::SEND_ZERO,
153 MuteValue::LastValue => vals::Muteval::SENDLAST, 159 MuteValue::LastValue => vals::Muteval::SEND_LAST,
154 } 160 }
155 } 161 }
156} 162}
@@ -184,7 +190,7 @@ pub enum SyncInput {
184 /// Syncs with the other A/B sub-block within the SAI unit 190 /// Syncs with the other A/B sub-block within the SAI unit
185 Internal, 191 Internal,
186 /// Syncs with a sub-block in the other SAI unit 192 /// Syncs with a sub-block in the other SAI unit
187 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] 193 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
188 External(SyncInputInstance), 194 External(SyncInputInstance),
189} 195}
190 196
@@ -193,14 +199,14 @@ impl SyncInput {
193 match self { 199 match self {
194 SyncInput::None => vals::Syncen::ASYNCHRONOUS, 200 SyncInput::None => vals::Syncen::ASYNCHRONOUS,
195 SyncInput::Internal => vals::Syncen::INTERNAL, 201 SyncInput::Internal => vals::Syncen::INTERNAL,
196 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] 202 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
197 SyncInput::External(_) => vals::Syncen::EXTERNAL, 203 SyncInput::External(_) => vals::Syncen::EXTERNAL,
198 } 204 }
199 } 205 }
200} 206}
201 207
202/// SAI instance to sync from. 208/// SAI instance to sync from.
203#[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] 209#[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
204#[derive(Copy, Clone, PartialEq)] 210#[derive(Copy, Clone, PartialEq)]
205#[allow(missing_docs)] 211#[allow(missing_docs)]
206pub enum SyncInputInstance { 212pub enum SyncInputInstance {
@@ -245,8 +251,8 @@ impl BitOrder {
245 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 251 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
246 const fn lsbfirst(&self) -> vals::Lsbfirst { 252 const fn lsbfirst(&self) -> vals::Lsbfirst {
247 match self { 253 match self {
248 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, 254 BitOrder::LsbFirst => vals::Lsbfirst::LSB_FIRST,
249 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, 255 BitOrder::MsbFirst => vals::Lsbfirst::MSB_FIRST,
250 } 256 }
251 } 257 }
252} 258}
@@ -264,8 +270,8 @@ impl FrameSyncOffset {
264 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 270 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
265 const fn fsoff(&self) -> vals::Fsoff { 271 const fn fsoff(&self) -> vals::Fsoff {
266 match self { 272 match self {
267 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, 273 FrameSyncOffset::OnFirstBit => vals::Fsoff::ON_FIRST,
268 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, 274 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFORE_FIRST,
269 } 275 }
270 } 276 }
271} 277}
@@ -283,8 +289,8 @@ impl FrameSyncPolarity {
283 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 289 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
284 const fn fspol(&self) -> vals::Fspol { 290 const fn fspol(&self) -> vals::Fspol {
285 match self { 291 match self {
286 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, 292 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLING_EDGE,
287 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, 293 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISING_EDGE,
288 } 294 }
289 } 295 }
290} 296}
@@ -319,8 +325,8 @@ impl ClockStrobe {
319 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 325 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
320 const fn ckstr(&self) -> vals::Ckstr { 326 const fn ckstr(&self) -> vals::Ckstr {
321 match self { 327 match self {
322 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, 328 ClockStrobe::Falling => vals::Ckstr::FALLING_EDGE,
323 ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, 329 ClockStrobe::Rising => vals::Ckstr::RISING_EDGE,
324 } 330 }
325 } 331 }
326} 332}
@@ -337,8 +343,8 @@ impl ComplementFormat {
337 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 343 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
338 const fn cpl(&self) -> vals::Cpl { 344 const fn cpl(&self) -> vals::Cpl {
339 match self { 345 match self {
340 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, 346 ComplementFormat::OnesComplement => vals::Cpl::ONES_COMPLEMENT,
341 ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, 347 ComplementFormat::TwosComplement => vals::Cpl::TWOS_COMPLEMENT,
342 } 348 }
343 } 349 }
344} 350}
@@ -356,8 +362,8 @@ impl Companding {
356 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 362 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
357 const fn comp(&self) -> vals::Comp { 363 const fn comp(&self) -> vals::Comp {
358 match self { 364 match self {
359 Companding::None => vals::Comp::NOCOMPANDING, 365 Companding::None => vals::Comp::NO_COMPANDING,
360 Companding::MuLaw => vals::Comp::MULAW, 366 Companding::MuLaw => vals::Comp::MU_LAW,
361 Companding::ALaw => vals::Comp::ALAW, 367 Companding::ALaw => vals::Comp::ALAW,
362 } 368 }
363 } 369 }
@@ -375,7 +381,7 @@ impl OutputDrive {
375 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 381 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
376 const fn outdriv(&self) -> vals::Outdriv { 382 const fn outdriv(&self) -> vals::Outdriv {
377 match self { 383 match self {
378 OutputDrive::OnStart => vals::Outdriv::ONSTART, 384 OutputDrive::OnStart => vals::Outdriv::ON_START,
379 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, 385 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY,
380 } 386 }
381 } 387 }
@@ -661,19 +667,19 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AfType, AfType) {
661 //sd is defined by tx/rx mode 667 //sd is defined by tx/rx mode
662 match tx_rx { 668 match tx_rx {
663 TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh), 669 TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh),
664 TxRx::Receiver => AfType::input(Pull::None), 670 TxRx::Receiver => AfType::input(Pull::Down), // Ensure mute level when no input is connected.
665 }, 671 },
666 //clocks (mclk, sck and fs) are defined by master/slave 672 //clocks (mclk, sck and fs) are defined by master/slave
667 match mode { 673 match mode {
668 Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh), 674 Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh),
669 Mode::Slave => AfType::input(Pull::None), 675 Mode::Slave => AfType::input(Pull::Down), // Ensure no clocks when no input is connected.
670 }, 676 },
671 ) 677 )
672} 678}
673 679
674#[cfg(not(gpdma))] 680#[cfg(not(gpdma))]
675fn get_ring_buffer<'d, T: Instance, W: word::Word>( 681fn get_ring_buffer<'d, T: Instance, W: word::Word>(
676 dma: impl Peripheral<P = impl Channel> + 'd, 682 dma: Peri<'d, impl Channel>,
677 dma_buf: &'d mut [W], 683 dma_buf: &'d mut [W],
678 request: Request, 684 request: Request,
679 sub_block: WhichSubBlock, 685 sub_block: WhichSubBlock,
@@ -698,12 +704,12 @@ fn update_synchronous_config(config: &mut Config) {
698 config.mode = Mode::Slave; 704 config.mode = Mode::Slave;
699 config.sync_output = false; 705 config.sync_output = false;
700 706
701 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm))] 707 #[cfg(any(sai_v1, sai_v2))]
702 { 708 {
703 config.sync_input = SyncInput::Internal; 709 config.sync_input = SyncInput::Internal;
704 } 710 }
705 711
706 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] 712 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
707 { 713 {
708 //this must either be Internal or External 714 //this must either be Internal or External
709 //The asynchronous sub-block on the same SAI needs to enable sync_output 715 //The asynchronous sub-block on the same SAI needs to enable sync_output
@@ -712,16 +718,15 @@ fn update_synchronous_config(config: &mut Config) {
712} 718}
713 719
714/// SAI subblock instance. 720/// SAI subblock instance.
715pub struct SubBlock<'d, T, S: SubBlockInstance> { 721pub struct SubBlock<'d, T: Instance, S: SubBlockInstance> {
716 peri: PeripheralRef<'d, T>, 722 peri: Peri<'d, T>,
717 _phantom: PhantomData<S>, 723 _phantom: PhantomData<S>,
718} 724}
719 725
720/// Split the main SAIx peripheral into the two subblocks. 726/// Split the main SAIx peripheral into the two subblocks.
721/// 727///
722/// You can then create a [`Sai`] driver for each each half. 728/// You can then create a [`Sai`] driver for each each half.
723pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { 729pub fn split_subblocks<'d, T: Instance>(peri: Peri<'d, T>) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
724 into_ref!(peri);
725 rcc::enable_and_reset::<T>(); 730 rcc::enable_and_reset::<T>();
726 731
727 ( 732 (
@@ -738,11 +743,11 @@ pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (S
738 743
739/// SAI sub-block driver. 744/// SAI sub-block driver.
740pub struct Sai<'d, T: Instance, W: word::Word> { 745pub struct Sai<'d, T: Instance, W: word::Word> {
741 _peri: PeripheralRef<'d, T>, 746 _peri: Peri<'d, T>,
742 sd: Option<PeripheralRef<'d, AnyPin>>, 747 sd: Option<Peri<'d, AnyPin>>,
743 fs: Option<PeripheralRef<'d, AnyPin>>, 748 fs: Option<Peri<'d, AnyPin>>,
744 sck: Option<PeripheralRef<'d, AnyPin>>, 749 sck: Option<Peri<'d, AnyPin>>,
745 mclk: Option<PeripheralRef<'d, AnyPin>>, 750 mclk: Option<Peri<'d, AnyPin>>,
746 #[cfg(gpdma)] 751 #[cfg(gpdma)]
747 ring_buffer: PhantomData<W>, 752 ring_buffer: PhantomData<W>,
748 #[cfg(not(gpdma))] 753 #[cfg(not(gpdma))]
@@ -757,16 +762,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
757 /// You can obtain the [`SubBlock`] with [`split_subblocks`]. 762 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
758 pub fn new_asynchronous_with_mclk<S: SubBlockInstance>( 763 pub fn new_asynchronous_with_mclk<S: SubBlockInstance>(
759 peri: SubBlock<'d, T, S>, 764 peri: SubBlock<'d, T, S>,
760 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd, 765 sck: Peri<'d, impl SckPin<T, S>>,
761 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, 766 sd: Peri<'d, impl SdPin<T, S>>,
762 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, 767 fs: Peri<'d, impl FsPin<T, S>>,
763 mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd, 768 mclk: Peri<'d, impl MclkPin<T, S>>,
764 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd, 769 dma: Peri<'d, impl Channel + Dma<T, S>>,
765 dma_buf: &'d mut [W], 770 dma_buf: &'d mut [W],
766 mut config: Config, 771 mut config: Config,
767 ) -> Self { 772 ) -> Self {
768 into_ref!(mclk);
769
770 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); 773 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
771 mclk.set_as_af(mclk.af_num(), ck_af_type); 774 mclk.set_as_af(mclk.af_num(), ck_af_type);
772 775
@@ -782,15 +785,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
782 /// You can obtain the [`SubBlock`] with [`split_subblocks`]. 785 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
783 pub fn new_asynchronous<S: SubBlockInstance>( 786 pub fn new_asynchronous<S: SubBlockInstance>(
784 peri: SubBlock<'d, T, S>, 787 peri: SubBlock<'d, T, S>,
785 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd, 788 sck: Peri<'d, impl SckPin<T, S>>,
786 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, 789 sd: Peri<'d, impl SdPin<T, S>>,
787 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, 790 fs: Peri<'d, impl FsPin<T, S>>,
788 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd, 791 dma: Peri<'d, impl Channel + Dma<T, S>>,
789 dma_buf: &'d mut [W], 792 dma_buf: &'d mut [W],
790 config: Config, 793 config: Config,
791 ) -> Self { 794 ) -> Self {
792 let peri = peri.peri; 795 let peri = peri.peri;
793 into_ref!(peri, dma, sck, sd, fs);
794 796
795 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); 797 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
796 sd.set_as_af(sd.af_num(), sd_af_type); 798 sd.set_as_af(sd.af_num(), sd_af_type);
@@ -803,10 +805,10 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
803 Self::new_inner( 805 Self::new_inner(
804 peri, 806 peri,
805 sub_block, 807 sub_block,
806 Some(sck.map_into()), 808 Some(sck.into()),
807 None, 809 None,
808 Some(sd.map_into()), 810 Some(sd.into()),
809 Some(fs.map_into()), 811 Some(fs.into()),
810 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx), 812 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
811 config, 813 config,
812 ) 814 )
@@ -817,15 +819,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
817 /// You can obtain the [`SubBlock`] with [`split_subblocks`]. 819 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
818 pub fn new_synchronous<S: SubBlockInstance>( 820 pub fn new_synchronous<S: SubBlockInstance>(
819 peri: SubBlock<'d, T, S>, 821 peri: SubBlock<'d, T, S>,
820 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, 822 sd: Peri<'d, impl SdPin<T, S>>,
821 dma: impl Peripheral<P = impl Channel + Dma<T, S>> + 'd, 823 dma: Peri<'d, impl Channel + Dma<T, S>>,
822 dma_buf: &'d mut [W], 824 dma_buf: &'d mut [W],
823 mut config: Config, 825 mut config: Config,
824 ) -> Self { 826 ) -> Self {
825 update_synchronous_config(&mut config); 827 update_synchronous_config(&mut config);
826 828
827 let peri = peri.peri; 829 let peri = peri.peri;
828 into_ref!(dma, peri, sd);
829 830
830 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); 831 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
831 sd.set_as_af(sd.af_num(), sd_af_type); 832 sd.set_as_af(sd.af_num(), sd_af_type);
@@ -838,7 +839,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
838 sub_block, 839 sub_block,
839 None, 840 None,
840 None, 841 None,
841 Some(sd.map_into()), 842 Some(sd.into()),
842 None, 843 None,
843 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx), 844 get_ring_buffer::<T, W>(dma, dma_buf, request, sub_block, config.tx_rx),
844 config, 845 config,
@@ -846,22 +847,25 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
846 } 847 }
847 848
848 fn new_inner( 849 fn new_inner(
849 peri: impl Peripheral<P = T> + 'd, 850 peri: Peri<'d, T>,
850 sub_block: WhichSubBlock, 851 sub_block: WhichSubBlock,
851 sck: Option<PeripheralRef<'d, AnyPin>>, 852 sck: Option<Peri<'d, AnyPin>>,
852 mclk: Option<PeripheralRef<'d, AnyPin>>, 853 mclk: Option<Peri<'d, AnyPin>>,
853 sd: Option<PeripheralRef<'d, AnyPin>>, 854 sd: Option<Peri<'d, AnyPin>>,
854 fs: Option<PeripheralRef<'d, AnyPin>>, 855 fs: Option<Peri<'d, AnyPin>>,
855 ring_buffer: RingBuffer<'d, W>, 856 ring_buffer: RingBuffer<'d, W>,
856 config: Config, 857 config: Config,
857 ) -> Self { 858 ) -> Self {
859 let ch = T::REGS.ch(sub_block as usize);
860
858 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 861 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
859 { 862 {
860 let ch = T::REGS.ch(sub_block as usize);
861 ch.cr1().modify(|w| w.set_saien(false)); 863 ch.cr1().modify(|w| w.set_saien(false));
862 } 864 }
863 865
864 #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] 866 ch.cr2().modify(|w| w.set_fflush(true));
867
868 #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
865 { 869 {
866 if let SyncInput::External(i) = config.sync_input { 870 if let SyncInput::External(i) = config.sync_input {
867 T::REGS.gcr().modify(|w| { 871 T::REGS.gcr().modify(|w| {
@@ -882,7 +886,6 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
882 886
883 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] 887 #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))]
884 { 888 {
885 let ch = T::REGS.ch(sub_block as usize);
886 ch.cr1().modify(|w| { 889 ch.cr1().modify(|w| {
887 w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) { 890 w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) {
888 TxRx::Transmitter 891 TxRx::Transmitter
@@ -899,9 +902,9 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
899 w.set_mckdiv(config.master_clock_divider.mckdiv()); 902 w.set_mckdiv(config.master_clock_divider.mckdiv());
900 w.set_nodiv( 903 w.set_nodiv(
901 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { 904 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
902 vals::Nodiv::NODIV 905 vals::Nodiv::NO_DIV
903 } else { 906 } else {
904 vals::Nodiv::MASTERCLOCK 907 vals::Nodiv::MASTER_CLOCK
905 }, 908 },
906 ); 909 );
907 w.set_dmaen(true); 910 w.set_dmaen(true);
@@ -928,7 +931,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
928 w.set_nbslot(config.slot_count.0 as u8 - 1); 931 w.set_nbslot(config.slot_count.0 as u8 - 1);
929 w.set_slotsz(config.slot_size.slotsz()); 932 w.set_slotsz(config.slot_size.slotsz());
930 w.set_fboff(config.first_bit_offset.0 as u8); 933 w.set_fboff(config.first_bit_offset.0 as u8);
931 w.set_sloten(vals::Sloten(config.slot_enable as u16)); 934 w.set_sloten(vals::Sloten::from_bits(config.slot_enable as u16));
932 }); 935 });
933 936
934 ch.cr1().modify(|w| w.set_saien(true)); 937 ch.cr1().modify(|w| w.set_saien(true));
@@ -939,7 +942,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
939 } 942 }
940 943
941 Self { 944 Self {
942 _peri: peri.into_ref(), 945 _peri: peri,
943 sub_block, 946 sub_block,
944 sck, 947 sck,
945 mclk, 948 mclk,
@@ -950,13 +953,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
950 } 953 }
951 954
952 /// Start the SAI driver. 955 /// Start the SAI driver.
953 pub fn start(&mut self) { 956 ///
957 /// Only receivers can be started. Transmitters are started on the first writing operation.
958 pub fn start(&mut self) -> Result<(), Error> {
954 match self.ring_buffer { 959 match self.ring_buffer {
955 RingBuffer::Writable(ref mut rb) => { 960 RingBuffer::Writable(_) => Err(Error::NotAReceiver),
956 rb.start();
957 }
958 RingBuffer::Readable(ref mut rb) => { 961 RingBuffer::Readable(ref mut rb) => {
959 rb.start(); 962 rb.start();
963 Ok(())
960 } 964 }
961 } 965 }
962 } 966 }
@@ -973,22 +977,48 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
973 rcc::enable_and_reset::<T>(); 977 rcc::enable_and_reset::<T>();
974 } 978 }
975 979
976 /// Flush.
977 pub fn flush(&mut self) {
978 let ch = T::REGS.ch(self.sub_block as usize);
979 ch.cr1().modify(|w| w.set_saien(false));
980 ch.cr2().modify(|w| w.set_fflush(true));
981 ch.cr1().modify(|w| w.set_saien(true));
982 }
983
984 /// Enable or disable mute. 980 /// Enable or disable mute.
985 pub fn set_mute(&mut self, value: bool) { 981 pub fn set_mute(&mut self, value: bool) {
986 let ch = T::REGS.ch(self.sub_block as usize); 982 let ch = T::REGS.ch(self.sub_block as usize);
987 ch.cr2().modify(|w| w.set_mute(value)); 983 ch.cr2().modify(|w| w.set_mute(value));
988 } 984 }
989 985
986 /// Determine the mute state of the receiver.
987 ///
988 /// Clears the mute state flag in the status register.
989 pub fn is_muted(&self) -> Result<bool, Error> {
990 match &self.ring_buffer {
991 RingBuffer::Readable(_) => {
992 let ch = T::REGS.ch(self.sub_block as usize);
993 let mute_state = ch.sr().read().mutedet();
994 ch.clrfr().write(|w| w.set_cmutedet(true));
995 Ok(mute_state)
996 }
997 _ => Err(Error::NotAReceiver),
998 }
999 }
1000
1001 /// Wait until any SAI write error occurs.
1002 ///
1003 /// One useful application for this is stopping playback as soon as the SAI
1004 /// experiences an overrun of the ring buffer. Then, instead of letting
1005 /// the SAI peripheral play the last written buffer over and over again, SAI
1006 /// can be muted or dropped instead.
1007 pub async fn wait_write_error(&mut self) -> Result<(), Error> {
1008 match &mut self.ring_buffer {
1009 RingBuffer::Writable(buffer) => {
1010 buffer.wait_write_error().await?;
1011 Ok(())
1012 }
1013 _ => return Err(Error::NotATransmitter),
1014 }
1015 }
1016
990 /// Write data to the SAI ringbuffer. 1017 /// Write data to the SAI ringbuffer.
991 /// 1018 ///
1019 /// The first write starts the DMA after filling the ring buffer with the provided data.
1020 /// This ensures that the DMA does not run before data is available in the ring buffer.
1021 ///
992 /// This appends the data to the buffer and returns immediately. The 1022 /// This appends the data to the buffer and returns immediately. The
993 /// data will be transmitted in the background. 1023 /// data will be transmitted in the background.
994 /// 1024 ///
@@ -996,7 +1026,12 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
996 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { 1026 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
997 match &mut self.ring_buffer { 1027 match &mut self.ring_buffer {
998 RingBuffer::Writable(buffer) => { 1028 RingBuffer::Writable(buffer) => {
999 buffer.write_exact(data).await?; 1029 if buffer.is_running() {
1030 buffer.write_exact(data).await?;
1031 } else {
1032 buffer.write_immediate(data)?;
1033 buffer.start();
1034 }
1000 Ok(()) 1035 Ok(())
1001 } 1036 }
1002 _ => return Err(Error::NotATransmitter), 1037 _ => return Err(Error::NotATransmitter),
@@ -1024,6 +1059,7 @@ impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> {
1024 fn drop(&mut self) { 1059 fn drop(&mut self) {
1025 let ch = T::REGS.ch(self.sub_block as usize); 1060 let ch = T::REGS.ch(self.sub_block as usize);
1026 ch.cr1().modify(|w| w.set_saien(false)); 1061 ch.cr1().modify(|w| w.set_saien(false));
1062 ch.cr2().modify(|w| w.set_fflush(true));
1027 self.fs.as_ref().map(|x| x.set_as_disconnected()); 1063 self.fs.as_ref().map(|x| x.set_as_disconnected());
1028 self.sd.as_ref().map(|x| x.set_as_disconnected()); 1064 self.sd.as_ref().map(|x| x.set_as_disconnected());
1029 self.sck.as_ref().map(|x| x.set_as_disconnected()); 1065 self.sck.as_ref().map(|x| x.set_as_disconnected());
@@ -1065,7 +1101,7 @@ impl SubBlockInstance for B {}
1065 1101
1066/// SAI instance trait. 1102/// SAI instance trait.
1067#[allow(private_bounds)] 1103#[allow(private_bounds)]
1068pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} 1104pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {}
1069 1105
1070pin_trait!(SckPin, Instance, SubBlockInstance); 1106pin_trait!(SckPin, Instance, SubBlockInstance);
1071pin_trait!(FsPin, Instance, SubBlockInstance); 1107pin_trait!(FsPin, Instance, SubBlockInstance);
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 44ff9fcd5..6a02aae70 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -8,11 +8,15 @@ use core::ops::{Deref, DerefMut};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_hal_internal::drop::OnDrop; 10use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::{Peri, PeripheralType};
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
13use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; 13use sdio_host::common_cmd::{self, Resp, ResponseLen};
14use sdio_host::emmc::{ExtCSD, EMMC};
15use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD};
16use sdio_host::{emmc_cmd, sd_cmd, Cmd};
14 17
15use crate::dma::NoDma; 18#[cfg(sdmmc_v1)]
19use crate::dma::ChannelAndRequest;
16#[cfg(gpio_v2)] 20#[cfg(gpio_v2)]
17use crate::gpio::Pull; 21use crate::gpio::Pull;
18use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 22use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
@@ -20,7 +24,7 @@ use crate::interrupt::typelevel::Interrupt;
20use crate::pac::sdmmc::Sdmmc as RegBlock; 24use crate::pac::sdmmc::Sdmmc as RegBlock;
21use crate::rcc::{self, RccPeripheral}; 25use crate::rcc::{self, RccPeripheral};
22use crate::time::Hertz; 26use crate::time::Hertz;
23use crate::{interrupt, peripherals, Peripheral}; 27use crate::{interrupt, peripherals};
24 28
25/// Interrupt handler. 29/// Interrupt handler.
26pub struct InterruptHandler<T: Instance> { 30pub struct InterruptHandler<T: Instance> {
@@ -135,51 +139,59 @@ pub enum Error {
135 UnsupportedCardVersion, 139 UnsupportedCardVersion,
136 /// Unsupported card type. 140 /// Unsupported card type.
137 UnsupportedCardType, 141 UnsupportedCardType,
142 /// Unsupported voltage.
143 UnsupportedVoltage,
138 /// CRC error. 144 /// CRC error.
139 Crc, 145 Crc,
140 /// No card inserted. 146 /// No card inserted.
141 NoCard, 147 NoCard,
148 /// 8-lane buses are not supported for SD cards.
149 BusWidth,
142 /// Bad clock supplied to the SDMMC peripheral. 150 /// Bad clock supplied to the SDMMC peripheral.
143 BadClock, 151 BadClock,
144 /// Signaling switch failed. 152 /// Signaling switch failed.
145 SignalingSwitchFailed, 153 SignalingSwitchFailed,
154 /// Underrun error
155 Underrun,
146 /// ST bit error. 156 /// ST bit error.
147 #[cfg(sdmmc_v1)] 157 #[cfg(sdmmc_v1)]
148 StBitErr, 158 StBitErr,
149} 159}
150 160
151/// A SD command
152struct Cmd {
153 cmd: u8,
154 arg: u32,
155 resp: Response,
156}
157
158#[derive(Clone, Copy, Debug, Default)] 161#[derive(Clone, Copy, Debug, Default)]
159/// SD Card 162/// SD Card
160pub struct Card { 163pub struct Card {
161 /// The type of this card 164 /// The type of this card
162 pub card_type: CardCapacity, 165 pub card_type: CardCapacity,
163 /// Operation Conditions Register 166 /// Operation Conditions Register
164 pub ocr: OCR, 167 pub ocr: OCR<SD>,
165 /// Relative Card Address 168 /// Relative Card Address
166 pub rca: u32, 169 pub rca: u16,
167 /// Card ID 170 /// Card ID
168 pub cid: CID, 171 pub cid: CID<SD>,
169 /// Card Specific Data 172 /// Card Specific Data
170 pub csd: CSD, 173 pub csd: CSD<SD>,
171 /// SD CARD Configuration Register 174 /// SD CARD Configuration Register
172 pub scr: SCR, 175 pub scr: SCR,
173 /// SD Status 176 /// SD Status
174 pub status: SDStatus, 177 pub status: SDStatus,
175} 178}
176 179
177impl Card { 180#[derive(Clone, Copy, Debug, Default)]
178 /// Size in bytes 181/// eMMC storage
179 pub fn size(&self) -> u64 { 182pub struct Emmc {
180 // SDHC / SDXC / SDUC 183 /// The capacity of this card
181 u64::from(self.csd.block_count()) * 512 184 pub capacity: CardCapacity,
182 } 185 /// Operation Conditions Register
186 pub ocr: OCR<EMMC>,
187 /// Relative Card Address
188 pub rca: u16,
189 /// Card ID
190 pub cid: CID<EMMC>,
191 /// Card Specific Data
192 pub csd: CSD<EMMC>,
193 /// Extended Card Specific Data
194 pub ext_csd: ExtCSD,
183} 195}
184 196
185#[repr(u8)] 197#[repr(u8)]
@@ -188,22 +200,12 @@ enum PowerCtrl {
188 On = 0b11, 200 On = 0b11,
189} 201}
190 202
191#[repr(u32)] 203fn get_waitresp_val(rlen: ResponseLen) -> u8 {
192#[allow(dead_code)] 204 match rlen {
193#[allow(non_camel_case_types)] 205 common_cmd::ResponseLen::Zero => 0,
194enum CmdAppOper { 206 common_cmd::ResponseLen::R48 => 1,
195 VOLTAGE_WINDOW_SD = 0x8010_0000, 207 common_cmd::ResponseLen::R136 => 3,
196 HIGH_CAPACITY = 0x4000_0000, 208 }
197 SDMMC_STD_CAPACITY = 0x0000_0000,
198 SDMMC_CHECK_PATTERN = 0x0000_01AA,
199 SD_SWITCH_1_8V_CAPACITY = 0x0100_0000,
200}
201
202#[derive(Eq, PartialEq, Copy, Clone)]
203enum Response {
204 None = 0,
205 Short = 1,
206 Long = 3,
207} 209}
208 210
209/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to 211/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
@@ -300,18 +302,77 @@ impl Default for Config {
300 } 302 }
301} 303}
302 304
305/// Peripheral that can be operated over SDMMC
306#[derive(Clone, Copy, Debug)]
307pub enum SdmmcPeripheral {
308 /// SD Card
309 SdCard(Card),
310 /// eMMC memory
311 Emmc(Emmc),
312}
313
314impl SdmmcPeripheral {
315 /// Get this peripheral's address on the SDMMC bus
316 fn get_address(&self) -> u16 {
317 match self {
318 Self::SdCard(c) => c.rca,
319 Self::Emmc(e) => e.rca,
320 }
321 }
322 /// Is this a standard or high capacity peripheral?
323 fn get_capacity(&self) -> CardCapacity {
324 match self {
325 Self::SdCard(c) => c.card_type,
326 Self::Emmc(e) => e.capacity,
327 }
328 }
329 /// Size in bytes
330 fn size(&self) -> u64 {
331 match self {
332 // SDHC / SDXC / SDUC
333 Self::SdCard(c) => u64::from(c.csd.block_count()) * 512,
334 // capacity > 2GB
335 Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512,
336 }
337 }
338
339 /// Get a mutable reference to the SD Card.
340 ///
341 /// Panics if there is another peripheral instead.
342 fn get_sd_card(&mut self) -> &mut Card {
343 match *self {
344 Self::SdCard(ref mut c) => c,
345 _ => unreachable!("SD only"),
346 }
347 }
348
349 /// Get a mutable reference to the eMMC.
350 ///
351 /// Panics if there is another peripheral instead.
352 fn get_emmc(&mut self) -> &mut Emmc {
353 match *self {
354 Self::Emmc(ref mut e) => e,
355 _ => unreachable!("eMMC only"),
356 }
357 }
358}
359
303/// Sdmmc device 360/// Sdmmc device
304pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> { 361pub struct Sdmmc<'d, T: Instance> {
305 _peri: PeripheralRef<'d, T>, 362 _peri: Peri<'d, T>,
306 #[allow(unused)] 363 #[cfg(sdmmc_v1)]
307 dma: PeripheralRef<'d, Dma>, 364 dma: ChannelAndRequest<'d>,
308 365
309 clk: PeripheralRef<'d, AnyPin>, 366 clk: Peri<'d, AnyPin>,
310 cmd: PeripheralRef<'d, AnyPin>, 367 cmd: Peri<'d, AnyPin>,
311 d0: PeripheralRef<'d, AnyPin>, 368 d0: Peri<'d, AnyPin>,
312 d1: Option<PeripheralRef<'d, AnyPin>>, 369 d1: Option<Peri<'d, AnyPin>>,
313 d2: Option<PeripheralRef<'d, AnyPin>>, 370 d2: Option<Peri<'d, AnyPin>>,
314 d3: Option<PeripheralRef<'d, AnyPin>>, 371 d3: Option<Peri<'d, AnyPin>>,
372 d4: Option<Peri<'d, AnyPin>>,
373 d5: Option<Peri<'d, AnyPin>>,
374 d6: Option<Peri<'d, AnyPin>>,
375 d7: Option<Peri<'d, AnyPin>>,
315 376
316 config: Config, 377 config: Config,
317 /// Current clock to card 378 /// Current clock to card
@@ -319,7 +380,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
319 /// Current signalling scheme to card 380 /// Current signalling scheme to card
320 signalling: Signalling, 381 signalling: Signalling,
321 /// Card 382 /// Card
322 card: Option<Card>, 383 card: Option<SdmmcPeripheral>,
323 384
324 /// An optional buffer to be used for commands 385 /// An optional buffer to be used for commands
325 /// This should be used if there are special memory location requirements for dma 386 /// This should be used if there are special memory location requirements for dma
@@ -334,19 +395,17 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh
334const DATA_AF: AfType = CMD_AF; 395const DATA_AF: AfType = CMD_AF;
335 396
336#[cfg(sdmmc_v1)] 397#[cfg(sdmmc_v1)]
337impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { 398impl<'d, T: Instance> Sdmmc<'d, T> {
338 /// Create a new SDMMC driver, with 1 data lane. 399 /// Create a new SDMMC driver, with 1 data lane.
339 pub fn new_1bit( 400 pub fn new_1bit(
340 sdmmc: impl Peripheral<P = T> + 'd, 401 sdmmc: Peri<'d, T>,
341 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 402 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
342 dma: impl Peripheral<P = Dma> + 'd, 403 dma: Peri<'d, impl SdmmcDma<T>>,
343 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 404 clk: Peri<'d, impl CkPin<T>>,
344 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 405 cmd: Peri<'d, impl CmdPin<T>>,
345 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 406 d0: Peri<'d, impl D0Pin<T>>,
346 config: Config, 407 config: Config,
347 ) -> Self { 408 ) -> Self {
348 into_ref!(clk, cmd, d0);
349
350 critical_section::with(|_| { 409 critical_section::with(|_| {
351 clk.set_as_af(clk.af_num(), CLK_AF); 410 clk.set_as_af(clk.af_num(), CLK_AF);
352 cmd.set_as_af(cmd.af_num(), CMD_AF); 411 cmd.set_as_af(cmd.af_num(), CMD_AF);
@@ -355,10 +414,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
355 414
356 Self::new_inner( 415 Self::new_inner(
357 sdmmc, 416 sdmmc,
358 dma, 417 new_dma_nonopt!(dma),
359 clk.map_into(), 418 clk.into(),
360 cmd.map_into(), 419 cmd.into(),
361 d0.map_into(), 420 d0.into(),
421 None,
422 None,
423 None,
424 None,
362 None, 425 None,
363 None, 426 None,
364 None, 427 None,
@@ -368,19 +431,63 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
368 431
369 /// Create a new SDMMC driver, with 4 data lanes. 432 /// Create a new SDMMC driver, with 4 data lanes.
370 pub fn new_4bit( 433 pub fn new_4bit(
371 sdmmc: impl Peripheral<P = T> + 'd, 434 sdmmc: Peri<'d, T>,
372 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 435 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
373 dma: impl Peripheral<P = Dma> + 'd, 436 dma: Peri<'d, impl SdmmcDma<T>>,
374 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 437 clk: Peri<'d, impl CkPin<T>>,
375 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 438 cmd: Peri<'d, impl CmdPin<T>>,
376 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 439 d0: Peri<'d, impl D0Pin<T>>,
377 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 440 d1: Peri<'d, impl D1Pin<T>>,
378 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 441 d2: Peri<'d, impl D2Pin<T>>,
379 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 442 d3: Peri<'d, impl D3Pin<T>>,
380 config: Config, 443 config: Config,
381 ) -> Self { 444 ) -> Self {
382 into_ref!(clk, cmd, d0, d1, d2, d3); 445 critical_section::with(|_| {
446 clk.set_as_af(clk.af_num(), CLK_AF);
447 cmd.set_as_af(cmd.af_num(), CMD_AF);
448 d0.set_as_af(d0.af_num(), DATA_AF);
449 d1.set_as_af(d1.af_num(), DATA_AF);
450 d2.set_as_af(d2.af_num(), DATA_AF);
451 d3.set_as_af(d3.af_num(), DATA_AF);
452 });
453
454 Self::new_inner(
455 sdmmc,
456 new_dma_nonopt!(dma),
457 clk.into(),
458 cmd.into(),
459 d0.into(),
460 Some(d1.into()),
461 Some(d2.into()),
462 Some(d3.into()),
463 None,
464 None,
465 None,
466 None,
467 config,
468 )
469 }
470}
383 471
472#[cfg(sdmmc_v1)]
473impl<'d, T: Instance> Sdmmc<'d, T> {
474 /// Create a new SDMMC driver, with 8 data lanes.
475 pub fn new_8bit(
476 sdmmc: Peri<'d, T>,
477 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
478 dma: Peri<'d, impl SdmmcDma<T>>,
479 clk: Peri<'d, impl CkPin<T>>,
480 cmd: Peri<'d, impl CmdPin<T>>,
481 d0: Peri<'d, impl D0Pin<T>>,
482 d1: Peri<'d, impl D1Pin<T>>,
483 d2: Peri<'d, impl D2Pin<T>>,
484 d3: Peri<'d, impl D3Pin<T>>,
485 d4: Peri<'d, impl D4Pin<T>>,
486 d5: Peri<'d, impl D5Pin<T>>,
487 d6: Peri<'d, impl D6Pin<T>>,
488 d7: Peri<'d, impl D7Pin<T>>,
489 config: Config,
490 ) -> Self {
384 critical_section::with(|_| { 491 critical_section::with(|_| {
385 clk.set_as_af(clk.af_num(), CLK_AF); 492 clk.set_as_af(clk.af_num(), CLK_AF);
386 cmd.set_as_af(cmd.af_num(), CMD_AF); 493 cmd.set_as_af(cmd.af_num(), CMD_AF);
@@ -388,35 +495,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
388 d1.set_as_af(d1.af_num(), DATA_AF); 495 d1.set_as_af(d1.af_num(), DATA_AF);
389 d2.set_as_af(d2.af_num(), DATA_AF); 496 d2.set_as_af(d2.af_num(), DATA_AF);
390 d3.set_as_af(d3.af_num(), DATA_AF); 497 d3.set_as_af(d3.af_num(), DATA_AF);
498 d4.set_as_af(d4.af_num(), DATA_AF);
499 d5.set_as_af(d5.af_num(), DATA_AF);
500 d6.set_as_af(d6.af_num(), DATA_AF);
501 d7.set_as_af(d7.af_num(), DATA_AF);
391 }); 502 });
392 503
393 Self::new_inner( 504 Self::new_inner(
394 sdmmc, 505 sdmmc,
395 dma, 506 new_dma_nonopt!(dma),
396 clk.map_into(), 507 clk.into(),
397 cmd.map_into(), 508 cmd.into(),
398 d0.map_into(), 509 d0.into(),
399 Some(d1.map_into()), 510 Some(d1.into()),
400 Some(d2.map_into()), 511 Some(d2.into()),
401 Some(d3.map_into()), 512 Some(d3.into()),
513 Some(d4.into()),
514 Some(d5.into()),
515 Some(d6.into()),
516 Some(d7.into()),
402 config, 517 config,
403 ) 518 )
404 } 519 }
405} 520}
406 521
407#[cfg(sdmmc_v2)] 522#[cfg(sdmmc_v2)]
408impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { 523impl<'d, T: Instance> Sdmmc<'d, T> {
409 /// Create a new SDMMC driver, with 1 data lane. 524 /// Create a new SDMMC driver, with 1 data lane.
410 pub fn new_1bit( 525 pub fn new_1bit(
411 sdmmc: impl Peripheral<P = T> + 'd, 526 sdmmc: Peri<'d, T>,
412 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 527 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
413 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 528 clk: Peri<'d, impl CkPin<T>>,
414 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 529 cmd: Peri<'d, impl CmdPin<T>>,
415 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 530 d0: Peri<'d, impl D0Pin<T>>,
416 config: Config, 531 config: Config,
417 ) -> Self { 532 ) -> Self {
418 into_ref!(clk, cmd, d0);
419
420 critical_section::with(|_| { 533 critical_section::with(|_| {
421 clk.set_as_af(clk.af_num(), CLK_AF); 534 clk.set_as_af(clk.af_num(), CLK_AF);
422 cmd.set_as_af(cmd.af_num(), CMD_AF); 535 cmd.set_as_af(cmd.af_num(), CMD_AF);
@@ -425,10 +538,13 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
425 538
426 Self::new_inner( 539 Self::new_inner(
427 sdmmc, 540 sdmmc,
428 NoDma.into_ref(), 541 clk.into(),
429 clk.map_into(), 542 cmd.into(),
430 cmd.map_into(), 543 d0.into(),
431 d0.map_into(), 544 None,
545 None,
546 None,
547 None,
432 None, 548 None,
433 None, 549 None,
434 None, 550 None,
@@ -438,18 +554,60 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
438 554
439 /// Create a new SDMMC driver, with 4 data lanes. 555 /// Create a new SDMMC driver, with 4 data lanes.
440 pub fn new_4bit( 556 pub fn new_4bit(
441 sdmmc: impl Peripheral<P = T> + 'd, 557 sdmmc: Peri<'d, T>,
442 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 558 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
443 clk: impl Peripheral<P = impl CkPin<T>> + 'd, 559 clk: Peri<'d, impl CkPin<T>>,
444 cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, 560 cmd: Peri<'d, impl CmdPin<T>>,
445 d0: impl Peripheral<P = impl D0Pin<T>> + 'd, 561 d0: Peri<'d, impl D0Pin<T>>,
446 d1: impl Peripheral<P = impl D1Pin<T>> + 'd, 562 d1: Peri<'d, impl D1Pin<T>>,
447 d2: impl Peripheral<P = impl D2Pin<T>> + 'd, 563 d2: Peri<'d, impl D2Pin<T>>,
448 d3: impl Peripheral<P = impl D3Pin<T>> + 'd, 564 d3: Peri<'d, impl D3Pin<T>>,
449 config: Config, 565 config: Config,
450 ) -> Self { 566 ) -> Self {
451 into_ref!(clk, cmd, d0, d1, d2, d3); 567 critical_section::with(|_| {
568 clk.set_as_af(clk.af_num(), CLK_AF);
569 cmd.set_as_af(cmd.af_num(), CMD_AF);
570 d0.set_as_af(d0.af_num(), DATA_AF);
571 d1.set_as_af(d1.af_num(), DATA_AF);
572 d2.set_as_af(d2.af_num(), DATA_AF);
573 d3.set_as_af(d3.af_num(), DATA_AF);
574 });
452 575
576 Self::new_inner(
577 sdmmc,
578 clk.into(),
579 cmd.into(),
580 d0.into(),
581 Some(d1.into()),
582 Some(d2.into()),
583 Some(d3.into()),
584 None,
585 None,
586 None,
587 None,
588 config,
589 )
590 }
591}
592
593#[cfg(sdmmc_v2)]
594impl<'d, T: Instance> Sdmmc<'d, T> {
595 /// Create a new SDMMC driver, with 8 data lanes.
596 pub fn new_8bit(
597 sdmmc: Peri<'d, T>,
598 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
599 clk: Peri<'d, impl CkPin<T>>,
600 cmd: Peri<'d, impl CmdPin<T>>,
601 d0: Peri<'d, impl D0Pin<T>>,
602 d1: Peri<'d, impl D1Pin<T>>,
603 d2: Peri<'d, impl D2Pin<T>>,
604 d3: Peri<'d, impl D3Pin<T>>,
605 d4: Peri<'d, impl D4Pin<T>>,
606 d5: Peri<'d, impl D5Pin<T>>,
607 d6: Peri<'d, impl D6Pin<T>>,
608 d7: Peri<'d, impl D7Pin<T>>,
609 config: Config,
610 ) -> Self {
453 critical_section::with(|_| { 611 critical_section::with(|_| {
454 clk.set_as_af(clk.af_num(), CLK_AF); 612 clk.set_as_af(clk.af_num(), CLK_AF);
455 cmd.set_as_af(cmd.af_num(), CMD_AF); 613 cmd.set_as_af(cmd.af_num(), CMD_AF);
@@ -457,36 +615,45 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
457 d1.set_as_af(d1.af_num(), DATA_AF); 615 d1.set_as_af(d1.af_num(), DATA_AF);
458 d2.set_as_af(d2.af_num(), DATA_AF); 616 d2.set_as_af(d2.af_num(), DATA_AF);
459 d3.set_as_af(d3.af_num(), DATA_AF); 617 d3.set_as_af(d3.af_num(), DATA_AF);
618 d4.set_as_af(d4.af_num(), DATA_AF);
619 d5.set_as_af(d5.af_num(), DATA_AF);
620 d6.set_as_af(d6.af_num(), DATA_AF);
621 d7.set_as_af(d7.af_num(), DATA_AF);
460 }); 622 });
461 623
462 Self::new_inner( 624 Self::new_inner(
463 sdmmc, 625 sdmmc,
464 NoDma.into_ref(), 626 clk.into(),
465 clk.map_into(), 627 cmd.into(),
466 cmd.map_into(), 628 d0.into(),
467 d0.map_into(), 629 Some(d1.into()),
468 Some(d1.map_into()), 630 Some(d2.into()),
469 Some(d2.map_into()), 631 Some(d3.into()),
470 Some(d3.map_into()), 632 Some(d4.into()),
633 Some(d5.into()),
634 Some(d6.into()),
635 Some(d7.into()),
471 config, 636 config,
472 ) 637 )
473 } 638 }
474} 639}
475 640
476impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { 641impl<'d, T: Instance> Sdmmc<'d, T> {
477 fn new_inner( 642 fn new_inner(
478 sdmmc: impl Peripheral<P = T> + 'd, 643 sdmmc: Peri<'d, T>,
479 dma: impl Peripheral<P = Dma> + 'd, 644 #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>,
480 clk: PeripheralRef<'d, AnyPin>, 645 clk: Peri<'d, AnyPin>,
481 cmd: PeripheralRef<'d, AnyPin>, 646 cmd: Peri<'d, AnyPin>,
482 d0: PeripheralRef<'d, AnyPin>, 647 d0: Peri<'d, AnyPin>,
483 d1: Option<PeripheralRef<'d, AnyPin>>, 648 d1: Option<Peri<'d, AnyPin>>,
484 d2: Option<PeripheralRef<'d, AnyPin>>, 649 d2: Option<Peri<'d, AnyPin>>,
485 d3: Option<PeripheralRef<'d, AnyPin>>, 650 d3: Option<Peri<'d, AnyPin>>,
651 d4: Option<Peri<'d, AnyPin>>,
652 d5: Option<Peri<'d, AnyPin>>,
653 d6: Option<Peri<'d, AnyPin>>,
654 d7: Option<Peri<'d, AnyPin>>,
486 config: Config, 655 config: Config,
487 ) -> Self { 656 ) -> Self {
488 into_ref!(sdmmc, dma);
489
490 rcc::enable_and_reset::<T>(); 657 rcc::enable_and_reset::<T>();
491 658
492 T::Interrupt::unpend(); 659 T::Interrupt::unpend();
@@ -514,6 +681,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
514 681
515 Self { 682 Self {
516 _peri: sdmmc, 683 _peri: sdmmc,
684 #[cfg(sdmmc_v1)]
517 dma, 685 dma,
518 686
519 clk, 687 clk,
@@ -522,6 +690,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
522 d1, 690 d1,
523 d2, 691 d2,
524 d3, 692 d3,
693 d4,
694 d5,
695 d6,
696 d7,
525 697
526 config, 698 config,
527 clock: SD_INIT_FREQ, 699 clock: SD_INIT_FREQ,
@@ -567,7 +739,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
567 #[allow(unused_variables)] 739 #[allow(unused_variables)]
568 fn prepare_datapath_read<'a>( 740 fn prepare_datapath_read<'a>(
569 config: &Config, 741 config: &Config,
570 dma: &'a mut PeripheralRef<'d, Dma>, 742 #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>,
571 buffer: &'a mut [u32], 743 buffer: &'a mut [u32],
572 length_bytes: u32, 744 length_bytes: u32,
573 block_size: u8, 745 block_size: u8,
@@ -583,16 +755,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
583 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 755 regs.dlenr().write(|w| w.set_datalength(length_bytes));
584 756
585 #[cfg(sdmmc_v1)] 757 #[cfg(sdmmc_v1)]
586 let transfer = unsafe { 758 let transfer = unsafe { dma.read(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) };
587 let request = dma.request();
588 Transfer::new_read(
589 dma,
590 request,
591 regs.fifor().as_ptr() as *mut u32,
592 buffer,
593 DMA_TRANSFER_OPTIONS,
594 )
595 };
596 #[cfg(sdmmc_v2)] 759 #[cfg(sdmmc_v2)]
597 let transfer = { 760 let transfer = {
598 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); 761 regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
@@ -632,14 +795,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
632 795
633 #[cfg(sdmmc_v1)] 796 #[cfg(sdmmc_v1)]
634 let transfer = unsafe { 797 let transfer = unsafe {
635 let request = self.dma.request(); 798 self.dma
636 Transfer::new_write( 799 .write(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS)
637 &mut self.dma,
638 request,
639 buffer,
640 regs.fifor().as_ptr() as *mut u32,
641 DMA_TRANSFER_OPTIONS,
642 )
643 }; 800 };
644 #[cfg(sdmmc_v2)] 801 #[cfg(sdmmc_v2)]
645 let transfer = { 802 let transfer = {
@@ -707,168 +864,29 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
707 Ok(()) 864 Ok(())
708 } 865 }
709 866
710 /// Switch mode using CMD6.
711 ///
712 /// Attempt to set a new signalling mode. The selected
713 /// signalling mode is returned. Expects the current clock
714 /// frequency to be > 12.5MHz.
715 async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> {
716 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
717 // necessary"
718
719 let set_function = 0x8000_0000
720 | match signalling {
721 // See PLSS v7_10 Table 4-11
722 Signalling::DDR50 => 0xFF_FF04,
723 Signalling::SDR104 => 0xFF_1F03,
724 Signalling::SDR50 => 0xFF_1F02,
725 Signalling::SDR25 => 0xFF_FF01,
726 Signalling::SDR12 => 0xFF_FF00,
727 };
728
729 let status = match self.cmd_block.as_deref_mut() {
730 Some(x) => x,
731 None => &mut CmdBlock::new(),
732 };
733
734 // Arm `OnDrop` after the buffer, so it will be dropped first
735 let regs = T::regs();
736 let on_drop = OnDrop::new(|| Self::on_drop());
737
738 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
739 InterruptHandler::<T>::data_interrupts(true);
740 Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
741
742 let res = poll_fn(|cx| {
743 T::state().register(cx.waker());
744 let status = regs.star().read();
745
746 if status.dcrcfail() {
747 return Poll::Ready(Err(Error::Crc));
748 }
749 if status.dtimeout() {
750 return Poll::Ready(Err(Error::Timeout));
751 }
752 #[cfg(sdmmc_v1)]
753 if status.stbiterr() {
754 return Poll::Ready(Err(Error::StBitErr));
755 }
756 if status.dataend() {
757 return Poll::Ready(Ok(()));
758 }
759 Poll::Pending
760 })
761 .await;
762 Self::clear_interrupt_flags();
763
764 // Host is allowed to use the new functions at least 8
765 // clocks after the end of the switch command
766 // transaction. We know the current clock period is < 80ns,
767 // so a total delay of 640ns is required here
768 for _ in 0..300 {
769 cortex_m::asm::nop();
770 }
771
772 match res {
773 Ok(_) => {
774 on_drop.defuse();
775 Self::stop_datapath();
776 drop(transfer);
777
778 // Function Selection of Function Group 1
779 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
780
781 match selection {
782 0 => Ok(Signalling::SDR12),
783 1 => Ok(Signalling::SDR25),
784 2 => Ok(Signalling::SDR50),
785 3 => Ok(Signalling::SDR104),
786 4 => Ok(Signalling::DDR50),
787 _ => Err(Error::UnsupportedCardType),
788 }
789 }
790 Err(e) => Err(e),
791 }
792 }
793
794 /// Query the card status (CMD13, returns R1) 867 /// Query the card status (CMD13, returns R1)
795 fn read_status(&self, card: &Card) -> Result<CardStatus, Error> { 868 fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error>
869 where
870 CardStatus<Ext>: From<u32>,
871 {
796 let regs = T::regs(); 872 let regs = T::regs();
797 let rca = card.rca; 873 let rca = card.get_address();
798 874
799 Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 875 Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13
800 876
801 let r1 = regs.respr(0).read().cardstatus(); 877 let r1 = regs.respr(0).read().cardstatus();
802 Ok(r1.into()) 878 Ok(r1.into())
803 } 879 }
804 880
805 /// Reads the SD Status (ACMD13)
806 async fn read_sd_status(&mut self) -> Result<(), Error> {
807 let card = self.card.as_mut().ok_or(Error::NoCard)?;
808 let rca = card.rca;
809
810 let cmd_block = match self.cmd_block.as_deref_mut() {
811 Some(x) => x,
812 None => &mut CmdBlock::new(),
813 };
814
815 Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
816 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
817
818 let status = cmd_block;
819
820 // Arm `OnDrop` after the buffer, so it will be dropped first
821 let regs = T::regs();
822 let on_drop = OnDrop::new(|| Self::on_drop());
823
824 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
825 InterruptHandler::<T>::data_interrupts(true);
826 Self::cmd(Cmd::card_status(0), true)?;
827
828 let res = poll_fn(|cx| {
829 T::state().register(cx.waker());
830 let status = regs.star().read();
831
832 if status.dcrcfail() {
833 return Poll::Ready(Err(Error::Crc));
834 }
835 if status.dtimeout() {
836 return Poll::Ready(Err(Error::Timeout));
837 }
838 #[cfg(sdmmc_v1)]
839 if status.stbiterr() {
840 return Poll::Ready(Err(Error::StBitErr));
841 }
842 if status.dataend() {
843 return Poll::Ready(Ok(()));
844 }
845 Poll::Pending
846 })
847 .await;
848 Self::clear_interrupt_flags();
849
850 if res.is_ok() {
851 on_drop.defuse();
852 Self::stop_datapath();
853 drop(transfer);
854
855 for byte in status.iter_mut() {
856 *byte = u32::from_be(*byte);
857 }
858 self.card.as_mut().unwrap().status = status.0.into();
859 }
860 res
861 }
862
863 /// Select one card and place it into the _Tranfer State_ 881 /// Select one card and place it into the _Tranfer State_
864 /// 882 ///
865 /// If `None` is specifed for `card`, all cards are put back into 883 /// If `None` is specifed for `card`, all cards are put back into
866 /// _Stand-by State_ 884 /// _Stand-by State_
867 fn select_card(&self, card: Option<&Card>) -> Result<(), Error> { 885 fn select_card(&self, rca: Option<u16>) -> Result<(), Error> {
868 // Determine Relative Card Address (RCA) of given card 886 // Determine Relative Card Address (RCA) of given card
869 let rca = card.map(|c| c.rca << 16).unwrap_or(0); 887 let rca = rca.unwrap_or(0);
870 888
871 let r = Self::cmd(Cmd::sel_desel_card(rca), false); 889 let r = Self::cmd(common_cmd::select_card(rca), false);
872 match (r, rca) { 890 match (r, rca) {
873 (Err(Error::Timeout), 0) => Ok(()), 891 (Err(Error::Timeout), 0) => Ok(()),
874 _ => r, 892 _ => r,
@@ -909,63 +927,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
909 }); 927 });
910 } 928 }
911 929
912 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
913 // Read the the 64-bit SCR register
914 Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
915 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
916
917 let cmd_block = match self.cmd_block.as_deref_mut() {
918 Some(x) => x,
919 None => &mut CmdBlock::new(),
920 };
921 let scr = &mut cmd_block.0[..2];
922
923 // Arm `OnDrop` after the buffer, so it will be dropped first
924 let regs = T::regs();
925 let on_drop = OnDrop::new(|| Self::on_drop());
926
927 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3);
928 InterruptHandler::<T>::data_interrupts(true);
929 Self::cmd(Cmd::cmd51(), true)?;
930
931 let res = poll_fn(|cx| {
932 T::state().register(cx.waker());
933 let status = regs.star().read();
934
935 if status.dcrcfail() {
936 return Poll::Ready(Err(Error::Crc));
937 }
938 if status.dtimeout() {
939 return Poll::Ready(Err(Error::Timeout));
940 }
941 #[cfg(sdmmc_v1)]
942 if status.stbiterr() {
943 return Poll::Ready(Err(Error::StBitErr));
944 }
945 if status.dataend() {
946 return Poll::Ready(Ok(()));
947 }
948 Poll::Pending
949 })
950 .await;
951 Self::clear_interrupt_flags();
952
953 if res.is_ok() {
954 on_drop.defuse();
955 Self::stop_datapath();
956 drop(transfer);
957
958 unsafe {
959 let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
960 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
961 }
962 }
963 res
964 }
965
966 /// Send command to card 930 /// Send command to card
967 #[allow(unused_variables)] 931 #[allow(unused_variables)]
968 fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { 932 fn cmd<R: Resp>(cmd: Cmd<R>, data: bool) -> Result<(), Error> {
969 let regs = T::regs(); 933 let regs = T::regs();
970 934
971 Self::clear_interrupt_flags(); 935 Self::clear_interrupt_flags();
@@ -978,7 +942,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
978 // Command index and start CP State Machine 942 // Command index and start CP State Machine
979 regs.cmdr().write(|w| { 943 regs.cmdr().write(|w| {
980 w.set_waitint(false); 944 w.set_waitint(false);
981 w.set_waitresp(cmd.resp as u8); 945 w.set_waitresp(get_waitresp_val(cmd.response_len()));
982 w.set_cmdindex(cmd.cmd); 946 w.set_cmdindex(cmd.cmd);
983 w.set_cpsmen(true); 947 w.set_cpsmen(true);
984 948
@@ -993,7 +957,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
993 }); 957 });
994 958
995 let mut status; 959 let mut status;
996 if cmd.resp == Response::None { 960 if cmd.response_len() == ResponseLen::Zero {
997 // Wait for CMDSENT or a timeout 961 // Wait for CMDSENT or a timeout
998 while { 962 while {
999 status = regs.star().read(); 963 status = regs.star().read();
@@ -1029,7 +993,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1029 // Command index and start CP State Machine 993 // Command index and start CP State Machine
1030 regs.cmdr().write(|w| { 994 regs.cmdr().write(|w| {
1031 w.set_waitint(false); 995 w.set_waitint(false);
1032 w.set_waitresp(Response::Short as u8); 996 w.set_waitresp(get_waitresp_val(ResponseLen::R48));
1033 w.set_cmdindex(12); 997 w.set_cmdindex(12);
1034 w.set_cpsmen(true); 998 w.set_cpsmen(true);
1035 999
@@ -1048,175 +1012,113 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1048 Self::stop_datapath(); 1012 Self::stop_datapath();
1049 } 1013 }
1050 1014
1051 /// Initializes card (if present) and sets the bus at the specified frequency. 1015 /// Wait for a previously started datapath transfer to complete from an interrupt.
1052 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { 1016 #[inline]
1017 async fn complete_datapath_transfer() -> Result<(), Error> {
1053 let regs = T::regs(); 1018 let regs = T::regs();
1054 let ker_ck = T::frequency();
1055 1019
1056 let bus_width = match self.d3.is_some() { 1020 let res = poll_fn(|cx| {
1057 true => BusWidth::Four, 1021 T::state().register(cx.waker());
1058 false => BusWidth::One, 1022 let status = regs.star().read();
1059 };
1060
1061 // While the SD/SDIO card or eMMC is in identification mode,
1062 // the SDMMC_CK frequency must be no more than 400 kHz.
1063 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1064 self.clock = init_clock;
1065
1066 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1067 Self::wait_idle();
1068 1023
1069 regs.clkcr().modify(|w| { 1024 if status.dcrcfail() {
1070 w.set_widbus(0); 1025 return Poll::Ready(Err(Error::Crc));
1071 w.set_clkdiv(clkdiv); 1026 }
1027 if status.dtimeout() {
1028 return Poll::Ready(Err(Error::Timeout));
1029 }
1030 if status.txunderr() {
1031 return Poll::Ready(Err(Error::Underrun));
1032 }
1072 #[cfg(sdmmc_v1)] 1033 #[cfg(sdmmc_v1)]
1073 w.set_bypass(_bypass); 1034 if status.stbiterr() {
1074 }); 1035 return Poll::Ready(Err(Error::StBitErr));
1075
1076 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1077 Self::cmd(Cmd::idle(), false)?;
1078
1079 // Check if cards supports CMD8 (with pattern)
1080 Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
1081 let r1 = regs.respr(0).read().cardstatus();
1082
1083 let mut card = if r1 == 0x1AA {
1084 // Card echoed back the pattern. Must be at least v2
1085 Card::default()
1086 } else {
1087 return Err(Error::UnsupportedCardVersion);
1088 };
1089
1090 let ocr = loop {
1091 // Signal that next command is a app command
1092 Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
1093
1094 let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
1095 | CmdAppOper::HIGH_CAPACITY as u32
1096 | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
1097
1098 // Initialize card
1099 match Self::cmd(Cmd::app_op_cmd(arg), false) {
1100 // ACMD41
1101 Ok(_) => (),
1102 Err(Error::Crc) => (),
1103 Err(err) => return Err(err),
1104 } 1036 }
1105 let ocr: OCR = regs.respr(0).read().cardstatus().into(); 1037 if status.dataend() {
1106 if !ocr.is_busy() { 1038 return Poll::Ready(Ok(()));
1107 // Power up done
1108 break ocr;
1109 } 1039 }
1110 }; 1040 Poll::Pending
1111 1041 })
1112 if ocr.high_capacity() { 1042 .await;
1113 // Card is SDHC or SDXC or SDUC
1114 card.card_type = CardCapacity::SDHC;
1115 } else {
1116 card.card_type = CardCapacity::SDSC;
1117 }
1118 card.ocr = ocr;
1119
1120 Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
1121 let cid0 = regs.respr(0).read().cardstatus() as u128;
1122 let cid1 = regs.respr(1).read().cardstatus() as u128;
1123 let cid2 = regs.respr(2).read().cardstatus() as u128;
1124 let cid3 = regs.respr(3).read().cardstatus() as u128;
1125 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1126 card.cid = cid.into();
1127 1043
1128 Self::cmd(Cmd::send_rel_addr(), false)?; 1044 Self::clear_interrupt_flags();
1129 card.rca = regs.respr(0).read().cardstatus() >> 16;
1130 1045
1131 Self::cmd(Cmd::send_csd(card.rca << 16), false)?; 1046 res
1132 let csd0 = regs.respr(0).read().cardstatus() as u128; 1047 }
1133 let csd1 = regs.respr(1).read().cardstatus() as u128;
1134 let csd2 = regs.respr(2).read().cardstatus() as u128;
1135 let csd3 = regs.respr(3).read().cardstatus() as u128;
1136 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1137 card.csd = csd.into();
1138 1048
1139 self.select_card(Some(&card))?; 1049 /// Read a data block.
1050 #[inline]
1051 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
1052 let card_capacity = self.card()?.get_capacity();
1140 1053
1141 self.get_scr(&mut card).await?; 1054 // NOTE(unsafe) DataBlock uses align 4
1055 let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) };
1142 1056
1143 // Set bus width 1057 // Always read 1 block of 512 bytes
1144 let (width, acmd_arg) = match bus_width { 1058 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1145 BusWidth::Eight => unimplemented!(), 1059 let address = match card_capacity {
1146 BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), 1060 CardCapacity::StandardCapacity => block_idx * 512,
1147 _ => (BusWidth::One, 0), 1061 _ => block_idx,
1148 }; 1062 };
1149 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; 1063 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1150 Self::cmd(Cmd::cmd6(acmd_arg), false)?;
1151
1152 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1153 Self::wait_idle();
1154
1155 regs.clkcr().modify(|w| {
1156 w.set_widbus(match width {
1157 BusWidth::One => 0,
1158 BusWidth::Four => 1,
1159 BusWidth::Eight => 2,
1160 _ => panic!("Invalid Bus Width"),
1161 })
1162 });
1163
1164 // Set Clock
1165 if freq.0 <= 25_000_000 {
1166 // Final clock frequency
1167 self.clkcr_set_clkdiv(freq.0, width)?;
1168 } else {
1169 // Switch to max clock for SDR12
1170 self.clkcr_set_clkdiv(25_000_000, width)?;
1171 }
1172 1064
1173 self.card = Some(card); 1065 let on_drop = OnDrop::new(|| Self::on_drop());
1174
1175 // Read status
1176 self.read_sd_status().await?;
1177 1066
1178 if freq.0 > 25_000_000 { 1067 let transfer = Self::prepare_datapath_read(
1179 // Switch to SDR25 1068 &self.config,
1180 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; 1069 #[cfg(sdmmc_v1)]
1070 &mut self.dma,
1071 buffer,
1072 512,
1073 9,
1074 );
1075 InterruptHandler::<T>::data_interrupts(true);
1076 Self::cmd(common_cmd::read_single_block(address), true)?;
1181 1077
1182 if self.signalling == Signalling::SDR25 { 1078 let res = Self::complete_datapath_transfer().await;
1183 // Set final clock frequency
1184 self.clkcr_set_clkdiv(freq.0, width)?;
1185 1079
1186 if self.read_status(&card)?.state() != CurrentState::Transfer { 1080 if res.is_ok() {
1187 return Err(Error::SignalingSwitchFailed); 1081 on_drop.defuse();
1188 } 1082 Self::stop_datapath();
1189 } 1083 drop(transfer);
1190 } 1084 }
1191 1085 res
1192 // Read status after signalling change
1193 self.read_sd_status().await?;
1194
1195 Ok(())
1196 } 1086 }
1197 1087
1198 /// Read a data block. 1088 /// Read multiple data blocks.
1199 #[inline] 1089 #[inline]
1200 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { 1090 pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> {
1201 let card_capacity = self.card()?.card_type; 1091 let card_capacity = self.card()?.get_capacity();
1202 1092
1203 // NOTE(unsafe) DataBlock uses align 4 1093 // NOTE(unsafe) reinterpret buffer as &mut [u32]
1204 let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; 1094 let buffer = unsafe {
1095 let ptr = blocks.as_mut_ptr() as *mut u32;
1096 let len = blocks.len() * 128;
1097 core::slice::from_raw_parts_mut(ptr, len)
1098 };
1205 1099
1206 // Always read 1 block of 512 bytes 1100 // Always read 1 block of 512 bytes
1207 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes 1101 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1208 let address = match card_capacity { 1102 let address = match card_capacity {
1209 CardCapacity::SDSC => block_idx * 512, 1103 CardCapacity::StandardCapacity => block_idx * 512,
1210 _ => block_idx, 1104 _ => block_idx,
1211 }; 1105 };
1212 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 1106 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1213 1107
1214 let regs = T::regs(); 1108 let regs = T::regs();
1215 let on_drop = OnDrop::new(|| Self::on_drop()); 1109 let on_drop = OnDrop::new(|| Self::on_drop());
1216 1110
1217 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9); 1111 let transfer = Self::prepare_datapath_read(
1112 &self.config,
1113 #[cfg(sdmmc_v1)]
1114 &mut self.dma,
1115 buffer,
1116 512 * blocks.len() as u32,
1117 9,
1118 );
1218 InterruptHandler::<T>::data_interrupts(true); 1119 InterruptHandler::<T>::data_interrupts(true);
1219 Self::cmd(Cmd::read_single_block(address), true)?; 1120
1121 Self::cmd(common_cmd::read_multiple_blocks(address), true)?;
1220 1122
1221 let res = poll_fn(|cx| { 1123 let res = poll_fn(|cx| {
1222 T::state().register(cx.waker()); 1124 T::state().register(cx.waker());
@@ -1238,6 +1140,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1238 Poll::Pending 1140 Poll::Pending
1239 }) 1141 })
1240 .await; 1142 .await;
1143
1144 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1241 Self::clear_interrupt_flags(); 1145 Self::clear_interrupt_flags();
1242 1146
1243 if res.is_ok() { 1147 if res.is_ok() {
@@ -1256,28 +1160,92 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1256 let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; 1160 let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) };
1257 1161
1258 // Always read 1 block of 512 bytes 1162 // Always read 1 block of 512 bytes
1259 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes 1163 // cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1260 let address = match card.card_type { 1164 let address = match card.get_capacity() {
1261 CardCapacity::SDSC => block_idx * 512, 1165 CardCapacity::StandardCapacity => block_idx * 512,
1262 _ => block_idx, 1166 _ => block_idx,
1263 }; 1167 };
1264 Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 1168 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1265 1169
1266 let regs = T::regs();
1267 let on_drop = OnDrop::new(|| Self::on_drop()); 1170 let on_drop = OnDrop::new(|| Self::on_drop());
1268 1171
1269 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes 1172 // sdmmc_v1 uses different cmd/dma order than v2, but only for writes
1270 #[cfg(sdmmc_v1)] 1173 #[cfg(sdmmc_v1)]
1271 Self::cmd(Cmd::write_single_block(address), true)?; 1174 Self::cmd(common_cmd::write_single_block(address), true)?;
1272 1175
1273 let transfer = self.prepare_datapath_write(buffer, 512, 9); 1176 let transfer = self.prepare_datapath_write(buffer, 512, 9);
1274 InterruptHandler::<T>::data_interrupts(true); 1177 InterruptHandler::<T>::data_interrupts(true);
1275 1178
1276 #[cfg(sdmmc_v2)] 1179 #[cfg(sdmmc_v2)]
1277 Self::cmd(Cmd::write_single_block(address), true)?; 1180 Self::cmd(common_cmd::write_single_block(address), true)?;
1181
1182 let res = Self::complete_datapath_transfer().await;
1183
1184 match res {
1185 Ok(_) => {
1186 on_drop.defuse();
1187 Self::stop_datapath();
1188 drop(transfer);
1189
1190 // TODO: Make this configurable
1191 let mut timeout: u32 = 0x00FF_FFFF;
1192
1193 let card = self.card.as_ref().unwrap();
1194 while timeout > 0 {
1195 let ready_for_data = match card {
1196 SdmmcPeripheral::Emmc(_) => self.read_status::<EMMC>(card)?.ready_for_data(),
1197 SdmmcPeripheral::SdCard(_) => self.read_status::<SD>(card)?.ready_for_data(),
1198 };
1199
1200 if ready_for_data {
1201 return Ok(());
1202 }
1203 timeout -= 1;
1204 }
1205 Err(Error::SoftwareTimeout)
1206 }
1207 Err(e) => Err(e),
1208 }
1209 }
1210
1211 /// Write multiple data blocks.
1212 pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> {
1213 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1214
1215 // NOTE(unsafe) reinterpret buffer as &[u32]
1216 let buffer = unsafe {
1217 let ptr = blocks.as_ptr() as *const u32;
1218 let len = blocks.len() * 128;
1219 core::slice::from_raw_parts(ptr, len)
1220 };
1221
1222 // Always read 1 block of 512 bytes
1223 // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
1224 let address = match card.get_capacity() {
1225 CardCapacity::StandardCapacity => block_idx * 512,
1226 _ => block_idx,
1227 };
1228
1229 Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
1230
1231 let block_count = blocks.len();
1232
1233 let regs = T::regs();
1234 let on_drop = OnDrop::new(|| Self::on_drop());
1235
1236 #[cfg(sdmmc_v1)]
1237 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1238
1239 // Setup write command
1240 let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9);
1241 InterruptHandler::<T>::data_interrupts(true);
1242
1243 #[cfg(sdmmc_v2)]
1244 Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
1278 1245
1279 let res = poll_fn(|cx| { 1246 let res = poll_fn(|cx| {
1280 T::state().register(cx.waker()); 1247 T::state().register(cx.waker());
1248
1281 let status = regs.star().read(); 1249 let status = regs.star().read();
1282 1250
1283 if status.dcrcfail() { 1251 if status.dcrcfail() {
@@ -1286,6 +1254,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1286 if status.dtimeout() { 1254 if status.dtimeout() {
1287 return Poll::Ready(Err(Error::Timeout)); 1255 return Poll::Ready(Err(Error::Timeout));
1288 } 1256 }
1257 if status.txunderr() {
1258 return Poll::Ready(Err(Error::Underrun));
1259 }
1289 #[cfg(sdmmc_v1)] 1260 #[cfg(sdmmc_v1)]
1290 if status.stbiterr() { 1261 if status.stbiterr() {
1291 return Poll::Ready(Err(Error::StBitErr)); 1262 return Poll::Ready(Err(Error::StBitErr));
@@ -1293,9 +1264,12 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1293 if status.dataend() { 1264 if status.dataend() {
1294 return Poll::Ready(Ok(())); 1265 return Poll::Ready(Ok(()));
1295 } 1266 }
1267
1296 Poll::Pending 1268 Poll::Pending
1297 }) 1269 })
1298 .await; 1270 .await;
1271
1272 Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
1299 Self::clear_interrupt_flags(); 1273 Self::clear_interrupt_flags();
1300 1274
1301 match res { 1275 match res {
@@ -1326,10 +1300,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1326 /// 1300 ///
1327 /// # Errors 1301 /// # Errors
1328 /// 1302 ///
1329 /// Returns Error::NoCard if [`init_card`](#method.init_card) 1303 /// Returns Error::NoCard if [`init_sd_card`](#method.init_sd_card) or
1330 /// has not previously succeeded 1304 /// [`init_emmc`](#method.init_emmc) has not previously succeeded
1331 #[inline] 1305 #[inline]
1332 pub fn card(&self) -> Result<&Card, Error> { 1306 pub fn card(&self) -> Result<&SdmmcPeripheral, Error> {
1333 self.card.as_ref().ok_or(Error::NoCard) 1307 self.card.as_ref().ok_or(Error::NoCard)
1334 } 1308 }
1335 1309
@@ -1345,114 +1319,490 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1345 pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { 1319 pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) {
1346 self.cmd_block = Some(cmd_block) 1320 self.cmd_block = Some(cmd_block)
1347 } 1321 }
1348}
1349 1322
1350impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { 1323 async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> {
1351 fn drop(&mut self) { 1324 let regs = T::regs();
1352 T::Interrupt::disable(); 1325 let ker_ck = T::frequency();
1353 Self::on_drop();
1354 1326
1355 critical_section::with(|_| { 1327 let bus_width = match (self.d3.is_some(), self.d7.is_some()) {
1356 self.clk.set_as_disconnected(); 1328 (true, true) => {
1357 self.cmd.set_as_disconnected(); 1329 if matches!(card, SdmmcPeripheral::SdCard(_)) {
1358 self.d0.set_as_disconnected(); 1330 return Err(Error::BusWidth);
1359 if let Some(x) = &mut self.d1 { 1331 }
1360 x.set_as_disconnected(); 1332 BusWidth::Eight
1361 } 1333 }
1362 if let Some(x) = &mut self.d2 { 1334 (true, false) => BusWidth::Four,
1363 x.set_as_disconnected(); 1335 _ => BusWidth::One,
1336 };
1337
1338 // While the SD/SDIO card or eMMC is in identification mode,
1339 // the SDMMC_CK frequency must be no more than 400 kHz.
1340 let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
1341 self.clock = init_clock;
1342
1343 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1344 Self::wait_idle();
1345
1346 regs.clkcr().modify(|w| {
1347 w.set_widbus(0);
1348 w.set_clkdiv(clkdiv);
1349 #[cfg(sdmmc_v1)]
1350 w.set_bypass(_bypass);
1351 });
1352
1353 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
1354 Self::cmd(common_cmd::idle(), false)?;
1355
1356 match card {
1357 SdmmcPeripheral::SdCard(ref mut card) => {
1358 // Check if cards supports CMD8 (with pattern)
1359 Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?;
1360 let cic = CIC::from(regs.respr(0).read().cardstatus());
1361
1362 if cic.pattern() != 0xAA {
1363 return Err(Error::UnsupportedCardVersion);
1364 }
1365
1366 if cic.voltage_accepted() & 1 == 0 {
1367 return Err(Error::UnsupportedVoltage);
1368 }
1369
1370 let ocr = loop {
1371 // Signal that next command is a app command
1372 Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55
1373
1374 // 3.2-3.3V
1375 let voltage_window = 1 << 5;
1376 // Initialize card
1377 match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) {
1378 // ACMD41
1379 Ok(_) => (),
1380 Err(Error::Crc) => (),
1381 Err(err) => return Err(err),
1382 }
1383 let ocr: OCR<SD> = regs.respr(0).read().cardstatus().into();
1384 if !ocr.is_busy() {
1385 // Power up done
1386 break ocr;
1387 }
1388 };
1389
1390 if ocr.high_capacity() {
1391 // Card is SDHC or SDXC or SDUC
1392 card.card_type = CardCapacity::HighCapacity;
1393 } else {
1394 card.card_type = CardCapacity::StandardCapacity;
1395 }
1396 card.ocr = ocr;
1364 } 1397 }
1365 if let Some(x) = &mut self.d3 { 1398 SdmmcPeripheral::Emmc(ref mut emmc) => {
1366 x.set_as_disconnected(); 1399 let ocr = loop {
1400 let high_voltage = 0b0 << 7;
1401 let access_mode = 0b10 << 29;
1402 let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15;
1403 // Initialize card
1404 match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) {
1405 Ok(_) => (),
1406 Err(Error::Crc) => (),
1407 Err(err) => return Err(err),
1408 }
1409 let ocr: OCR<EMMC> = regs.respr(0).read().cardstatus().into();
1410 if !ocr.is_busy() {
1411 // Power up done
1412 break ocr;
1413 }
1414 };
1415
1416 emmc.capacity = if ocr.access_mode() == 0b10 {
1417 // Card is SDHC or SDXC or SDUC
1418 CardCapacity::HighCapacity
1419 } else {
1420 CardCapacity::StandardCapacity
1421 };
1422 emmc.ocr = ocr;
1367 } 1423 }
1368 }); 1424 }
1369 }
1370}
1371 1425
1372/// SD card Commands 1426 Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2
1373impl Cmd { 1427 let cid0 = regs.respr(0).read().cardstatus() as u128;
1374 const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd { 1428 let cid1 = regs.respr(1).read().cardstatus() as u128;
1375 Cmd { cmd, arg, resp } 1429 let cid2 = regs.respr(2).read().cardstatus() as u128;
1376 } 1430 let cid3 = regs.respr(3).read().cardstatus() as u128;
1431 let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
1377 1432
1378 /// CMD0: Idle 1433 match card {
1379 const fn idle() -> Cmd { 1434 SdmmcPeripheral::SdCard(ref mut card) => {
1380 Cmd::new(0, 0, Response::None) 1435 card.cid = cid.into();
1381 }
1382 1436
1383 /// CMD2: Send CID 1437 Self::cmd(sd_cmd::send_relative_address(), false)?;
1384 const fn all_send_cid() -> Cmd { 1438 let rca = RCA::<SD>::from(regs.respr(0).read().cardstatus());
1385 Cmd::new(2, 0, Response::Long) 1439 card.rca = rca.address();
1386 } 1440 }
1441 SdmmcPeripheral::Emmc(ref mut emmc) => {
1442 emmc.cid = cid.into();
1387 1443
1388 /// CMD3: Send Relative Address 1444 emmc.rca = 1u16.into();
1389 const fn send_rel_addr() -> Cmd { 1445 Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?;
1390 Cmd::new(3, 0, Response::Short) 1446 }
1391 } 1447 }
1392 1448
1393 /// CMD6: Switch Function Command 1449 Self::cmd(common_cmd::send_csd(card.get_address()), false)?;
1394 /// ACMD6: Bus Width 1450 let csd0 = regs.respr(0).read().cardstatus() as u128;
1395 const fn cmd6(arg: u32) -> Cmd { 1451 let csd1 = regs.respr(1).read().cardstatus() as u128;
1396 Cmd::new(6, arg, Response::Short) 1452 let csd2 = regs.respr(2).read().cardstatus() as u128;
1397 } 1453 let csd3 = regs.respr(3).read().cardstatus() as u128;
1454 let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
1398 1455
1399 /// CMD7: Select one card and put it into the _Tranfer State_ 1456 self.select_card(Some(card.get_address()))?;
1400 const fn sel_desel_card(rca: u32) -> Cmd { 1457
1401 Cmd::new(7, rca, Response::Short) 1458 let bus_width = match card {
1402 } 1459 SdmmcPeripheral::SdCard(ref mut card) => {
1460 card.csd = csd.into();
1461
1462 self.get_scr(card).await?;
1463
1464 if !card.scr.bus_width_four() {
1465 BusWidth::One
1466 } else {
1467 BusWidth::Four
1468 }
1469 }
1470 SdmmcPeripheral::Emmc(ref mut emmc) => {
1471 emmc.csd = csd.into();
1472
1473 bus_width
1474 }
1475 };
1403 1476
1404 /// CMD8: 1477 // Set bus width
1405 const fn hs_send_ext_csd(arg: u32) -> Cmd { 1478 let widbus = match bus_width {
1406 Cmd::new(8, arg, Response::Short) 1479 BusWidth::Eight => 2,
1480 BusWidth::Four => 1,
1481 BusWidth::One => 0,
1482 _ => unreachable!(),
1483 };
1484
1485 match card {
1486 SdmmcPeripheral::SdCard(ref mut card) => {
1487 let acmd_arg = match bus_width {
1488 BusWidth::Four if card.scr.bus_width_four() => 2,
1489 _ => 0,
1490 };
1491 Self::cmd(common_cmd::app_cmd(card.rca), false)?;
1492 Self::cmd(sd_cmd::cmd6(acmd_arg), false)?;
1493 }
1494 SdmmcPeripheral::Emmc(_) => {
1495 // Write bus width to ExtCSD byte 183
1496 Self::cmd(
1497 emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus),
1498 false,
1499 )?;
1500
1501 // Wait for ready after R1b response
1502 loop {
1503 let status = self.read_status::<EMMC>(&card)?;
1504
1505 if status.ready_for_data() {
1506 break;
1507 }
1508 }
1509 }
1510 }
1511
1512 // CPSMACT and DPSMACT must be 0 to set WIDBUS
1513 Self::wait_idle();
1514
1515 regs.clkcr().modify(|w| w.set_widbus(widbus));
1516
1517 // Set Clock
1518 if freq.0 <= 25_000_000 {
1519 // Final clock frequency
1520 self.clkcr_set_clkdiv(freq.0, bus_width)?;
1521 } else {
1522 // Switch to max clock for SDR12
1523 self.clkcr_set_clkdiv(25_000_000, bus_width)?;
1524 }
1525
1526 self.card = Some(card);
1527
1528 match card {
1529 SdmmcPeripheral::SdCard(_) => {
1530 // Read status
1531 self.read_sd_status().await?;
1532
1533 if freq.0 > 25_000_000 {
1534 // Switch to SDR25
1535 self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
1536
1537 if self.signalling == Signalling::SDR25 {
1538 // Set final clock frequency
1539 self.clkcr_set_clkdiv(freq.0, bus_width)?;
1540
1541 if self.read_status::<SD>(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer {
1542 return Err(Error::SignalingSwitchFailed);
1543 }
1544 }
1545 }
1546
1547 // Read status after signalling change
1548 self.read_sd_status().await?;
1549 }
1550 SdmmcPeripheral::Emmc(_) => {
1551 self.read_ext_csd().await?;
1552 }
1553 }
1554
1555 Ok(())
1407 } 1556 }
1408 1557
1409 /// CMD9: 1558 /// Initializes card (if present) and sets the bus at the specified frequency.
1410 const fn send_csd(rca: u32) -> Cmd { 1559 ///
1411 Cmd::new(9, rca, Response::Long) 1560 /// SD only.
1561 pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> {
1562 self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await
1412 } 1563 }
1413 1564
1414 /// CMD12: 1565 /// Switch mode using CMD6.
1415 //const fn stop_transmission() -> Cmd { 1566 ///
1416 // Cmd::new(12, 0, Response::Short) 1567 /// Attempt to set a new signalling mode. The selected
1417 //} 1568 /// signalling mode is returned. Expects the current clock
1569 /// frequency to be > 12.5MHz.
1570 ///
1571 /// SD only.
1572 async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result<Signalling, Error> {
1573 let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card();
1574 // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not
1575 // necessary"
1418 1576
1419 /// CMD13: Ask card to send status register 1577 let set_function = 0x8000_0000
1420 /// ACMD13: SD Status 1578 | match signalling {
1421 const fn card_status(rca: u32) -> Cmd { 1579 // See PLSS v7_10 Table 4-11
1422 Cmd::new(13, rca, Response::Short) 1580 Signalling::DDR50 => 0xFF_FF04,
1423 } 1581 Signalling::SDR104 => 0xFF_1F03,
1582 Signalling::SDR50 => 0xFF_1F02,
1583 Signalling::SDR25 => 0xFF_FF01,
1584 Signalling::SDR12 => 0xFF_FF00,
1585 };
1586
1587 let status = match self.cmd_block.as_deref_mut() {
1588 Some(x) => x,
1589 None => &mut CmdBlock::new(),
1590 };
1591
1592 // Arm `OnDrop` after the buffer, so it will be dropped first
1593 let on_drop = OnDrop::new(|| Self::on_drop());
1424 1594
1425 /// CMD16: 1595 let transfer = Self::prepare_datapath_read(
1426 const fn set_block_length(blocklen: u32) -> Cmd { 1596 &self.config,
1427 Cmd::new(16, blocklen, Response::Short) 1597 #[cfg(sdmmc_v1)]
1598 &mut self.dma,
1599 status.as_mut(),
1600 64,
1601 6,
1602 );
1603 InterruptHandler::<T>::data_interrupts(true);
1604 Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6
1605
1606 let res = Self::complete_datapath_transfer().await;
1607
1608 // Host is allowed to use the new functions at least 8
1609 // clocks after the end of the switch command
1610 // transaction. We know the current clock period is < 80ns,
1611 // so a total delay of 640ns is required here
1612 for _ in 0..300 {
1613 cortex_m::asm::nop();
1614 }
1615
1616 match res {
1617 Ok(_) => {
1618 on_drop.defuse();
1619 Self::stop_datapath();
1620 drop(transfer);
1621
1622 // Function Selection of Function Group 1
1623 let selection = (u32::from_be(status[4]) >> 24) & 0xF;
1624
1625 match selection {
1626 0 => Ok(Signalling::SDR12),
1627 1 => Ok(Signalling::SDR25),
1628 2 => Ok(Signalling::SDR50),
1629 3 => Ok(Signalling::SDR104),
1630 4 => Ok(Signalling::DDR50),
1631 _ => Err(Error::UnsupportedCardType),
1632 }
1633 }
1634 Err(e) => Err(e),
1635 }
1428 } 1636 }
1429 1637
1430 /// CMD17: Block Read 1638 /// Reads the SCR register.
1431 const fn read_single_block(addr: u32) -> Cmd { 1639 ///
1432 Cmd::new(17, addr, Response::Short) 1640 /// SD only.
1641 async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
1642 // Read the 64-bit SCR register
1643 Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16
1644 Self::cmd(common_cmd::app_cmd(card.rca), false)?;
1645
1646 let cmd_block = match self.cmd_block.as_deref_mut() {
1647 Some(x) => x,
1648 None => &mut CmdBlock::new(),
1649 };
1650 let scr = &mut cmd_block.0[..2];
1651
1652 // Arm `OnDrop` after the buffer, so it will be dropped first
1653 let on_drop = OnDrop::new(|| Self::on_drop());
1654
1655 let transfer = Self::prepare_datapath_read(
1656 &self.config,
1657 #[cfg(sdmmc_v1)]
1658 &mut self.dma,
1659 scr,
1660 8,
1661 3,
1662 );
1663 InterruptHandler::<T>::data_interrupts(true);
1664 Self::cmd(sd_cmd::send_scr(), true)?;
1665
1666 let res = Self::complete_datapath_transfer().await;
1667
1668 if res.is_ok() {
1669 on_drop.defuse();
1670 Self::stop_datapath();
1671 drop(transfer);
1672
1673 unsafe {
1674 let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
1675 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
1676 }
1677 }
1678 res
1433 } 1679 }
1434 1680
1435 /// CMD18: Multiple Block Read 1681 /// Reads the SD Status (ACMD13)
1436 //const fn read_multiple_blocks(addr: u32) -> Cmd { 1682 ///
1437 // Cmd::new(18, addr, Response::Short) 1683 /// SD only.
1438 //} 1684 async fn read_sd_status(&mut self) -> Result<(), Error> {
1685 let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card();
1686 let rca = card.rca;
1687
1688 let cmd_block = match self.cmd_block.as_deref_mut() {
1689 Some(x) => x,
1690 None => &mut CmdBlock::new(),
1691 };
1692
1693 Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16
1694 Self::cmd(common_cmd::app_cmd(rca), false)?; // APP
1695
1696 let status = cmd_block;
1697
1698 // Arm `OnDrop` after the buffer, so it will be dropped first
1699 let on_drop = OnDrop::new(|| Self::on_drop());
1439 1700
1440 /// CMD24: Block Write 1701 let transfer = Self::prepare_datapath_read(
1441 const fn write_single_block(addr: u32) -> Cmd { 1702 &self.config,
1442 Cmd::new(24, addr, Response::Short) 1703 #[cfg(sdmmc_v1)]
1704 &mut self.dma,
1705 status.as_mut(),
1706 64,
1707 6,
1708 );
1709 InterruptHandler::<T>::data_interrupts(true);
1710 Self::cmd(sd_cmd::sd_status(), true)?;
1711
1712 let res = Self::complete_datapath_transfer().await;
1713
1714 if res.is_ok() {
1715 on_drop.defuse();
1716 Self::stop_datapath();
1717 drop(transfer);
1718
1719 for byte in status.iter_mut() {
1720 *byte = u32::from_be(*byte);
1721 }
1722 card.status = status.0.into();
1723 }
1724 res
1443 } 1725 }
1444 1726
1445 const fn app_op_cmd(arg: u32) -> Cmd { 1727 /// Initializes eMMC and sets the bus at the specified frequency.
1446 Cmd::new(41, arg, Response::Short) 1728 ///
1729 /// eMMC only.
1730 pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> {
1731 self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await
1447 } 1732 }
1448 1733
1449 const fn cmd51() -> Cmd { 1734 /// Gets the EXT_CSD register.
1450 Cmd::new(51, 0, Response::Short) 1735 ///
1736 /// eMMC only.
1737 async fn read_ext_csd(&mut self) -> Result<(), Error> {
1738 let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc();
1739
1740 // Note: cmd_block can't be used because ExtCSD is too long to fit.
1741 let mut data_block = DataBlock([0u8; 512]);
1742
1743 // NOTE(unsafe) DataBlock uses align 4
1744 let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) };
1745
1746 Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16
1747
1748 // Arm `OnDrop` after the buffer, so it will be dropped first
1749 let on_drop = OnDrop::new(|| Self::on_drop());
1750
1751 let transfer = Self::prepare_datapath_read(
1752 &self.config,
1753 #[cfg(sdmmc_v1)]
1754 &mut self.dma,
1755 buffer,
1756 512,
1757 9,
1758 );
1759 InterruptHandler::<T>::data_interrupts(true);
1760 Self::cmd(emmc_cmd::send_ext_csd(), true)?;
1761
1762 let res = Self::complete_datapath_transfer().await;
1763
1764 if res.is_ok() {
1765 on_drop.defuse();
1766 Self::stop_datapath();
1767 drop(transfer);
1768
1769 card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into();
1770 }
1771 res
1451 } 1772 }
1773}
1774
1775impl<'d, T: Instance> Drop for Sdmmc<'d, T> {
1776 fn drop(&mut self) {
1777 T::Interrupt::disable();
1778 Self::on_drop();
1452 1779
1453 /// App Command. Indicates that next command will be a app command 1780 critical_section::with(|_| {
1454 const fn app_cmd(rca: u32) -> Cmd { 1781 self.clk.set_as_disconnected();
1455 Cmd::new(55, rca, Response::Short) 1782 self.cmd.set_as_disconnected();
1783 self.d0.set_as_disconnected();
1784 if let Some(x) = &mut self.d1 {
1785 x.set_as_disconnected();
1786 }
1787 if let Some(x) = &mut self.d2 {
1788 x.set_as_disconnected();
1789 }
1790 if let Some(x) = &mut self.d3 {
1791 x.set_as_disconnected();
1792 }
1793 if let Some(x) = &mut self.d4 {
1794 x.set_as_disconnected();
1795 }
1796 if let Some(x) = &mut self.d5 {
1797 x.set_as_disconnected();
1798 }
1799 if let Some(x) = &mut self.d6 {
1800 x.set_as_disconnected();
1801 }
1802 if let Some(x) = &mut self.d7 {
1803 x.set_as_disconnected();
1804 }
1805 });
1456 } 1806 }
1457} 1807}
1458 1808
@@ -1465,7 +1815,7 @@ trait SealedInstance {
1465 1815
1466/// SDMMC instance trait. 1816/// SDMMC instance trait.
1467#[allow(private_bounds)] 1817#[allow(private_bounds)]
1468pub trait Instance: SealedInstance + RccPeripheral + 'static { 1818pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {
1469 /// Interrupt for this instance. 1819 /// Interrupt for this instance.
1470 type Interrupt: interrupt::typelevel::Interrupt; 1820 type Interrupt: interrupt::typelevel::Interrupt;
1471} 1821}
@@ -1484,15 +1834,6 @@ pin_trait!(D7Pin, Instance);
1484#[cfg(sdmmc_v1)] 1834#[cfg(sdmmc_v1)]
1485dma_trait!(SdmmcDma, Instance); 1835dma_trait!(SdmmcDma, Instance);
1486 1836
1487/// DMA instance trait.
1488///
1489/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of
1490/// using ST's system-wide DMA peripheral.
1491#[cfg(sdmmc_v2)]
1492pub trait SdmmcDma<T: Instance> {}
1493#[cfg(sdmmc_v2)]
1494impl<T: Instance> SdmmcDma<T> for NoDma {}
1495
1496foreach_peripheral!( 1837foreach_peripheral!(
1497 (sdmmc, $inst:ident) => { 1838 (sdmmc, $inst:ident) => {
1498 impl SealedInstance for peripherals::$inst { 1839 impl SealedInstance for peripherals::$inst {
@@ -1511,3 +1852,46 @@ foreach_peripheral!(
1511 } 1852 }
1512 }; 1853 };
1513); 1854);
1855
1856impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> {
1857 type Error = Error;
1858 type Align = aligned::A4;
1859
1860 async fn read(
1861 &mut self,
1862 block_address: u32,
1863 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
1864 ) -> Result<(), Self::Error> {
1865 // TODO: I think block_address needs to be adjusted by the partition start offset
1866 if buf.len() == 1 {
1867 let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) };
1868 self.read_block(block_address, block).await?;
1869 } else {
1870 let blocks: &mut [DataBlock] =
1871 unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) };
1872 self.read_blocks(block_address, blocks).await?;
1873 }
1874 Ok(())
1875 }
1876
1877 async fn write(
1878 &mut self,
1879 block_address: u32,
1880 buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
1881 ) -> Result<(), Self::Error> {
1882 // TODO: I think block_address needs to be adjusted by the partition start offset
1883 if buf.len() == 1 {
1884 let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) };
1885 self.write_block(block_address, block).await?;
1886 } else {
1887 let blocks: &[DataBlock] =
1888 unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) };
1889 self.write_blocks(block_address, blocks).await?;
1890 }
1891 Ok(())
1892 }
1893
1894 async fn size(&mut self) -> Result<u64, Self::Error> {
1895 Ok(self.card()?.size())
1896 }
1897}
diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs
new file mode 100644
index 000000000..9c42217f0
--- /dev/null
+++ b/embassy-stm32/src/spdifrx/mod.rs
@@ -0,0 +1,333 @@
1//! S/PDIF receiver
2#![macro_use]
3#![cfg_attr(gpdma, allow(unused))]
4
5use core::marker::PhantomData;
6
7use embassy_sync::waitqueue::AtomicWaker;
8
9use crate::dma::ringbuffer::Error as RingbufferError;
10pub use crate::dma::word;
11#[cfg(not(gpdma))]
12use crate::dma::ReadableRingBuffer;
13use crate::dma::{Channel, TransferOptions};
14use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
15use crate::interrupt::typelevel::Interrupt;
16use crate::pac::spdifrx::Spdifrx as Regs;
17use crate::rcc::{RccInfo, SealedRccPeripheral};
18use crate::{interrupt, peripherals, Peri};
19
20/// Possible S/PDIF preamble types.
21#[allow(dead_code)]
22#[repr(u8)]
23enum PreambleType {
24 Unused = 0x00,
25 /// The preamble changes to preamble “B” once every 192 frames to identify the start of the block structure used to
26 /// organize the channel status and user information.
27 B = 0x01,
28 /// The first sub-frame (left or “A” channel in stereophonic operation and primary channel in monophonic operation)
29 /// normally starts with preamble “M”
30 M = 0x02,
31 /// The second sub-frame (right or “B” channel in stereophonic operation and secondary channel in monophonic
32 /// operation) always starts with preamble “W”.
33 W = 0x03,
34}
35
36macro_rules! new_spdifrx_pin {
37 ($name:ident, $af_type:expr) => {{
38 let pin = $name;
39 let input_sel = pin.input_sel();
40 pin.set_as_af(pin.af_num(), $af_type);
41 (Some(pin.into()), input_sel)
42 }};
43}
44
45macro_rules! impl_spdifrx_pin {
46 ($inst:ident, $pin:ident, $af:expr, $sel:expr) => {
47 impl crate::spdifrx::InPin<peripherals::$inst> for crate::peripherals::$pin {
48 fn af_num(&self) -> u8 {
49 $af
50 }
51 fn input_sel(&self) -> u8 {
52 $sel
53 }
54 }
55 };
56}
57
58/// Ring-buffered SPDIFRX driver.
59///
60/// Data is read by DMAs and stored in a ring buffer.
61#[cfg(not(gpdma))]
62pub struct Spdifrx<'d, T: Instance> {
63 _peri: Peri<'d, T>,
64 spdifrx_in: Option<Peri<'d, AnyPin>>,
65 data_ring_buffer: ReadableRingBuffer<'d, u32>,
66}
67
68/// Gives the address of the data register.
69fn dr_address(r: Regs) -> *mut u32 {
70 #[cfg(spdifrx_v1)]
71 let address = r.dr().as_ptr() as _;
72 #[cfg(spdifrx_h7)]
73 let address = r.fmt0_dr().as_ptr() as _; // All fmtx_dr() implementations have the same address.
74
75 return address;
76}
77
78/// Gives the address of the channel status register.
79#[allow(unused)]
80fn csr_address(r: Regs) -> *mut u32 {
81 r.csr().as_ptr() as _
82}
83
84/// Select the channel for capturing control information.
85pub enum ControlChannelSelection {
86 /// Capture control info from channel A.
87 A,
88 /// Capture control info from channel B.
89 B,
90}
91
92/// Configuration options for the SPDIFRX driver.
93pub struct Config {
94 /// Select the channel for capturing control information.
95 pub control_channel_selection: ControlChannelSelection,
96}
97
98/// S/PDIF errors.
99#[derive(Debug)]
100pub enum Error {
101 /// DMA overrun error.
102 RingbufferError(RingbufferError),
103 /// Left/right channel synchronization error.
104 ChannelSyncError,
105}
106
107impl From<RingbufferError> for Error {
108 fn from(error: RingbufferError) -> Self {
109 Self::RingbufferError(error)
110 }
111}
112
113impl Default for Config {
114 fn default() -> Self {
115 Self {
116 control_channel_selection: ControlChannelSelection::A,
117 }
118 }
119}
120
121#[cfg(not(gpdma))]
122impl<'d, T: Instance> Spdifrx<'d, T> {
123 fn dma_opts() -> TransferOptions {
124 TransferOptions {
125 half_transfer_ir: true,
126 // new_write() and new_read() always use circular mode
127 ..Default::default()
128 }
129 }
130
131 /// Create a new `Spdifrx` instance.
132 pub fn new(
133 peri: Peri<'d, T>,
134 _irq: impl interrupt::typelevel::Binding<T::GlobalInterrupt, GlobalInterruptHandler<T>> + 'd,
135 config: Config,
136 spdifrx_in: Peri<'d, impl InPin<T>>,
137 data_dma: Peri<'d, impl Channel + Dma<T>>,
138 data_dma_buf: &'d mut [u32],
139 ) -> Self {
140 let (spdifrx_in, input_sel) = new_spdifrx_pin!(spdifrx_in, AfType::input(Pull::None));
141 Self::setup(config, input_sel);
142
143 let regs = T::info().regs;
144 let dr_request = data_dma.request();
145 let dr_ring_buffer =
146 unsafe { ReadableRingBuffer::new(data_dma, dr_request, dr_address(regs), data_dma_buf, Self::dma_opts()) };
147
148 Self {
149 _peri: peri,
150 spdifrx_in,
151 data_ring_buffer: dr_ring_buffer,
152 }
153 }
154
155 fn setup(config: Config, input_sel: u8) {
156 T::info().rcc.enable_and_reset();
157 T::GlobalInterrupt::unpend();
158 unsafe { T::GlobalInterrupt::enable() };
159
160 let regs = T::info().regs;
161
162 regs.imr().write(|imr| {
163 imr.set_ifeie(true); // Enables interrupts for TERR, SERR, FERR.
164 imr.set_syncdie(true); // Enables SYNCD interrupt.
165 });
166
167 regs.cr().write(|cr| {
168 cr.set_spdifen(0x00); // Disable SPDIF receiver synchronization.
169 cr.set_rxdmaen(true); // Use RX DMA for data. Enabled on `read`.
170 cr.set_cbdmaen(false); // Do not capture channel info.
171 cr.set_rxsteo(true); // Operate in stereo mode.
172 cr.set_drfmt(0x01); // Data is left-aligned (MSB).
173
174 // Disable all status fields in the data register.
175 // Status can be obtained directly with the status register DMA.
176 cr.set_pmsk(false); // Write parity bit to the data register. FIXME: Add parity check.
177 cr.set_vmsk(false); // Write validity to the data register.
178 cr.set_cumsk(true); // Do not write C and U bits to the data register.
179 cr.set_ptmsk(false); // Write preamble bits to the data register.
180
181 cr.set_chsel(match config.control_channel_selection {
182 ControlChannelSelection::A => false,
183 ControlChannelSelection::B => true,
184 }); // Select channel status source.
185
186 cr.set_nbtr(0x02); // 16 attempts are allowed.
187 cr.set_wfa(true); // Wait for activity before going to synchronization phase.
188 cr.set_insel(input_sel); // Input pin selection.
189
190 #[cfg(stm32h7)]
191 cr.set_cksen(true); // Generate a symbol clock.
192
193 #[cfg(stm32h7)]
194 cr.set_cksbkpen(true); // Generate a backup symbol clock.
195 });
196 }
197
198 /// Start the SPDIFRX driver.
199 pub fn start(&mut self) {
200 self.data_ring_buffer.start();
201
202 T::info().regs.cr().modify(|cr| {
203 cr.set_spdifen(0x03); // Enable S/PDIF receiver.
204 });
205 }
206
207 /// Read from the SPDIFRX data ring buffer.
208 ///
209 /// SPDIFRX is always receiving data in the background. This function pops already-received
210 /// data from the buffer.
211 ///
212 /// If there's less than `data.len()` data in the buffer, this waits until there is.
213 pub async fn read(&mut self, data: &mut [u32]) -> Result<(), Error> {
214 self.data_ring_buffer.read_exact(data).await?;
215
216 let first_preamble = (data[0] >> 4) & 0b11_u32;
217 if (first_preamble as u8) == (PreambleType::W as u8) {
218 trace!("S/PDIF left/right mismatch");
219
220 // Resynchronize until the first sample is for the left channel.
221 self.data_ring_buffer.clear();
222 return Err(Error::ChannelSyncError);
223 };
224
225 for sample in data.as_mut() {
226 if (*sample & (0x0002_u32)) != 0 {
227 // Discard invalid samples, setting them to mute level.
228 *sample = 0;
229 } else {
230 // Discard status information in the lowest byte.
231 *sample &= 0xFFFFFF00;
232 }
233 }
234
235 Ok(())
236 }
237}
238
239#[cfg(not(gpdma))]
240impl<'d, T: Instance> Drop for Spdifrx<'d, T> {
241 fn drop(&mut self) {
242 T::info().regs.cr().modify(|cr| cr.set_spdifen(0x00));
243 self.spdifrx_in.as_ref().map(|x| x.set_as_disconnected());
244 }
245}
246
247struct State {
248 #[allow(unused)]
249 waker: AtomicWaker,
250}
251
252impl State {
253 const fn new() -> Self {
254 Self {
255 waker: AtomicWaker::new(),
256 }
257 }
258}
259
260struct Info {
261 regs: crate::pac::spdifrx::Spdifrx,
262 rcc: RccInfo,
263}
264
265peri_trait!(
266 irqs: [GlobalInterrupt],
267);
268
269/// SPIDFRX pin trait
270pub trait InPin<T: Instance>: crate::gpio::Pin {
271 /// Get the GPIO AF number needed to use this pin.
272 fn af_num(&self) -> u8;
273 /// Get the SPIDFRX INSEL number needed to use this pin.
274 fn input_sel(&self) -> u8;
275}
276
277dma_trait!(Dma, Instance);
278
279/// Global interrupt handler.
280pub struct GlobalInterruptHandler<T: Instance> {
281 _phantom: PhantomData<T>,
282}
283
284impl<T: Instance> interrupt::typelevel::Handler<T::GlobalInterrupt> for GlobalInterruptHandler<T> {
285 unsafe fn on_interrupt() {
286 T::state().waker.wake();
287
288 let regs = T::info().regs;
289 let sr = regs.sr().read();
290
291 if sr.serr() || sr.terr() || sr.ferr() {
292 trace!("SPDIFRX error, resync");
293
294 // Clear errors by disabling SPDIFRX, then reenable.
295 regs.cr().modify(|cr| cr.set_spdifen(0x00));
296 regs.cr().modify(|cr| cr.set_spdifen(0x03));
297 } else if sr.syncd() {
298 // Synchronization was successful.
299 trace!("SPDIFRX sync success");
300 }
301
302 // Clear interrupt flags.
303 regs.ifcr().write(|ifcr| {
304 ifcr.set_perrcf(true); // Clears parity error flag.
305 ifcr.set_ovrcf(true); // Clears overrun error flag.
306 ifcr.set_sbdcf(true); // Clears synchronization block detected flag.
307 ifcr.set_syncdcf(true); // Clears SYNCD from SR (was read above).
308 });
309 }
310}
311
312foreach_peripheral!(
313 (spdifrx, $inst:ident) => {
314 #[allow(private_interfaces)]
315 impl SealedInstance for peripherals::$inst {
316 fn info() -> &'static Info {
317 static INFO: Info = Info{
318 regs: crate::pac::$inst,
319 rcc: crate::peripherals::$inst::RCC_INFO,
320 };
321 &INFO
322 }
323 fn state() -> &'static State {
324 static STATE: State = State::new();
325 &STATE
326 }
327 }
328
329 impl Instance for peripherals::$inst {
330 type GlobalInterrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL;
331 }
332 };
333);
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 20718147a..9e2ba093a 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -6,7 +6,6 @@ use core::ptr;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_hal_internal::PeripheralRef;
10pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
11 10
12use crate::dma::{word, ChannelAndRequest}; 11use crate::dma::{word, ChannelAndRequest};
@@ -15,7 +14,7 @@ use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::spi::{regs, vals, Spi as Regs}; 14use crate::pac::spi::{regs, vals, Spi as Regs};
16use crate::rcc::{RccInfo, SealedRccPeripheral}; 15use crate::rcc::{RccInfo, SealedRccPeripheral};
17use crate::time::Hertz; 16use crate::time::Hertz;
18use crate::Peripheral; 17use crate::Peri;
19 18
20/// SPI error. 19/// SPI error.
21#[derive(Debug, PartialEq, Eq, Clone, Copy)] 20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -31,6 +30,21 @@ pub enum Error {
31 Overrun, 30 Overrun,
32} 31}
33 32
33impl core::fmt::Display for Error {
34 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
35 let message = match self {
36 Self::Framing => "Invalid Framing",
37 Self::Crc => "Hardware CRC Check Failed",
38 Self::ModeFault => "Mode Fault",
39 Self::Overrun => "Buffer Overrun",
40 };
41
42 write!(f, "{}", message)
43 }
44}
45
46impl core::error::Error for Error {}
47
34/// SPI bit order 48/// SPI bit order
35#[derive(Copy, Clone)] 49#[derive(Copy, Clone)]
36pub enum BitOrder { 50pub enum BitOrder {
@@ -55,6 +69,9 @@ pub struct Config {
55 /// There are some ICs that require a pull-up on the MISO pin for some applications. 69 /// There are some ICs that require a pull-up on the MISO pin for some applications.
56 /// If you are unsure, you probably don't need this. 70 /// If you are unsure, you probably don't need this.
57 pub miso_pull: Pull, 71 pub miso_pull: Pull,
72 /// signal rise/fall speed (slew rate) - defaults to `Medium`.
73 /// Increase for high SPI speeds. Change to `Low` to reduce ringing.
74 pub rise_fall_speed: Speed,
58} 75}
59 76
60impl Default for Config { 77impl Default for Config {
@@ -64,6 +81,7 @@ impl Default for Config {
64 bit_order: BitOrder::MsbFirst, 81 bit_order: BitOrder::MsbFirst,
65 frequency: Hertz(1_000_000), 82 frequency: Hertz(1_000_000),
66 miso_pull: Pull::None, 83 miso_pull: Pull::None,
84 rise_fall_speed: Speed::VeryHigh,
67 } 85 }
68 } 86 }
69} 87}
@@ -71,15 +89,15 @@ impl Default for Config {
71impl Config { 89impl Config {
72 fn raw_phase(&self) -> vals::Cpha { 90 fn raw_phase(&self) -> vals::Cpha {
73 match self.mode.phase { 91 match self.mode.phase {
74 Phase::CaptureOnSecondTransition => vals::Cpha::SECONDEDGE, 92 Phase::CaptureOnSecondTransition => vals::Cpha::SECOND_EDGE,
75 Phase::CaptureOnFirstTransition => vals::Cpha::FIRSTEDGE, 93 Phase::CaptureOnFirstTransition => vals::Cpha::FIRST_EDGE,
76 } 94 }
77 } 95 }
78 96
79 fn raw_polarity(&self) -> vals::Cpol { 97 fn raw_polarity(&self) -> vals::Cpol {
80 match self.mode.polarity { 98 match self.mode.polarity {
81 Polarity::IdleHigh => vals::Cpol::IDLEHIGH, 99 Polarity::IdleHigh => vals::Cpol::IDLE_HIGH,
82 Polarity::IdleLow => vals::Cpol::IDLELOW, 100 Polarity::IdleLow => vals::Cpol::IDLE_LOW,
83 } 101 }
84 } 102 }
85 103
@@ -92,14 +110,14 @@ impl Config {
92 110
93 #[cfg(gpio_v1)] 111 #[cfg(gpio_v1)]
94 fn sck_af(&self) -> AfType { 112 fn sck_af(&self) -> AfType {
95 AfType::output(OutputType::PushPull, Speed::VeryHigh) 113 AfType::output(OutputType::PushPull, self.rise_fall_speed)
96 } 114 }
97 115
98 #[cfg(gpio_v2)] 116 #[cfg(gpio_v2)]
99 fn sck_af(&self) -> AfType { 117 fn sck_af(&self) -> AfType {
100 AfType::output_pull( 118 AfType::output_pull(
101 OutputType::PushPull, 119 OutputType::PushPull,
102 Speed::VeryHigh, 120 self.rise_fall_speed,
103 match self.mode.polarity { 121 match self.mode.polarity {
104 Polarity::IdleLow => Pull::Down, 122 Polarity::IdleLow => Pull::Down,
105 Polarity::IdleHigh => Pull::Up, 123 Polarity::IdleHigh => Pull::Up,
@@ -111,21 +129,22 @@ impl Config {
111pub struct Spi<'d, M: PeriMode> { 129pub struct Spi<'d, M: PeriMode> {
112 pub(crate) info: &'static Info, 130 pub(crate) info: &'static Info,
113 kernel_clock: Hertz, 131 kernel_clock: Hertz,
114 sck: Option<PeripheralRef<'d, AnyPin>>, 132 sck: Option<Peri<'d, AnyPin>>,
115 mosi: Option<PeripheralRef<'d, AnyPin>>, 133 mosi: Option<Peri<'d, AnyPin>>,
116 miso: Option<PeripheralRef<'d, AnyPin>>, 134 miso: Option<Peri<'d, AnyPin>>,
117 tx_dma: Option<ChannelAndRequest<'d>>, 135 tx_dma: Option<ChannelAndRequest<'d>>,
118 rx_dma: Option<ChannelAndRequest<'d>>, 136 rx_dma: Option<ChannelAndRequest<'d>>,
119 _phantom: PhantomData<M>, 137 _phantom: PhantomData<M>,
120 current_word_size: word_impl::Config, 138 current_word_size: word_impl::Config,
139 rise_fall_speed: Speed,
121} 140}
122 141
123impl<'d, M: PeriMode> Spi<'d, M> { 142impl<'d, M: PeriMode> Spi<'d, M> {
124 fn new_inner<T: Instance>( 143 fn new_inner<T: Instance>(
125 _peri: impl Peripheral<P = T> + 'd, 144 _peri: Peri<'d, T>,
126 sck: Option<PeripheralRef<'d, AnyPin>>, 145 sck: Option<Peri<'d, AnyPin>>,
127 mosi: Option<PeripheralRef<'d, AnyPin>>, 146 mosi: Option<Peri<'d, AnyPin>>,
128 miso: Option<PeripheralRef<'d, AnyPin>>, 147 miso: Option<Peri<'d, AnyPin>>,
129 tx_dma: Option<ChannelAndRequest<'d>>, 148 tx_dma: Option<ChannelAndRequest<'d>>,
130 rx_dma: Option<ChannelAndRequest<'d>>, 149 rx_dma: Option<ChannelAndRequest<'d>>,
131 config: Config, 150 config: Config,
@@ -140,6 +159,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
140 rx_dma, 159 rx_dma,
141 current_word_size: <u8 as SealedWord>::CONFIG, 160 current_word_size: <u8 as SealedWord>::CONFIG,
142 _phantom: PhantomData, 161 _phantom: PhantomData,
162 rise_fall_speed: config.rise_fall_speed,
143 }; 163 };
144 this.enable_and_init(config); 164 this.enable_and_init(config);
145 this 165 this
@@ -174,7 +194,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
174 // we're doing "fake rxonly", by actually writing one 194 // we're doing "fake rxonly", by actually writing one
175 // byte to TXDR for each byte we want to receive. if we 195 // byte to TXDR for each byte we want to receive. if we
176 // set OUTPUTDISABLED here, this hangs. 196 // set OUTPUTDISABLED here, this hangs.
177 w.set_rxonly(vals::Rxonly::FULLDUPLEX); 197 w.set_rxonly(vals::Rxonly::FULL_DUPLEX);
178 w.set_dff(<u8 as SealedWord>::CONFIG) 198 w.set_dff(<u8 as SealedWord>::CONFIG)
179 }); 199 });
180 } 200 }
@@ -211,18 +231,18 @@ impl<'d, M: PeriMode> Spi<'d, M> {
211 w.set_lsbfirst(lsbfirst); 231 w.set_lsbfirst(lsbfirst);
212 w.set_ssm(true); 232 w.set_ssm(true);
213 w.set_master(vals::Master::MASTER); 233 w.set_master(vals::Master::MASTER);
214 w.set_comm(vals::Comm::FULLDUPLEX); 234 w.set_comm(vals::Comm::FULL_DUPLEX);
215 w.set_ssom(vals::Ssom::ASSERTED); 235 w.set_ssom(vals::Ssom::ASSERTED);
216 w.set_midi(0); 236 w.set_midi(0);
217 w.set_mssi(0); 237 w.set_mssi(0);
218 w.set_afcntr(true); 238 w.set_afcntr(true);
219 w.set_ssiop(vals::Ssiop::ACTIVEHIGH); 239 w.set_ssiop(vals::Ssiop::ACTIVE_HIGH);
220 }); 240 });
221 regs.cfg1().modify(|w| { 241 regs.cfg1().modify(|w| {
222 w.set_crcen(false); 242 w.set_crcen(false);
223 w.set_mbr(br); 243 w.set_mbr(br);
224 w.set_dsize(<u8 as SealedWord>::CONFIG); 244 w.set_dsize(<u8 as SealedWord>::CONFIG);
225 w.set_fthlv(vals::Fthlv::ONEFRAME); 245 w.set_fthlv(vals::Fthlv::ONE_FRAME);
226 }); 246 });
227 regs.cr2().modify(|w| { 247 regs.cr2().modify(|w| {
228 w.set_tsize(0); 248 w.set_tsize(0);
@@ -243,6 +263,17 @@ impl<'d, M: PeriMode> Spi<'d, M> {
243 263
244 let br = compute_baud_rate(self.kernel_clock, config.frequency); 264 let br = compute_baud_rate(self.kernel_clock, config.frequency);
245 265
266 #[cfg(gpio_v2)]
267 {
268 self.rise_fall_speed = config.rise_fall_speed;
269 if let Some(sck) = self.sck.as_ref() {
270 sck.set_speed(config.rise_fall_speed);
271 }
272 if let Some(mosi) = self.mosi.as_ref() {
273 mosi.set_speed(config.rise_fall_speed);
274 }
275 }
276
246 #[cfg(any(spi_v1, spi_f1, spi_v2))] 277 #[cfg(any(spi_v1, spi_f1, spi_v2))]
247 self.info.regs.cr1().modify(|w| { 278 self.info.regs.cr1().modify(|w| {
248 w.set_cpha(cpha); 279 w.set_cpha(cpha);
@@ -253,6 +284,10 @@ impl<'d, M: PeriMode> Spi<'d, M> {
253 284
254 #[cfg(any(spi_v3, spi_v4, spi_v5))] 285 #[cfg(any(spi_v3, spi_v4, spi_v5))]
255 { 286 {
287 self.info.regs.cr1().modify(|w| {
288 w.set_spe(false);
289 });
290
256 self.info.regs.cfg2().modify(|w| { 291 self.info.regs.cfg2().modify(|w| {
257 w.set_cpha(cpha); 292 w.set_cpha(cpha);
258 w.set_cpol(cpol); 293 w.set_cpol(cpol);
@@ -261,6 +296,10 @@ impl<'d, M: PeriMode> Spi<'d, M> {
261 self.info.regs.cfg1().modify(|w| { 296 self.info.regs.cfg1().modify(|w| {
262 w.set_mbr(br); 297 w.set_mbr(br);
263 }); 298 });
299
300 self.info.regs.cr1().modify(|w| {
301 w.set_spe(true);
302 });
264 } 303 }
265 Ok(()) 304 Ok(())
266 } 305 }
@@ -274,12 +313,12 @@ impl<'d, M: PeriMode> Spi<'d, M> {
274 #[cfg(any(spi_v3, spi_v4, spi_v5))] 313 #[cfg(any(spi_v3, spi_v4, spi_v5))]
275 let cfg1 = self.info.regs.cfg1().read(); 314 let cfg1 = self.info.regs.cfg1().read();
276 315
277 let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { 316 let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW {
278 Polarity::IdleLow 317 Polarity::IdleLow
279 } else { 318 } else {
280 Polarity::IdleHigh 319 Polarity::IdleHigh
281 }; 320 };
282 let phase = if cfg.cpha() == vals::Cpha::FIRSTEDGE { 321 let phase = if cfg.cpha() == vals::Cpha::FIRST_EDGE {
283 Phase::CaptureOnFirstTransition 322 Phase::CaptureOnFirstTransition
284 } else { 323 } else {
285 Phase::CaptureOnSecondTransition 324 Phase::CaptureOnSecondTransition
@@ -308,54 +347,32 @@ impl<'d, M: PeriMode> Spi<'d, M> {
308 bit_order, 347 bit_order,
309 frequency, 348 frequency,
310 miso_pull, 349 miso_pull,
350 rise_fall_speed: self.rise_fall_speed,
311 } 351 }
312 } 352 }
313 353
314 fn set_word_size(&mut self, word_size: word_impl::Config) { 354 pub(crate) fn set_word_size(&mut self, word_size: word_impl::Config) {
315 if self.current_word_size == word_size { 355 if self.current_word_size == word_size {
316 return; 356 return;
317 } 357 }
318 358
359 self.info.regs.cr1().modify(|w| {
360 w.set_spe(false);
361 });
362
319 #[cfg(any(spi_v1, spi_f1))] 363 #[cfg(any(spi_v1, spi_f1))]
320 { 364 self.info.regs.cr1().modify(|reg| {
321 self.info.regs.cr1().modify(|reg| { 365 reg.set_dff(word_size);
322 reg.set_spe(false); 366 });
323 reg.set_dff(word_size)
324 });
325 self.info.regs.cr1().modify(|reg| {
326 reg.set_spe(true);
327 });
328 }
329 #[cfg(spi_v2)] 367 #[cfg(spi_v2)]
330 { 368 self.info.regs.cr2().modify(|w| {
331 self.info.regs.cr1().modify(|w| { 369 w.set_frxth(word_size.1);
332 w.set_spe(false); 370 w.set_ds(word_size.0);
333 }); 371 });
334 self.info.regs.cr2().modify(|w| {
335 w.set_frxth(word_size.1);
336 w.set_ds(word_size.0);
337 });
338 self.info.regs.cr1().modify(|w| {
339 w.set_spe(true);
340 });
341 }
342 #[cfg(any(spi_v3, spi_v4, spi_v5))] 372 #[cfg(any(spi_v3, spi_v4, spi_v5))]
343 { 373 self.info.regs.cfg1().modify(|w| {
344 self.info.regs.cr1().modify(|w| { 374 w.set_dsize(word_size);
345 w.set_csusp(true); 375 });
346 });
347 while self.info.regs.sr().read().eot() {}
348 self.info.regs.cr1().modify(|w| {
349 w.set_spe(false);
350 });
351 self.info.regs.cfg1().modify(|w| {
352 w.set_dsize(word_size);
353 });
354 self.info.regs.cr1().modify(|w| {
355 w.set_csusp(false);
356 w.set_spe(true);
357 });
358 }
359 376
360 self.current_word_size = word_size; 377 self.current_word_size = word_size;
361 } 378 }
@@ -365,9 +382,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
365 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 382 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
366 #[cfg(any(spi_v3, spi_v4, spi_v5))] 383 #[cfg(any(spi_v3, spi_v4, spi_v5))]
367 self.info.regs.cr1().modify(|w| w.set_spe(false)); 384 self.info.regs.cr1().modify(|w| w.set_spe(false));
385 self.set_word_size(W::CONFIG);
368 self.info.regs.cr1().modify(|w| w.set_spe(true)); 386 self.info.regs.cr1().modify(|w| w.set_spe(true));
369 flush_rx_fifo(self.info.regs); 387 flush_rx_fifo(self.info.regs);
370 self.set_word_size(W::CONFIG);
371 for word in words.iter() { 388 for word in words.iter() {
372 // this cannot use `transfer_word` because on SPIv2 and higher, 389 // this cannot use `transfer_word` because on SPIv2 and higher,
373 // the SPI RX state machine hangs if no physical pin is connected to the SCK AF. 390 // the SPI RX state machine hangs if no physical pin is connected to the SCK AF.
@@ -402,9 +419,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
402 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 419 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
403 #[cfg(any(spi_v3, spi_v4, spi_v5))] 420 #[cfg(any(spi_v3, spi_v4, spi_v5))]
404 self.info.regs.cr1().modify(|w| w.set_spe(false)); 421 self.info.regs.cr1().modify(|w| w.set_spe(false));
422 self.set_word_size(W::CONFIG);
405 self.info.regs.cr1().modify(|w| w.set_spe(true)); 423 self.info.regs.cr1().modify(|w| w.set_spe(true));
406 flush_rx_fifo(self.info.regs); 424 flush_rx_fifo(self.info.regs);
407 self.set_word_size(W::CONFIG);
408 for word in words.iter_mut() { 425 for word in words.iter_mut() {
409 *word = transfer_word(self.info.regs, W::default())?; 426 *word = transfer_word(self.info.regs, W::default())?;
410 } 427 }
@@ -418,9 +435,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
418 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 435 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
419 #[cfg(any(spi_v3, spi_v4, spi_v5))] 436 #[cfg(any(spi_v3, spi_v4, spi_v5))]
420 self.info.regs.cr1().modify(|w| w.set_spe(false)); 437 self.info.regs.cr1().modify(|w| w.set_spe(false));
438 self.set_word_size(W::CONFIG);
421 self.info.regs.cr1().modify(|w| w.set_spe(true)); 439 self.info.regs.cr1().modify(|w| w.set_spe(true));
422 flush_rx_fifo(self.info.regs); 440 flush_rx_fifo(self.info.regs);
423 self.set_word_size(W::CONFIG);
424 for word in words.iter_mut() { 441 for word in words.iter_mut() {
425 *word = transfer_word(self.info.regs, *word)?; 442 *word = transfer_word(self.info.regs, *word)?;
426 } 443 }
@@ -437,9 +454,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
437 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 454 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
438 #[cfg(any(spi_v3, spi_v4, spi_v5))] 455 #[cfg(any(spi_v3, spi_v4, spi_v5))]
439 self.info.regs.cr1().modify(|w| w.set_spe(false)); 456 self.info.regs.cr1().modify(|w| w.set_spe(false));
457 self.set_word_size(W::CONFIG);
440 self.info.regs.cr1().modify(|w| w.set_spe(true)); 458 self.info.regs.cr1().modify(|w| w.set_spe(true));
441 flush_rx_fifo(self.info.regs); 459 flush_rx_fifo(self.info.regs);
442 self.set_word_size(W::CONFIG);
443 let len = read.len().max(write.len()); 460 let len = read.len().max(write.len());
444 for i in 0..len { 461 for i in 0..len {
445 let wb = write.get(i).copied().unwrap_or_default(); 462 let wb = write.get(i).copied().unwrap_or_default();
@@ -455,16 +472,16 @@ impl<'d, M: PeriMode> Spi<'d, M> {
455impl<'d> Spi<'d, Blocking> { 472impl<'d> Spi<'d, Blocking> {
456 /// Create a new blocking SPI driver. 473 /// Create a new blocking SPI driver.
457 pub fn new_blocking<T: Instance>( 474 pub fn new_blocking<T: Instance>(
458 peri: impl Peripheral<P = T> + 'd, 475 peri: Peri<'d, T>,
459 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 476 sck: Peri<'d, impl SckPin<T>>,
460 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 477 mosi: Peri<'d, impl MosiPin<T>>,
461 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 478 miso: Peri<'d, impl MisoPin<T>>,
462 config: Config, 479 config: Config,
463 ) -> Self { 480 ) -> Self {
464 Self::new_inner( 481 Self::new_inner(
465 peri, 482 peri,
466 new_pin!(sck, config.sck_af()), 483 new_pin!(sck, config.sck_af()),
467 new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 484 new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)),
468 new_pin!(miso, AfType::input(config.miso_pull)), 485 new_pin!(miso, AfType::input(config.miso_pull)),
469 None, 486 None,
470 None, 487 None,
@@ -474,9 +491,9 @@ impl<'d> Spi<'d, Blocking> {
474 491
475 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI). 492 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
476 pub fn new_blocking_rxonly<T: Instance>( 493 pub fn new_blocking_rxonly<T: Instance>(
477 peri: impl Peripheral<P = T> + 'd, 494 peri: Peri<'d, T>,
478 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 495 sck: Peri<'d, impl SckPin<T>>,
479 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 496 miso: Peri<'d, impl MisoPin<T>>,
480 config: Config, 497 config: Config,
481 ) -> Self { 498 ) -> Self {
482 Self::new_inner( 499 Self::new_inner(
@@ -492,15 +509,15 @@ impl<'d> Spi<'d, Blocking> {
492 509
493 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO). 510 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
494 pub fn new_blocking_txonly<T: Instance>( 511 pub fn new_blocking_txonly<T: Instance>(
495 peri: impl Peripheral<P = T> + 'd, 512 peri: Peri<'d, T>,
496 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 513 sck: Peri<'d, impl SckPin<T>>,
497 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 514 mosi: Peri<'d, impl MosiPin<T>>,
498 config: Config, 515 config: Config,
499 ) -> Self { 516 ) -> Self {
500 Self::new_inner( 517 Self::new_inner(
501 peri, 518 peri,
502 new_pin!(sck, config.sck_af()), 519 new_pin!(sck, config.sck_af()),
503 new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 520 new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)),
504 None, 521 None,
505 None, 522 None,
506 None, 523 None,
@@ -512,14 +529,14 @@ impl<'d> Spi<'d, Blocking> {
512 /// 529 ///
513 /// This can be useful for bit-banging non-SPI protocols. 530 /// This can be useful for bit-banging non-SPI protocols.
514 pub fn new_blocking_txonly_nosck<T: Instance>( 531 pub fn new_blocking_txonly_nosck<T: Instance>(
515 peri: impl Peripheral<P = T> + 'd, 532 peri: Peri<'d, T>,
516 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 533 mosi: Peri<'d, impl MosiPin<T>>,
517 config: Config, 534 config: Config,
518 ) -> Self { 535 ) -> Self {
519 Self::new_inner( 536 Self::new_inner(
520 peri, 537 peri,
521 None, 538 None,
522 new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 539 new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)),
523 None, 540 None,
524 None, 541 None,
525 None, 542 None,
@@ -531,18 +548,18 @@ impl<'d> Spi<'d, Blocking> {
531impl<'d> Spi<'d, Async> { 548impl<'d> Spi<'d, Async> {
532 /// Create a new SPI driver. 549 /// Create a new SPI driver.
533 pub fn new<T: Instance>( 550 pub fn new<T: Instance>(
534 peri: impl Peripheral<P = T> + 'd, 551 peri: Peri<'d, T>,
535 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 552 sck: Peri<'d, impl SckPin<T>>,
536 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 553 mosi: Peri<'d, impl MosiPin<T>>,
537 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 554 miso: Peri<'d, impl MisoPin<T>>,
538 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 555 tx_dma: Peri<'d, impl TxDma<T>>,
539 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 556 rx_dma: Peri<'d, impl RxDma<T>>,
540 config: Config, 557 config: Config,
541 ) -> Self { 558 ) -> Self {
542 Self::new_inner( 559 Self::new_inner(
543 peri, 560 peri,
544 new_pin!(sck, config.sck_af()), 561 new_pin!(sck, config.sck_af()),
545 new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)),
546 new_pin!(miso, AfType::input(config.miso_pull)), 563 new_pin!(miso, AfType::input(config.miso_pull)),
547 new_dma!(tx_dma), 564 new_dma!(tx_dma),
548 new_dma!(rx_dma), 565 new_dma!(rx_dma),
@@ -552,11 +569,11 @@ impl<'d> Spi<'d, Async> {
552 569
553 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). 570 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
554 pub fn new_rxonly<T: Instance>( 571 pub fn new_rxonly<T: Instance>(
555 peri: impl Peripheral<P = T> + 'd, 572 peri: Peri<'d, T>,
556 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 573 sck: Peri<'d, impl SckPin<T>>,
557 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 574 miso: Peri<'d, impl MisoPin<T>>,
558 #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 575 #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: Peri<'d, impl TxDma<T>>,
559 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 576 rx_dma: Peri<'d, impl RxDma<T>>,
560 config: Config, 577 config: Config,
561 ) -> Self { 578 ) -> Self {
562 Self::new_inner( 579 Self::new_inner(
@@ -575,16 +592,16 @@ impl<'d> Spi<'d, Async> {
575 592
576 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). 593 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
577 pub fn new_txonly<T: Instance>( 594 pub fn new_txonly<T: Instance>(
578 peri: impl Peripheral<P = T> + 'd, 595 peri: Peri<'d, T>,
579 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 596 sck: Peri<'d, impl SckPin<T>>,
580 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 597 mosi: Peri<'d, impl MosiPin<T>>,
581 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 598 tx_dma: Peri<'d, impl TxDma<T>>,
582 config: Config, 599 config: Config,
583 ) -> Self { 600 ) -> Self {
584 Self::new_inner( 601 Self::new_inner(
585 peri, 602 peri,
586 new_pin!(sck, config.sck_af()), 603 new_pin!(sck, config.sck_af()),
587 new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)),
588 None, 605 None,
589 new_dma!(tx_dma), 606 new_dma!(tx_dma),
590 None, 607 None,
@@ -596,15 +613,15 @@ impl<'d> Spi<'d, Async> {
596 /// 613 ///
597 /// This can be useful for bit-banging non-SPI protocols. 614 /// This can be useful for bit-banging non-SPI protocols.
598 pub fn new_txonly_nosck<T: Instance>( 615 pub fn new_txonly_nosck<T: Instance>(
599 peri: impl Peripheral<P = T> + 'd, 616 peri: Peri<'d, T>,
600 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 617 mosi: Peri<'d, impl MosiPin<T>>,
601 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 618 tx_dma: Peri<'d, impl TxDma<T>>,
602 config: Config, 619 config: Config,
603 ) -> Self { 620 ) -> Self {
604 Self::new_inner( 621 Self::new_inner(
605 peri, 622 peri,
606 None, 623 None,
607 new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)),
608 None, 625 None,
609 new_dma!(tx_dma), 626 new_dma!(tx_dma),
610 None, 627 None,
@@ -615,9 +632,9 @@ impl<'d> Spi<'d, Async> {
615 #[cfg(stm32wl)] 632 #[cfg(stm32wl)]
616 /// Useful for on chip peripherals like SUBGHZ which are hardwired. 633 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
617 pub fn new_subghz<T: Instance>( 634 pub fn new_subghz<T: Instance>(
618 peri: impl Peripheral<P = T> + 'd, 635 peri: Peri<'d, T>,
619 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 636 tx_dma: Peri<'d, impl TxDma<T>>,
620 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 637 rx_dma: Peri<'d, impl RxDma<T>>,
621 ) -> Self { 638 ) -> Self {
622 // see RM0453 rev 1 section 7.2.13 page 291 639 // see RM0453 rev 1 section 7.2.13 page 291
623 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. 640 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
@@ -634,7 +651,7 @@ impl<'d> Spi<'d, Async> {
634 651
635 #[allow(dead_code)] 652 #[allow(dead_code)]
636 pub(crate) fn new_internal<T: Instance>( 653 pub(crate) fn new_internal<T: Instance>(
637 peri: impl Peripheral<P = T> + 'd, 654 peri: Peri<'d, T>,
638 tx_dma: Option<ChannelAndRequest<'d>>, 655 tx_dma: Option<ChannelAndRequest<'d>>,
639 rx_dma: Option<ChannelAndRequest<'d>>, 656 rx_dma: Option<ChannelAndRequest<'d>>,
640 config: Config, 657 config: Config,
@@ -648,10 +665,10 @@ impl<'d> Spi<'d, Async> {
648 return Ok(()); 665 return Ok(());
649 } 666 }
650 667
651 self.set_word_size(W::CONFIG);
652 self.info.regs.cr1().modify(|w| { 668 self.info.regs.cr1().modify(|w| {
653 w.set_spe(false); 669 w.set_spe(false);
654 }); 670 });
671 self.set_word_size(W::CONFIG);
655 672
656 let tx_dst = self.info.regs.tx_ptr(); 673 let tx_dst = self.info.regs.tx_ptr();
657 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) }; 674 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
@@ -685,6 +702,8 @@ impl<'d> Spi<'d, Async> {
685 w.set_spe(false); 702 w.set_spe(false);
686 }); 703 });
687 704
705 self.set_word_size(W::CONFIG);
706
688 let comm = regs.cfg2().modify(|w| { 707 let comm = regs.cfg2().modify(|w| {
689 let prev = w.comm(); 708 let prev = w.comm();
690 w.set_comm(vals::Comm::RECEIVER); 709 w.set_comm(vals::Comm::RECEIVER);
@@ -696,8 +715,8 @@ impl<'d> Spi<'d, Async> {
696 w.i2smod().then(|| { 715 w.i2smod().then(|| {
697 let prev = w.i2scfg(); 716 let prev = w.i2scfg();
698 w.set_i2scfg(match prev { 717 w.set_i2scfg(match prev {
699 vals::I2scfg::SLAVERX | vals::I2scfg::SLAVEFULLDUPLEX => vals::I2scfg::SLAVERX, 718 vals::I2scfg::SLAVE_RX | vals::I2scfg::SLAVE_FULL_DUPLEX => vals::I2scfg::SLAVE_RX,
700 vals::I2scfg::MASTERRX | vals::I2scfg::MASTERFULLDUPLEX => vals::I2scfg::MASTERRX, 719 vals::I2scfg::MASTER_RX | vals::I2scfg::MASTER_FULL_DUPLEX => vals::I2scfg::MASTER_RX,
701 _ => panic!("unsupported configuration"), 720 _ => panic!("unsupported configuration"),
702 }); 721 });
703 prev 722 prev
@@ -707,7 +726,6 @@ impl<'d> Spi<'d, Async> {
707 let rx_src = regs.rx_ptr(); 726 let rx_src = regs.rx_ptr();
708 727
709 for mut chunk in data.chunks_mut(u16::max_value().into()) { 728 for mut chunk in data.chunks_mut(u16::max_value().into()) {
710 self.set_word_size(W::CONFIG);
711 set_rxdmaen(regs, true); 729 set_rxdmaen(regs, true);
712 730
713 let tsize = chunk.len(); 731 let tsize = chunk.len();
@@ -765,12 +783,12 @@ impl<'d> Spi<'d, Async> {
765 return Ok(()); 783 return Ok(());
766 } 784 }
767 785
768 self.set_word_size(W::CONFIG);
769
770 self.info.regs.cr1().modify(|w| { 786 self.info.regs.cr1().modify(|w| {
771 w.set_spe(false); 787 w.set_spe(false);
772 }); 788 });
773 789
790 self.set_word_size(W::CONFIG);
791
774 // SPIv3 clears rxfifo on SPE=0 792 // SPIv3 clears rxfifo on SPE=0
775 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 793 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
776 flush_rx_fifo(self.info.regs); 794 flush_rx_fifo(self.info.regs);
@@ -783,7 +801,7 @@ impl<'d> Spi<'d, Async> {
783 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) }; 801 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
784 802
785 let tx_dst = self.info.regs.tx_ptr(); 803 let tx_dst = self.info.regs.tx_ptr();
786 let clock_byte = 0x00u8; 804 let clock_byte = W::default();
787 let tx_f = unsafe { 805 let tx_f = unsafe {
788 self.tx_dma 806 self.tx_dma
789 .as_mut() 807 .as_mut()
@@ -813,11 +831,12 @@ impl<'d> Spi<'d, Async> {
813 return Ok(()); 831 return Ok(());
814 } 832 }
815 833
816 self.set_word_size(W::CONFIG);
817 self.info.regs.cr1().modify(|w| { 834 self.info.regs.cr1().modify(|w| {
818 w.set_spe(false); 835 w.set_spe(false);
819 }); 836 });
820 837
838 self.set_word_size(W::CONFIG);
839
821 // SPIv3 clears rxfifo on SPE=0 840 // SPIv3 clears rxfifo on SPE=0
822 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 841 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
823 flush_rx_fifo(self.info.regs); 842 flush_rx_fifo(self.info.regs);
@@ -827,7 +846,7 @@ impl<'d> Spi<'d, Async> {
827 let rx_src = self.info.regs.rx_ptr(); 846 let rx_src = self.info.regs.rx_ptr();
828 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; 847 let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
829 848
830 let tx_dst = self.info.regs.tx_ptr(); 849 let tx_dst: *mut W = self.info.regs.tx_ptr();
831 let tx_f = unsafe { 850 let tx_f = unsafe {
832 self.tx_dma 851 self.tx_dma
833 .as_mut() 852 .as_mut()
@@ -915,7 +934,7 @@ fn compute_frequency(kernel_clock: Hertz, br: Br) -> Hertz {
915 kernel_clock / div 934 kernel_clock / div
916} 935}
917 936
918trait RegsExt { 937pub(crate) trait RegsExt {
919 fn tx_ptr<W>(&self) -> *mut W; 938 fn tx_ptr<W>(&self) -> *mut W;
920 fn rx_ptr<W>(&self) -> *mut W; 939 fn rx_ptr<W>(&self) -> *mut W;
921} 940}
@@ -1003,7 +1022,7 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
1003 } 1022 }
1004} 1023}
1005 1024
1006fn flush_rx_fifo(regs: Regs) { 1025pub(crate) fn flush_rx_fifo(regs: Regs) {
1007 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 1026 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1008 while regs.sr().read().rxne() { 1027 while regs.sr().read().rxne() {
1009 #[cfg(not(spi_v2))] 1028 #[cfg(not(spi_v2))]
@@ -1017,7 +1036,7 @@ fn flush_rx_fifo(regs: Regs) {
1017 } 1036 }
1018} 1037}
1019 1038
1020fn set_txdmaen(regs: Regs, val: bool) { 1039pub(crate) fn set_txdmaen(regs: Regs, val: bool) {
1021 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 1040 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1022 regs.cr2().modify(|reg| { 1041 regs.cr2().modify(|reg| {
1023 reg.set_txdmaen(val); 1042 reg.set_txdmaen(val);
@@ -1028,7 +1047,7 @@ fn set_txdmaen(regs: Regs, val: bool) {
1028 }); 1047 });
1029} 1048}
1030 1049
1031fn set_rxdmaen(regs: Regs, val: bool) { 1050pub(crate) fn set_rxdmaen(regs: Regs, val: bool) {
1032 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 1051 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
1033 regs.cr2().modify(|reg| { 1052 regs.cr2().modify(|reg| {
1034 reg.set_rxdmaen(val); 1053 reg.set_rxdmaen(val);
@@ -1189,13 +1208,13 @@ impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> {
1189 } 1208 }
1190} 1209}
1191 1210
1192trait SealedWord { 1211pub(crate) trait SealedWord {
1193 const CONFIG: word_impl::Config; 1212 const CONFIG: word_impl::Config;
1194} 1213}
1195 1214
1196/// Word sizes usable for SPI. 1215/// Word sizes usable for SPI.
1197#[allow(private_bounds)] 1216#[allow(private_bounds)]
1198pub trait Word: word::Word + SealedWord {} 1217pub trait Word: word::Word + SealedWord + Default {}
1199 1218
1200macro_rules! impl_word { 1219macro_rules! impl_word {
1201 ($T:ty, $config:expr) => { 1220 ($T:ty, $config:expr) => {
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index 802ff41ce..532877f70 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -1,12 +1,25 @@
1//! Time units 1//! Time units
2 2
3use core::fmt::Display;
3use core::ops::{Div, Mul}; 4use core::ops::{Div, Mul};
4 5
5/// Hertz 6/// Hertz
6#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] 7#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub struct Hertz(pub u32); 8pub struct Hertz(pub u32);
9 9
10impl Display for Hertz {
11 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12 write!(f, "{} Hz", self.0)
13 }
14}
15
16#[cfg(feature = "defmt")]
17impl defmt::Format for Hertz {
18 fn format(&self, f: defmt::Formatter) {
19 defmt::write!(f, "{=u32} Hz", self.0)
20 }
21}
22
10impl Hertz { 23impl Hertz {
11 /// Create a `Hertz` from the given hertz. 24 /// Create a `Hertz` from the given hertz.
12 pub const fn hz(hertz: u32) -> Self { 25 pub const fn hz(hertz: u32) -> Self {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index f8041bf1e..7db74bdf6 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -1,13 +1,13 @@
1#![allow(non_snake_case)] 1#![allow(non_snake_case)]
2 2
3use core::cell::Cell; 3use core::cell::{Cell, RefCell};
4use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; 4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
5use core::{mem, ptr};
6 5
7use critical_section::CriticalSection; 6use critical_section::CriticalSection;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::blocking_mutex::Mutex; 8use embassy_sync::blocking_mutex::Mutex;
10use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; 9use embassy_time_driver::{Driver, TICK_HZ};
10use embassy_time_queue_utils::Queue;
11use stm32_metapac::timer::{regs, TimGp16}; 11use stm32_metapac::timer::{regs, TimGp16};
12 12
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
@@ -24,18 +24,6 @@ use crate::{interrupt, peripherals};
24// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST 24// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST
25// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not 25// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not
26// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.) 26// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.)
27//
28// The values of ALARM_COUNT below are not the TOTAL CC registers available, but rather the number
29// available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers:
30// CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3.
31
32cfg_if::cfg_if! {
33 if #[cfg(any(time_driver_tim9, time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] {
34 const ALARM_COUNT: usize = 1;
35 } else {
36 const ALARM_COUNT: usize = 3;
37 }
38}
39 27
40#[cfg(time_driver_tim1)] 28#[cfg(time_driver_tim1)]
41type T = peripherals::TIM1; 29type T = peripherals::TIM1;
@@ -75,14 +63,6 @@ foreach_interrupt! {
75 DRIVER.on_interrupt() 63 DRIVER.on_interrupt()
76 } 64 }
77 }; 65 };
78 (TIM1, timer, $block:ident, CC, $irq:ident) => {
79 #[cfg(time_driver_tim1)]
80 #[cfg(feature = "rt")]
81 #[interrupt]
82 fn $irq() {
83 DRIVER.on_interrupt()
84 }
85 };
86 (TIM2, timer, $block:ident, CC, $irq:ident) => { 66 (TIM2, timer, $block:ident, CC, $irq:ident) => {
87 #[cfg(time_driver_tim2)] 67 #[cfg(time_driver_tim2)]
88 #[cfg(feature = "rt")] 68 #[cfg(feature = "rt")]
@@ -123,14 +103,6 @@ foreach_interrupt! {
123 DRIVER.on_interrupt() 103 DRIVER.on_interrupt()
124 } 104 }
125 }; 105 };
126 (TIM8, timer, $block:ident, CC, $irq:ident) => {
127 #[cfg(time_driver_tim8)]
128 #[cfg(feature = "rt")]
129 #[interrupt]
130 fn $irq() {
131 DRIVER.on_interrupt()
132 }
133 };
134 (TIM9, timer, $block:ident, CC, $irq:ident) => { 106 (TIM9, timer, $block:ident, CC, $irq:ident) => {
135 #[cfg(time_driver_tim9)] 107 #[cfg(time_driver_tim9)]
136 #[cfg(feature = "rt")] 108 #[cfg(feature = "rt")]
@@ -163,14 +135,6 @@ foreach_interrupt! {
163 DRIVER.on_interrupt() 135 DRIVER.on_interrupt()
164 } 136 }
165 }; 137 };
166 (TIM20, timer, $block:ident, CC, $irq:ident) => {
167 #[cfg(time_driver_tim20)]
168 #[cfg(feature = "rt")]
169 #[interrupt]
170 fn $irq() {
171 DRIVER.on_interrupt()
172 }
173 };
174 (TIM21, timer, $block:ident, CC, $irq:ident) => { 138 (TIM21, timer, $block:ident, CC, $irq:ident) => {
175 #[cfg(time_driver_tim21)] 139 #[cfg(time_driver_tim21)]
176 #[cfg(feature = "rt")] 140 #[cfg(feature = "rt")]
@@ -232,11 +196,6 @@ fn calc_now(period: u32, counter: u16) -> u64 {
232 196
233struct AlarmState { 197struct AlarmState {
234 timestamp: Cell<u64>, 198 timestamp: Cell<u64>,
235
236 // This is really a Option<(fn(*mut ()), *mut ())>
237 // but fn pointers aren't allowed in const yet
238 callback: Cell<*const ()>,
239 ctx: Cell<*mut ()>,
240} 199}
241 200
242unsafe impl Send for AlarmState {} 201unsafe impl Send for AlarmState {}
@@ -245,8 +204,6 @@ impl AlarmState {
245 const fn new() -> Self { 204 const fn new() -> Self {
246 Self { 205 Self {
247 timestamp: Cell::new(u64::MAX), 206 timestamp: Cell::new(u64::MAX),
248 callback: Cell::new(ptr::null()),
249 ctx: Cell::new(ptr::null_mut()),
250 } 207 }
251 } 208 }
252} 209}
@@ -254,22 +211,18 @@ impl AlarmState {
254pub(crate) struct RtcDriver { 211pub(crate) struct RtcDriver {
255 /// Number of 2^15 periods elapsed since boot. 212 /// Number of 2^15 periods elapsed since boot.
256 period: AtomicU32, 213 period: AtomicU32,
257 alarm_count: AtomicU8, 214 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
258 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
259 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
260 #[cfg(feature = "low-power")] 215 #[cfg(feature = "low-power")]
261 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, 216 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>,
217 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
262} 218}
263 219
264#[allow(clippy::declare_interior_mutable_const)]
265const ALARM_STATE_NEW: AlarmState = AlarmState::new();
266
267embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 220embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
268 period: AtomicU32::new(0), 221 period: AtomicU32::new(0),
269 alarm_count: AtomicU8::new(0), 222 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
270 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
271 #[cfg(feature = "low-power")] 223 #[cfg(feature = "low-power")]
272 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 224 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
225 queue: Mutex::new(RefCell::new(Queue::new()))
273}); 226});
274 227
275impl RtcDriver { 228impl RtcDriver {
@@ -293,9 +246,9 @@ impl RtcDriver {
293 r.arr().write(|w| w.set_arr(u16::MAX)); 246 r.arr().write(|w| w.set_arr(u16::MAX));
294 247
295 // Set URS, generate update and clear URS 248 // Set URS, generate update and clear URS
296 r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTERONLY)); 249 r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTER_ONLY));
297 r.egr().write(|w| w.set_ug(true)); 250 r.egr().write(|w| w.set_ug(true));
298 r.cr1().modify(|w| w.set_urs(vals::Urs::ANYEVENT)); 251 r.cr1().modify(|w| w.set_urs(vals::Urs::ANY_EVENT));
299 252
300 // Mid-way point 253 // Mid-way point
301 r.ccr(0).write(|w| w.set_ccr(0x8000)); 254 r.ccr(0).write(|w| w.set_ccr(0x8000));
@@ -315,7 +268,6 @@ impl RtcDriver {
315 fn on_interrupt(&self) { 268 fn on_interrupt(&self) {
316 let r = regs_gp16(); 269 let r = regs_gp16();
317 270
318 // XXX: reduce the size of this critical section ?
319 critical_section::with(|cs| { 271 critical_section::with(|cs| {
320 let sr = r.sr().read(); 272 let sr = r.sr().read();
321 let dier = r.dier().read(); 273 let dier = r.dier().read();
@@ -335,10 +287,9 @@ impl RtcDriver {
335 self.next_period(); 287 self.next_period();
336 } 288 }
337 289
338 for n in 0..ALARM_COUNT { 290 let n = 0;
339 if sr.ccif(n + 1) && dier.ccie(n + 1) { 291 if sr.ccif(n + 1) && dier.ccie(n + 1) {
340 self.trigger_alarm(n, cs); 292 self.trigger_alarm(cs);
341 }
342 } 293 }
343 }) 294 })
344 } 295 }
@@ -353,36 +304,23 @@ impl RtcDriver {
353 304
354 critical_section::with(move |cs| { 305 critical_section::with(move |cs| {
355 r.dier().modify(move |w| { 306 r.dier().modify(move |w| {
356 for n in 0..ALARM_COUNT { 307 let n = 0;
357 let alarm = &self.alarms.borrow(cs)[n]; 308 let alarm = self.alarm.borrow(cs);
358 let at = alarm.timestamp.get(); 309 let at = alarm.timestamp.get();
359 310
360 if at < t + 0xc000 { 311 if at < t + 0xc000 {
361 // just enable it. `set_alarm` has already set the correct CCR val. 312 // just enable it. `set_alarm` has already set the correct CCR val.
362 w.set_ccie(n + 1, true); 313 w.set_ccie(n + 1, true);
363 }
364 } 314 }
365 }) 315 })
366 }) 316 })
367 } 317 }
368 318
369 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { 319 fn trigger_alarm(&self, cs: CriticalSection) {
370 // safety: we're allowed to assume the AlarmState is created by us, and 320 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
371 // we never create one that's out of bounds. 321 while !self.set_alarm(cs, next) {
372 unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) } 322 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
373 } 323 }
374
375 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
376 let alarm = &self.alarms.borrow(cs)[n];
377 alarm.timestamp.set(u64::MAX);
378
379 // Call after clearing alarm, so the callback can set another alarm.
380
381 // safety:
382 // - we can ignore the possibility of `f` being unset (null) because of the safety contract of `allocate_alarm`.
383 // - other than that we only store valid function pointers into alarm.callback
384 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
385 f(alarm.ctx.get());
386 } 324 }
387 325
388 /* 326 /*
@@ -394,14 +332,7 @@ impl RtcDriver {
394 fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration { 332 fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration {
395 let now = self.now() + 32; 333 let now = self.now() + 32;
396 334
397 embassy_time::Duration::from_ticks( 335 embassy_time::Duration::from_ticks(self.alarm.borrow(cs).timestamp.get().saturating_sub(now))
398 self.alarms
399 .borrow(cs)
400 .iter()
401 .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now))
402 .min()
403 .unwrap_or(u64::MAX),
404 )
405 } 336 }
406 337
407 #[cfg(feature = "low-power")] 338 #[cfg(feature = "low-power")]
@@ -436,12 +367,12 @@ impl RtcDriver {
436 self.period.store(period, Ordering::SeqCst); 367 self.period.store(period, Ordering::SeqCst);
437 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 368 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
438 369
439 // Now, recompute all alarms 370 // Now, recompute alarm
440 for i in 0..ALARM_COUNT { 371 let alarm = self.alarm.borrow(cs);
441 let alarm_handle = unsafe { AlarmHandle::new(i as u8) };
442 let alarm = self.get_alarm(cs, alarm_handle);
443 372
444 self.set_alarm(alarm_handle, alarm.timestamp.get()); 373 if !self.set_alarm(cs, alarm.timestamp.get()) {
374 // If the alarm timestamp has passed, we need to trigger it
375 self.trigger_alarm(cs);
445 } 376 }
446 } 377 }
447 378
@@ -513,82 +444,71 @@ impl RtcDriver {
513 regs_gp16().cr1().modify(|w| w.set_cen(true)); 444 regs_gp16().cr1().modify(|w| w.set_cen(true));
514 }) 445 })
515 } 446 }
516}
517 447
518impl Driver for RtcDriver { 448 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
519 fn now(&self) -> u64 {
520 let r = regs_gp16(); 449 let r = regs_gp16();
521 450
522 let period = self.period.load(Ordering::Relaxed); 451 let n = 0;
523 compiler_fence(Ordering::Acquire); 452 self.alarm.borrow(cs).timestamp.set(timestamp);
524 let counter = r.cnt().read().cnt();
525 calc_now(period, counter)
526 }
527 453
528 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 454 let t = self.now();
529 critical_section::with(|_| { 455 if timestamp <= t {
530 let id = self.alarm_count.load(Ordering::Relaxed); 456 // If alarm timestamp has passed the alarm will not fire.
531 if id < ALARM_COUNT as u8 { 457 // Disarm the alarm and return `false` to indicate that.
532 self.alarm_count.store(id + 1, Ordering::Relaxed); 458 r.dier().modify(|w| w.set_ccie(n + 1, false));
533 Some(AlarmHandle::new(id))
534 } else {
535 None
536 }
537 })
538 }
539 459
540 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 460 self.alarm.borrow(cs).timestamp.set(u64::MAX);
541 critical_section::with(|cs| {
542 let alarm = self.get_alarm(cs, alarm);
543 461
544 alarm.callback.set(callback as *const ()); 462 return false;
545 alarm.ctx.set(ctx); 463 }
546 })
547 }
548 464
549 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 465 // Write the CCR value regardless of whether we're going to enable it now or not.
550 critical_section::with(|cs| { 466 // This way, when we enable it later, the right value is already set.
551 let r = regs_gp16(); 467 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
552 468
553 let n = alarm.id() as usize; 469 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
554 let alarm = self.get_alarm(cs, alarm); 470 let diff = timestamp - t;
555 alarm.timestamp.set(timestamp); 471 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
556 472
557 let t = self.now(); 473 // Reevaluate if the alarm timestamp is still in the future
558 if timestamp <= t { 474 let t = self.now();
559 // If alarm timestamp has passed the alarm will not fire. 475 if timestamp <= t {
560 // Disarm the alarm and return `false` to indicate that. 476 // If alarm timestamp has passed since we set it, we have a race condition and
561 r.dier().modify(|w| w.set_ccie(n + 1, false)); 477 // the alarm may or may not have fired.
478 // Disarm the alarm and return `false` to indicate that.
479 // It is the caller's responsibility to handle this ambiguity.
480 r.dier().modify(|w| w.set_ccie(n + 1, false));
562 481
563 alarm.timestamp.set(u64::MAX); 482 self.alarm.borrow(cs).timestamp.set(u64::MAX);
564 483
565 return false; 484 return false;
566 } 485 }
567 486
568 // Write the CCR value regardless of whether we're going to enable it now or not. 487 // We're confident the alarm will ring in the future.
569 // This way, when we enable it later, the right value is already set. 488 true
570 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16)); 489 }
490}
571 491
572 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 492impl Driver for RtcDriver {
573 let diff = timestamp - t; 493 fn now(&self) -> u64 {
574 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); 494 let r = regs_gp16();
575 495
576 // Reevaluate if the alarm timestamp is still in the future 496 let period = self.period.load(Ordering::Relaxed);
577 let t = self.now(); 497 compiler_fence(Ordering::Acquire);
578 if timestamp <= t { 498 let counter = r.cnt().read().cnt();
579 // If alarm timestamp has passed since we set it, we have a race condition and 499 calc_now(period, counter)
580 // the alarm may or may not have fired. 500 }
581 // Disarm the alarm and return `false` to indicate that.
582 // It is the caller's responsibility to handle this ambiguity.
583 r.dier().modify(|w| w.set_ccie(n + 1, false));
584 501
585 alarm.timestamp.set(u64::MAX); 502 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
503 critical_section::with(|cs| {
504 let mut queue = self.queue.borrow(cs).borrow_mut();
586 505
587 return false; 506 if queue.schedule_wake(at, waker) {
507 let mut next = queue.next_expiration(self.now());
508 while !self.set_alarm(cs, next) {
509 next = queue.next_expiration(self.now());
510 }
588 } 511 }
589
590 // We're confident the alarm will ring in the future.
591 true
592 }) 512 })
593 } 513 }
594} 514}
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 46ccbf3df..8eec6c0c7 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -2,7 +2,6 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::{into_ref, PeripheralRef};
6use stm32_metapac::timer::vals::Ckd; 5use stm32_metapac::timer::vals::Ckd;
7 6
8use super::low_level::{CountingMode, OutputPolarity, Timer}; 7use super::low_level::{CountingMode, OutputPolarity, Timer};
@@ -14,13 +13,13 @@ use super::{
14use crate::gpio::{AnyPin, OutputType}; 13use crate::gpio::{AnyPin, OutputType};
15use crate::time::Hertz; 14use crate::time::Hertz;
16use crate::timer::low_level::OutputCompareMode; 15use crate::timer::low_level::OutputCompareMode;
17use crate::Peripheral; 16use crate::Peri;
18 17
19/// Complementary PWM pin wrapper. 18/// Complementary PWM pin wrapper.
20/// 19///
21/// This wraps a pin to make it usable with PWM. 20/// This wraps a pin to make it usable with PWM.
22pub struct ComplementaryPwmPin<'d, T, C> { 21pub struct ComplementaryPwmPin<'d, T, C> {
23 _pin: PeripheralRef<'d, AnyPin>, 22 _pin: Peri<'d, AnyPin>,
24 phantom: PhantomData<(T, C)>, 23 phantom: PhantomData<(T, C)>,
25} 24}
26 25
@@ -28,8 +27,7 @@ macro_rules! complementary_channel_impl {
28 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 27 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
29 impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { 28 impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> {
30 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 29 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
31 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { 30 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, output_type: OutputType) -> Self {
32 into_ref!(pin);
33 critical_section::with(|_| { 31 critical_section::with(|_| {
34 pin.set_low(); 32 pin.set_low();
35 pin.set_as_af( 33 pin.set_as_af(
@@ -38,7 +36,7 @@ macro_rules! complementary_channel_impl {
38 ); 36 );
39 }); 37 });
40 ComplementaryPwmPin { 38 ComplementaryPwmPin {
41 _pin: pin.map_into(), 39 _pin: pin.into(),
42 phantom: PhantomData, 40 phantom: PhantomData,
43 } 41 }
44 } 42 }
@@ -60,7 +58,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
60 /// Create a new complementary PWM driver. 58 /// Create a new complementary PWM driver.
61 #[allow(clippy::too_many_arguments)] 59 #[allow(clippy::too_many_arguments)]
62 pub fn new( 60 pub fn new(
63 tim: impl Peripheral<P = T> + 'd, 61 tim: Peri<'d, T>,
64 _ch1: Option<PwmPin<'d, T, Ch1>>, 62 _ch1: Option<PwmPin<'d, T, Ch1>>,
65 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>, 63 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
66 _ch2: Option<PwmPin<'d, T, Ch2>>, 64 _ch2: Option<PwmPin<'d, T, Ch2>>,
@@ -75,7 +73,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
75 Self::new_inner(tim, freq, counting_mode) 73 Self::new_inner(tim, freq, counting_mode)
76 } 74 }
77 75
78 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { 76 fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self {
79 let mut this = Self { inner: Timer::new(tim) }; 77 let mut this = Self { inner: Timer::new(tim) };
80 78
81 this.inner.set_counting_mode(counting_mode); 79 this.inner.set_counting_mode(counting_mode);
@@ -116,7 +114,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
116 } else { 114 } else {
117 1u8 115 1u8
118 }; 116 };
119 self.inner.set_frequency(freq * multiplier); 117 self.inner.set_frequency_internal(freq * multiplier, 16);
120 } 118 }
121 119
122 /// Get max duty value. 120 /// Get max duty value.
@@ -242,11 +240,11 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
242 let (these_bits, result) = if target < 128 { 240 let (these_bits, result) = if target < 128 {
243 (target as u8, target) 241 (target as u8, target)
244 } else if target < 255 { 242 } else if target < 255 {
245 (64 + (target / 2) as u8, (target - target % 2)) 243 ((64 + (target / 2) as u8) | 128, (target - target % 2))
246 } else if target < 508 { 244 } else if target < 508 {
247 (32 + (target / 8) as u8, (target - target % 8)) 245 ((32 + (target / 8) as u8) | 192, (target - target % 8))
248 } else if target < 1008 { 246 } else if target < 1008 {
249 (32 + (target / 16) as u8, (target - target % 16)) 247 ((32 + (target / 16) as u8) | 224, (target - target % 16))
250 } else { 248 } else {
251 (u8::MAX, 1008) 249 (u8::MAX, 1008)
252 }; 250 };
@@ -302,7 +300,7 @@ mod tests {
302 TestRun { 300 TestRun {
303 value: 400, 301 value: 400,
304 ckd: Ckd::DIV1, 302 ckd: Ckd::DIV1,
305 bits: 32 + (400u16 / 8) as u8, 303 bits: 210,
306 }, 304 },
307 TestRun { 305 TestRun {
308 value: 600, 306 value: 600,
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index 341ac2c04..ec8b1ddf1 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -5,32 +5,22 @@ 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::{into_ref, PeripheralRef};
9
10use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; 8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
11use super::{ 9use super::{
12 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, 10 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin,
13 GeneralInstance4Channel, 11 GeneralInstance4Channel,
14}; 12};
13pub use super::{Ch1, Ch2, Ch3, Ch4};
15use crate::gpio::{AfType, AnyPin, Pull}; 14use crate::gpio::{AfType, AnyPin, Pull};
16use crate::interrupt::typelevel::{Binding, Interrupt}; 15use crate::interrupt::typelevel::{Binding, Interrupt};
17use crate::time::Hertz; 16use crate::time::Hertz;
18use crate::Peripheral; 17use crate::Peri;
19
20/// Channel 1 marker type.
21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
24/// Channel 3 marker type.
25pub enum Ch3 {}
26/// Channel 4 marker type.
27pub enum Ch4 {}
28 18
29/// Capture pin wrapper. 19/// Capture pin wrapper.
30/// 20///
31/// This wraps a pin to make it usable with capture. 21/// This wraps a pin to make it usable with capture.
32pub struct CapturePin<'d, T, C> { 22pub struct CapturePin<'d, T, C> {
33 _pin: PeripheralRef<'d, AnyPin>, 23 _pin: Peri<'d, AnyPin>,
34 phantom: PhantomData<(T, C)>, 24 phantom: PhantomData<(T, C)>,
35} 25}
36 26
@@ -38,11 +28,10 @@ macro_rules! channel_impl {
38 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 28 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
39 impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> { 29 impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> {
40 #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] 30 #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")]
41 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, pull: Pull) -> Self { 31 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, pull: Pull) -> Self {
42 into_ref!(pin);
43 pin.set_as_af(pin.af_num(), AfType::input(pull)); 32 pin.set_as_af(pin.af_num(), AfType::input(pull));
44 CapturePin { 33 CapturePin {
45 _pin: pin.map_into(), 34 _pin: pin.into(),
46 phantom: PhantomData, 35 phantom: PhantomData,
47 } 36 }
48 } 37 }
@@ -63,7 +52,7 @@ pub struct InputCapture<'d, T: GeneralInstance4Channel> {
63impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { 52impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
64 /// Create a new input capture driver. 53 /// Create a new input capture driver.
65 pub fn new( 54 pub fn new(
66 tim: impl Peripheral<P = T> + 'd, 55 tim: Peri<'d, T>,
67 _ch1: Option<CapturePin<'d, T, Ch1>>, 56 _ch1: Option<CapturePin<'d, T, Ch1>>,
68 _ch2: Option<CapturePin<'d, T, Ch2>>, 57 _ch2: Option<CapturePin<'d, T, Ch2>>,
69 _ch3: Option<CapturePin<'d, T, Ch3>>, 58 _ch3: Option<CapturePin<'d, T, Ch3>>,
@@ -75,7 +64,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
75 Self::new_inner(tim, freq, counting_mode) 64 Self::new_inner(tim, freq, counting_mode)
76 } 65 }
77 66
78 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { 67 fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self {
79 let mut this = Self { inner: Timer::new(tim) }; 68 let mut this = Self { inner: Timer::new(tim) };
80 69
81 this.inner.set_counting_mode(counting_mode); 70 this.inner.set_counting_mode(counting_mode);
@@ -129,7 +118,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
129 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.5 118 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.5
130 // or ST RM0008 (STM32F103) chapter 15.3.5 Input capture mode 119 // or ST RM0008 (STM32F103) chapter 15.3.5 Input capture mode
131 self.inner.set_input_ti_selection(channel, tisel); 120 self.inner.set_input_ti_selection(channel, tisel);
132 self.inner.set_input_capture_filter(channel, FilterValue::NOFILTER); 121 self.inner.set_input_capture_filter(channel, FilterValue::NO_FILTER);
133 self.inner.set_input_capture_mode(channel, mode); 122 self.inner.set_input_capture_mode(channel, mode);
134 self.inner.set_input_capture_prescaler(channel, 0); 123 self.inner.set_input_capture_prescaler(channel, 0);
135 self.inner.enable_channel(channel, true); 124 self.inner.enable_channel(channel, true);
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index e643722aa..dc8ceb725 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -6,7 +6,9 @@
6//! 6//!
7//! The available functionality depends on the timer type. 7//! The available functionality depends on the timer type.
8 8
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 9use core::mem::ManuallyDrop;
10
11use embassy_hal_internal::Peri;
10// Re-export useful enums 12// Re-export useful enums
11pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; 13pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource};
12 14
@@ -93,11 +95,11 @@ impl CountingMode {
93impl From<CountingMode> for (vals::Cms, vals::Dir) { 95impl From<CountingMode> for (vals::Cms, vals::Dir) {
94 fn from(value: CountingMode) -> Self { 96 fn from(value: CountingMode) -> Self {
95 match value { 97 match value {
96 CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), 98 CountingMode::EdgeAlignedUp => (vals::Cms::EDGE_ALIGNED, vals::Dir::UP),
97 CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), 99 CountingMode::EdgeAlignedDown => (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN),
98 CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), 100 CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTER_ALIGNED1, vals::Dir::UP),
99 CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), 101 CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTER_ALIGNED2, vals::Dir::UP),
100 CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), 102 CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTER_ALIGNED3, vals::Dir::UP),
101 } 103 }
102 } 104 }
103} 105}
@@ -105,11 +107,11 @@ impl From<CountingMode> for (vals::Cms, vals::Dir) {
105impl From<(vals::Cms, vals::Dir)> for CountingMode { 107impl From<(vals::Cms, vals::Dir)> for CountingMode {
106 fn from(value: (vals::Cms, vals::Dir)) -> Self { 108 fn from(value: (vals::Cms, vals::Dir)) -> Self {
107 match value { 109 match value {
108 (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, 110 (vals::Cms::EDGE_ALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp,
109 (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, 111 (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown,
110 (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, 112 (vals::Cms::CENTER_ALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts,
111 (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, 113 (vals::Cms::CENTER_ALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts,
112 (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, 114 (vals::Cms::CENTER_ALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts,
113 } 115 }
114 } 116 }
115} 117}
@@ -148,13 +150,13 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
148 fn from(mode: OutputCompareMode) -> Self { 150 fn from(mode: OutputCompareMode) -> Self {
149 match mode { 151 match mode {
150 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, 152 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
151 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, 153 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH,
152 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, 154 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH,
153 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, 155 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
154 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, 156 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE,
155 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, 157 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE,
156 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, 158 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1,
157 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, 159 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2,
158 } 160 }
159 } 161 }
160} 162}
@@ -179,7 +181,7 @@ impl From<OutputPolarity> for bool {
179 181
180/// Low-level timer driver. 182/// Low-level timer driver.
181pub struct Timer<'d, T: CoreInstance> { 183pub struct Timer<'d, T: CoreInstance> {
182 tim: PeripheralRef<'d, T>, 184 tim: Peri<'d, T>,
183} 185}
184 186
185impl<'d, T: CoreInstance> Drop for Timer<'d, T> { 187impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
@@ -190,14 +192,17 @@ impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
190 192
191impl<'d, T: CoreInstance> Timer<'d, T> { 193impl<'d, T: CoreInstance> Timer<'d, T> {
192 /// Create a new timer driver. 194 /// Create a new timer driver.
193 pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self { 195 pub fn new(tim: Peri<'d, T>) -> Self {
194 into_ref!(tim);
195
196 rcc::enable_and_reset::<T>(); 196 rcc::enable_and_reset::<T>();
197 197
198 Self { tim } 198 Self { tim }
199 } 199 }
200 200
201 pub(crate) unsafe fn clone_unchecked(&self) -> ManuallyDrop<Self> {
202 let tim = unsafe { self.tim.clone_unchecked() };
203 ManuallyDrop::new(Self { tim })
204 }
205
201 /// Get access to the virutal core 16bit timer registers. 206 /// Get access to the virutal core 16bit timer registers.
202 /// 207 ///
203 /// Note: This works even if the timer is more capable, because registers 208 /// Note: This works even if the timer is more capable, because registers
@@ -228,6 +233,11 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
228 self.regs_core().cnt().write(|r| r.set_cnt(0)); 233 self.regs_core().cnt().write(|r| r.set_cnt(0));
229 } 234 }
230 235
236 /// get the capability of the timer
237 pub fn bits(&self) -> TimerBits {
238 T::BITS
239 }
240
231 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. 241 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
232 /// 242 ///
233 /// This means that in the default edge-aligned mode, 243 /// This means that in the default edge-aligned mode,
@@ -235,16 +245,28 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
235 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved 245 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
236 /// because it needs to count up and down. 246 /// because it needs to count up and down.
237 pub fn set_frequency(&self, frequency: Hertz) { 247 pub fn set_frequency(&self, frequency: Hertz) {
248 match T::BITS {
249 TimerBits::Bits16 => {
250 self.set_frequency_internal(frequency, 16);
251 }
252 #[cfg(not(stm32l0))]
253 TimerBits::Bits32 => {
254 self.set_frequency_internal(frequency, 32);
255 }
256 }
257 }
258
259 pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) {
238 let f = frequency.0; 260 let f = frequency.0;
239 assert!(f > 0); 261 assert!(f > 0);
240 let timer_f = T::frequency().0; 262 let timer_f = T::frequency().0;
241 263
264 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
265 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into());
266 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
267
242 match T::BITS { 268 match T::BITS {
243 TimerBits::Bits16 => { 269 TimerBits::Bits16 => {
244 let pclk_ticks_per_timer_period = timer_f / f;
245 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
246 let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1);
247
248 // the timer counts `0..=arr`, we want it to count `0..divide_by` 270 // the timer counts `0..=arr`, we want it to count `0..divide_by`
249 let arr = unwrap!(u16::try_from(divide_by - 1)); 271 let arr = unwrap!(u16::try_from(divide_by - 1));
250 272
@@ -252,16 +274,12 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
252 regs.psc().write_value(psc); 274 regs.psc().write_value(psc);
253 regs.arr().write(|r| r.set_arr(arr)); 275 regs.arr().write(|r| r.set_arr(arr));
254 276
255 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 277 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
256 regs.egr().write(|r| r.set_ug(true)); 278 regs.egr().write(|r| r.set_ug(true));
257 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 279 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
258 } 280 }
259 #[cfg(not(stm32l0))] 281 #[cfg(not(stm32l0))]
260 TimerBits::Bits32 => { 282 TimerBits::Bits32 => {
261 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
262 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
263 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
264
265 // the timer counts `0..=arr`, we want it to count `0..divide_by` 283 // the timer counts `0..=arr`, we want it to count `0..divide_by`
266 let arr: u32 = unwrap!(u32::try_from(divide_by - 1)); 284 let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
267 285
@@ -269,9 +287,9 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
269 regs.psc().write_value(psc); 287 regs.psc().write_value(psc);
270 regs.arr().write_value(arr); 288 regs.arr().write_value(arr);
271 289
272 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 290 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
273 regs.egr().write(|r| r.set_ug(true)); 291 regs.egr().write(|r| r.set_ug(true));
274 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 292 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
275 } 293 }
276 } 294 }
277 } 295 }
@@ -405,6 +423,36 @@ impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
405 TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), 423 TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(),
406 } 424 }
407 } 425 }
426
427 /// Set the max compare value.
428 ///
429 /// An update event is generated to load the new value. The update event is
430 /// generated such that it will not cause an interrupt or DMA request.
431 pub fn set_max_compare_value(&self, ticks: u32) {
432 match T::BITS {
433 TimerBits::Bits16 => {
434 let arr = unwrap!(u16::try_from(ticks));
435
436 let regs = self.regs_1ch();
437 regs.arr().write(|r| r.set_arr(arr));
438
439 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
440 regs.egr().write(|r| r.set_ug(true));
441 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
442 }
443 #[cfg(not(stm32l0))]
444 TimerBits::Bits32 => {
445 let arr = ticks;
446
447 let regs = self.regs_gp32_unchecked();
448 regs.arr().write_value(arr);
449
450 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
451 regs.egr().write(|r| r.set_ug(true));
452 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
453 }
454 }
455 }
408} 456}
409 457
410impl<'d, T: GeneralInstance2Channel> Timer<'d, T> { 458impl<'d, T: GeneralInstance2Channel> Timer<'d, T> {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 25782ee13..b29382fc8 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -2,12 +2,14 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::PeripheralType;
5use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
6 7
7#[cfg(not(stm32l0))] 8#[cfg(not(stm32l0))]
8pub mod complementary_pwm; 9pub mod complementary_pwm;
9pub mod input_capture; 10pub mod input_capture;
10pub mod low_level; 11pub mod low_level;
12pub mod one_pulse;
11pub mod pwm_input; 13pub mod pwm_input;
12pub mod qei; 14pub mod qei;
13pub mod simple_pwm; 15pub mod simple_pwm;
@@ -40,6 +42,15 @@ impl Channel {
40 } 42 }
41} 43}
42 44
45/// Channel 1 marker type.
46pub enum Ch1 {}
47/// Channel 2 marker type.
48pub enum Ch2 {}
49/// Channel 3 marker type.
50pub enum Ch3 {}
51/// Channel 4 marker type.
52pub enum Ch4 {}
53
43/// Amount of bits of a timer. 54/// Amount of bits of a timer.
44#[derive(Clone, Copy, PartialEq, Eq, Debug)] 55#[derive(Clone, Copy, PartialEq, Eq, Debug)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))] 56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -58,15 +69,14 @@ struct State {
58 69
59impl State { 70impl State {
60 const fn new() -> Self { 71 const fn new() -> Self {
61 const NEW_AW: AtomicWaker = AtomicWaker::new();
62 Self { 72 Self {
63 up_waker: NEW_AW, 73 up_waker: AtomicWaker::new(),
64 cc_waker: [NEW_AW; 4], 74 cc_waker: [const { AtomicWaker::new() }; 4],
65 } 75 }
66 } 76 }
67} 77}
68 78
69trait SealedInstance: RccPeripheral { 79trait SealedInstance: RccPeripheral + PeripheralType {
70 /// Async state for this timer 80 /// Async state for this timer
71 fn state() -> &'static State; 81 fn state() -> &'static State;
72} 82}
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
new file mode 100644
index 000000000..933165ef9
--- /dev/null
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -0,0 +1,383 @@
1//! One pulse mode driver.
2
3use core::future::Future;
4use core::marker::PhantomData;
5use core::mem::ManuallyDrop;
6use core::pin::Pin;
7use core::task::{Context, Poll};
8
9use super::low_level::{
10 CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource,
11};
12use super::{
13 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, ExternalTriggerPin, GeneralInstance4Channel,
14};
15pub use super::{Ch1, Ch2};
16use crate::gpio::{AfType, AnyPin, Pull};
17use crate::interrupt::typelevel::{Binding, Interrupt};
18use crate::pac::timer::vals::Etp;
19use crate::time::Hertz;
20use crate::Peri;
21
22/// External input marker type.
23pub enum Ext {}
24
25/// External trigger pin trigger polarity.
26#[derive(Clone, Copy)]
27pub enum ExternalTriggerPolarity {
28 /// Rising edge only.
29 Rising,
30 /// Falling edge only.
31 Falling,
32}
33
34impl From<ExternalTriggerPolarity> for Etp {
35 fn from(mode: ExternalTriggerPolarity) -> Self {
36 match mode {
37 ExternalTriggerPolarity::Rising => 0.into(),
38 ExternalTriggerPolarity::Falling => 1.into(),
39 }
40 }
41}
42
43/// Trigger pin wrapper.
44///
45/// This wraps a pin to make it usable as a timer trigger.
46pub struct TriggerPin<'d, T, C> {
47 _pin: Peri<'d, AnyPin>,
48 phantom: PhantomData<(T, C)>,
49}
50
51macro_rules! channel_impl {
52 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
53 impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, $channel> {
54 #[doc = concat!("Create a new ", stringify!($channel), " trigger pin instance.")]
55 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, pull: Pull) -> Self {
56 pin.set_as_af(pin.af_num(), AfType::input(pull));
57 TriggerPin {
58 _pin: pin.into(),
59 phantom: PhantomData,
60 }
61 }
62 }
63 };
64}
65
66channel_impl!(new_ch1, Ch1, Channel1Pin);
67channel_impl!(new_ch2, Ch2, Channel2Pin);
68channel_impl!(new_ext, Ext, ExternalTriggerPin);
69
70/// One pulse driver.
71///
72/// Generates a pulse after a trigger and some configurable delay.
73pub struct OnePulse<'d, T: GeneralInstance4Channel> {
74 inner: Timer<'d, T>,
75}
76
77impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
78 /// Create a new one pulse driver.
79 ///
80 /// The pulse is triggered by a channel 1 input pin on both rising and
81 /// falling edges. Channel 1 will unusable as an output.
82 pub fn new_ch1_edge_detect(
83 tim: Peri<'d, T>,
84 _pin: TriggerPin<'d, T, Ch1>,
85 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
86 freq: Hertz,
87 pulse_end: u32,
88 counting_mode: CountingMode,
89 ) -> Self {
90 let mut this = Self { inner: Timer::new(tim) };
91
92 this.inner.set_trigger_source(TriggerSource::TI1F_ED);
93 this.inner
94 .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
95 this.inner
96 .set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
97 this.new_inner(freq, pulse_end, counting_mode);
98
99 this
100 }
101
102 /// Create a new one pulse driver.
103 ///
104 /// The pulse is triggered by a channel 1 input pin. Channel 1 will unusable
105 /// as an output.
106 pub fn new_ch1(
107 tim: Peri<'d, T>,
108 _pin: TriggerPin<'d, T, Ch1>,
109 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
110 freq: Hertz,
111 pulse_end: u32,
112 counting_mode: CountingMode,
113 capture_mode: InputCaptureMode,
114 ) -> Self {
115 let mut this = Self { inner: Timer::new(tim) };
116
117 this.inner.set_trigger_source(TriggerSource::TI1FP1);
118 this.inner
119 .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
120 this.inner
121 .set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER);
122 this.inner.set_input_capture_mode(Channel::Ch1, capture_mode);
123 this.new_inner(freq, pulse_end, counting_mode);
124
125 this
126 }
127
128 /// Create a new one pulse driver.
129 ///
130 /// The pulse is triggered by a channel 2 input pin. Channel 2 will unusable
131 /// as an output.
132 pub fn new_ch2(
133 tim: Peri<'d, T>,
134 _pin: TriggerPin<'d, T, Ch1>,
135 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
136 freq: Hertz,
137 pulse_end: u32,
138 counting_mode: CountingMode,
139 capture_mode: InputCaptureMode,
140 ) -> Self {
141 let mut this = Self { inner: Timer::new(tim) };
142
143 this.inner.set_trigger_source(TriggerSource::TI2FP2);
144 this.inner
145 .set_input_ti_selection(Channel::Ch2, InputTISelection::Normal);
146 this.inner
147 .set_input_capture_filter(Channel::Ch2, FilterValue::NO_FILTER);
148 this.inner.set_input_capture_mode(Channel::Ch2, capture_mode);
149 this.new_inner(freq, pulse_end, counting_mode);
150
151 this
152 }
153
154 /// Create a new one pulse driver.
155 ///
156 /// The pulse is triggered by a external trigger input pin.
157 pub fn new_ext(
158 tim: Peri<'d, T>,
159 _pin: TriggerPin<'d, T, Ext>,
160 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
161 freq: Hertz,
162 pulse_end: u32,
163 counting_mode: CountingMode,
164 polarity: ExternalTriggerPolarity,
165 ) -> Self {
166 let mut this = Self { inner: Timer::new(tim) };
167
168 this.inner.regs_gp16().smcr().modify(|r| {
169 r.set_etp(polarity.into());
170 // No pre-scaling
171 r.set_etps(0.into());
172 // No filtering
173 r.set_etf(FilterValue::NO_FILTER);
174 });
175 this.inner.set_trigger_source(TriggerSource::ETRF);
176 this.new_inner(freq, pulse_end, counting_mode);
177
178 this
179 }
180
181 fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) {
182 self.inner.set_counting_mode(counting_mode);
183 self.inner.set_tick_freq(freq);
184 self.inner.set_max_compare_value(pulse_end);
185 self.inner.regs_core().cr1().modify(|r| r.set_opm(true));
186 // Required for advanced timers, see GeneralInstance4Channel for details
187 self.inner.enable_outputs();
188 self.inner.set_slave_mode(SlaveMode::TRIGGER_MODE);
189
190 T::CaptureCompareInterrupt::unpend();
191 unsafe { T::CaptureCompareInterrupt::enable() };
192 }
193
194 /// Get the end of the pulse in ticks from the trigger.
195 pub fn pulse_end(&self) -> u32 {
196 let max = self.inner.get_max_compare_value();
197 assert!(max < u32::MAX);
198 max + 1
199 }
200
201 /// Set the end of the pulse in ticks from the trigger.
202 pub fn set_pulse_end(&mut self, ticks: u32) {
203 self.inner.set_max_compare_value(ticks)
204 }
205
206 /// Reset the timer on each trigger
207 #[cfg(not(stm32l0))]
208 pub fn set_reset_on_trigger(&mut self, reset: bool) {
209 let slave_mode = if reset {
210 SlaveMode::COMBINED_RESET_TRIGGER
211 } else {
212 SlaveMode::TRIGGER_MODE
213 };
214 self.inner.set_slave_mode(slave_mode);
215 }
216
217 /// Get a single channel
218 ///
219 /// If you need to use multiple channels, use [`Self::split`].
220 pub fn channel(&mut self, channel: Channel) -> OnePulseChannel<'_, T> {
221 OnePulseChannel {
222 inner: unsafe { self.inner.clone_unchecked() },
223 channel,
224 }
225 }
226
227 /// Channel 1
228 ///
229 /// This is just a convenience wrapper around [`Self::channel`].
230 ///
231 /// If you need to use multiple channels, use [`Self::split`].
232 pub fn ch1(&mut self) -> OnePulseChannel<'_, T> {
233 self.channel(Channel::Ch1)
234 }
235
236 /// Channel 2
237 ///
238 /// This is just a convenience wrapper around [`Self::channel`].
239 ///
240 /// If you need to use multiple channels, use [`Self::split`].
241 pub fn ch2(&mut self) -> OnePulseChannel<'_, T> {
242 self.channel(Channel::Ch2)
243 }
244
245 /// Channel 3
246 ///
247 /// This is just a convenience wrapper around [`Self::channel`].
248 ///
249 /// If you need to use multiple channels, use [`Self::split`].
250 pub fn ch3(&mut self) -> OnePulseChannel<'_, T> {
251 self.channel(Channel::Ch3)
252 }
253
254 /// Channel 4
255 ///
256 /// This is just a convenience wrapper around [`Self::channel`].
257 ///
258 /// If you need to use multiple channels, use [`Self::split`].
259 pub fn ch4(&mut self) -> OnePulseChannel<'_, T> {
260 self.channel(Channel::Ch4)
261 }
262
263 /// Splits a [`OnePulse`] into four output channels.
264 // TODO: I hate the name "split"
265 pub fn split(self) -> OnePulseChannels<'static, T>
266 where
267 // must be static because the timer will never be dropped/disabled
268 'd: 'static,
269 {
270 // without this, the timer would be disabled at the end of this function
271 let timer = ManuallyDrop::new(self.inner);
272
273 let ch = |channel| OnePulseChannel {
274 inner: unsafe { timer.clone_unchecked() },
275 channel,
276 };
277
278 OnePulseChannels {
279 ch1: ch(Channel::Ch1),
280 ch2: ch(Channel::Ch2),
281 ch3: ch(Channel::Ch3),
282 ch4: ch(Channel::Ch4),
283 }
284 }
285}
286
287/// A group of four [`OnePulseChannel`]s, obtained from [`OnePulse::split`].
288pub struct OnePulseChannels<'d, T: GeneralInstance4Channel> {
289 /// Channel 1
290 pub ch1: OnePulseChannel<'d, T>,
291 /// Channel 2
292 pub ch2: OnePulseChannel<'d, T>,
293 /// Channel 3
294 pub ch3: OnePulseChannel<'d, T>,
295 /// Channel 4
296 pub ch4: OnePulseChannel<'d, T>,
297}
298
299/// A single channel of a one pulse-configured timer, obtained from
300/// [`OnePulse::split`],[`OnePulse::channel`], [`OnePulse::ch1`], etc.
301///
302/// It is not possible to change the pulse end tick because the end tick
303/// configuration is shared with all four channels.
304pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> {
305 inner: ManuallyDrop<Timer<'d, T>>,
306 channel: Channel,
307}
308
309impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
310 /// Get the end of the pulse in ticks from the trigger.
311 pub fn pulse_end(&self) -> u32 {
312 let max = self.inner.get_max_compare_value();
313 assert!(max < u32::MAX);
314 max + 1
315 }
316
317 /// Get the width of the pulse in ticks.
318 pub fn pulse_width(&mut self) -> u32 {
319 self.pulse_end().saturating_sub(self.pulse_delay())
320 }
321
322 /// Get the start of the pulse in ticks from the trigger.
323 pub fn pulse_delay(&mut self) -> u32 {
324 self.inner.get_compare_value(self.channel)
325 }
326
327 /// Set the start of the pulse in ticks from the trigger.
328 pub fn set_pulse_delay(&mut self, delay: u32) {
329 assert!(delay <= self.pulse_end());
330 self.inner.set_compare_value(self.channel, delay);
331 }
332
333 /// Set the pulse width in ticks.
334 pub fn set_pulse_width(&mut self, width: u32) {
335 assert!(width <= self.pulse_end());
336 self.set_pulse_delay(self.pulse_end() - width);
337 }
338
339 /// Waits until the trigger and following delay has passed.
340 pub async fn wait_for_pulse_start(&mut self) {
341 self.inner.enable_input_interrupt(self.channel, true);
342
343 OnePulseFuture::<T> {
344 channel: self.channel,
345 phantom: PhantomData,
346 }
347 .await
348 }
349}
350
351#[must_use = "futures do nothing unless you `.await` or poll them"]
352struct OnePulseFuture<T: GeneralInstance4Channel> {
353 channel: Channel,
354 phantom: PhantomData<T>,
355}
356
357impl<'d, T: GeneralInstance4Channel> Drop for OnePulseFuture<T> {
358 fn drop(&mut self) {
359 critical_section::with(|_| {
360 let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
361
362 // disable interrupt enable
363 regs.dier().modify(|w| w.set_ccie(self.channel.index(), false));
364 });
365 }
366}
367
368impl<'d, T: GeneralInstance4Channel> Future for OnePulseFuture<T> {
369 type Output = ();
370
371 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
372 T::state().cc_waker[self.channel.index()].register(cx.waker());
373
374 let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) };
375
376 let dier = regs.dier().read();
377 if !dier.ccie(self.channel.index()) {
378 Poll::Ready(())
379 } else {
380 Poll::Pending
381 }
382 }
383}
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index e3eb6042a..98b798634 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -1,12 +1,10 @@
1//! PWM Input driver. 1//! PWM Input driver.
2 2
3use embassy_hal_internal::into_ref;
4
5use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; 3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
6use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel}; 4use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel};
7use crate::gpio::{AfType, Pull}; 5use crate::gpio::{AfType, Pull};
8use crate::time::Hertz; 6use crate::time::Hertz;
9use crate::Peripheral; 7use crate::Peri;
10 8
11/// PWM Input driver. 9/// PWM Input driver.
12pub struct PwmInput<'d, T: GeneralInstance4Channel> { 10pub struct PwmInput<'d, T: GeneralInstance4Channel> {
@@ -16,34 +14,20 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> {
16 14
17impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { 15impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
18 /// Create a new PWM input driver. 16 /// Create a new PWM input driver.
19 pub fn new( 17 pub fn new(tim: Peri<'d, T>, pin: Peri<'d, impl Channel1Pin<T>>, pull: Pull, freq: Hertz) -> Self {
20 tim: impl Peripheral<P = T> + 'd,
21 pin: impl Peripheral<P = impl Channel1Pin<T>> + 'd,
22 pull: Pull,
23 freq: Hertz,
24 ) -> Self {
25 into_ref!(pin);
26
27 pin.set_as_af(pin.af_num(), AfType::input(pull)); 18 pin.set_as_af(pin.af_num(), AfType::input(pull));
28 19
29 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) 20 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
30 } 21 }
31 22
32 /// Create a new PWM input driver. 23 /// Create a new PWM input driver.
33 pub fn new_alt( 24 pub fn new_alt(tim: Peri<'d, T>, pin: Peri<'d, impl Channel2Pin<T>>, pull: Pull, freq: Hertz) -> Self {
34 tim: impl Peripheral<P = T> + 'd,
35 pin: impl Peripheral<P = impl Channel2Pin<T>> + 'd,
36 pull: Pull,
37 freq: Hertz,
38 ) -> Self {
39 into_ref!(pin);
40
41 pin.set_as_af(pin.af_num(), AfType::input(pull)); 25 pin.set_as_af(pin.af_num(), AfType::input(pull));
42 26
43 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) 27 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
44 } 28 }
45 29
46 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, ch1: Channel, ch2: Channel) -> Self { 30 fn new_inner(tim: Peri<'d, T>, freq: Hertz, ch1: Channel, ch2: Channel) -> Self {
47 let mut inner = Timer::new(tim); 31 let mut inner = Timer::new(tim);
48 32
49 inner.set_counting_mode(CountingMode::EdgeAlignedUp); 33 inner.set_counting_mode(CountingMode::EdgeAlignedUp);
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index fc5835414..f3c81667c 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -2,13 +2,13 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::{into_ref, PeripheralRef};
6use stm32_metapac::timer::vals; 5use stm32_metapac::timer::vals;
7 6
8use super::low_level::Timer; 7use super::low_level::Timer;
8pub use super::{Ch1, Ch2};
9use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; 9use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel};
10use crate::gpio::{AfType, AnyPin, Pull}; 10use crate::gpio::{AfType, AnyPin, Pull};
11use crate::Peripheral; 11use crate::Peri;
12 12
13/// Counting direction 13/// Counting direction
14pub enum Direction { 14pub enum Direction {
@@ -18,14 +18,9 @@ pub enum Direction {
18 Downcounting, 18 Downcounting,
19} 19}
20 20
21/// Channel 1 marker type.
22pub enum Ch1 {}
23/// Channel 2 marker type.
24pub enum Ch2 {}
25
26/// Wrapper for using a pin with QEI. 21/// Wrapper for using a pin with QEI.
27pub struct QeiPin<'d, T, Channel> { 22pub struct QeiPin<'d, T, Channel> {
28 _pin: PeripheralRef<'d, AnyPin>, 23 _pin: Peri<'d, AnyPin>,
29 phantom: PhantomData<(T, Channel)>, 24 phantom: PhantomData<(T, Channel)>,
30} 25}
31 26
@@ -33,14 +28,13 @@ macro_rules! channel_impl {
33 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 28 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
34 impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { 29 impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> {
35 #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] 30 #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")]
36 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { 31 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
37 into_ref!(pin);
38 critical_section::with(|_| { 32 critical_section::with(|_| {
39 pin.set_low(); 33 pin.set_low();
40 pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); 34 pin.set_as_af(pin.af_num(), AfType::input(Pull::None));
41 }); 35 });
42 QeiPin { 36 QeiPin {
43 _pin: pin.map_into(), 37 _pin: pin.into(),
44 phantom: PhantomData, 38 phantom: PhantomData,
45 } 39 }
46 } 40 }
@@ -58,11 +52,11 @@ pub struct Qei<'d, T: GeneralInstance4Channel> {
58 52
59impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { 53impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
60 /// Create a new quadrature decoder driver. 54 /// Create a new quadrature decoder driver.
61 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { 55 pub fn new(tim: Peri<'d, T>, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
62 Self::new_inner(tim) 56 Self::new_inner(tim)
63 } 57 }
64 58
65 fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { 59 fn new_inner(tim: Peri<'d, T>) -> Self {
66 let inner = Timer::new(tim); 60 let inner = Timer::new(tim);
67 let r = inner.regs_gp16(); 61 let r = inner.regs_gp16();
68 62
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index b7771bd64..f7f433154 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -1,14 +1,15 @@
1//! Simple PWM driver. 1//! Simple PWM driver.
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4use core::mem::ManuallyDrop;
5use embassy_hal_internal::{into_ref, PeripheralRef};
6 5
7use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; 6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
8use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; 7use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits};
8#[cfg(gpio_v2)]
9use crate::gpio::Pull;
9use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
10use crate::time::Hertz; 11use crate::time::Hertz;
11use crate::Peripheral; 12use crate::Peri;
12 13
13/// Channel 1 marker type. 14/// Channel 1 marker type.
14pub enum Ch1 {} 15pub enum Ch1 {}
@@ -23,22 +24,54 @@ pub enum Ch4 {}
23/// 24///
24/// This wraps a pin to make it usable with PWM. 25/// This wraps a pin to make it usable with PWM.
25pub struct PwmPin<'d, T, C> { 26pub struct PwmPin<'d, T, C> {
26 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: Peri<'d, AnyPin>,
27 phantom: PhantomData<(T, C)>, 28 phantom: PhantomData<(T, C)>,
28} 29}
29 30
31/// PWM pin config
32///
33/// This configures the pwm pin settings
34#[derive(Debug, Copy, Clone)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36pub struct PwmPinConfig {
37 /// PWM Pin output type
38 pub output_type: OutputType,
39 /// PWM Pin speed
40 pub speed: Speed,
41 /// PWM Pin pull type
42 #[cfg(gpio_v2)]
43 pub pull: Pull,
44}
45
30macro_rules! channel_impl { 46macro_rules! channel_impl {
31 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 47 ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => {
32 impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { 48 impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> {
33 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 49 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
34 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { 50 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, output_type: OutputType) -> Self {
35 into_ref!(pin);
36 critical_section::with(|_| { 51 critical_section::with(|_| {
37 pin.set_low(); 52 pin.set_low();
38 pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); 53 pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh));
39 }); 54 });
40 PwmPin { 55 PwmPin {
41 _pin: pin.map_into(), 56 _pin: pin.into(),
57 phantom: PhantomData,
58 }
59 }
60
61 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")]
62 pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T>>, pin_config: PwmPinConfig) -> Self {
63 critical_section::with(|_| {
64 pin.set_low();
65 pin.set_as_af(
66 pin.af_num(),
67 #[cfg(gpio_v1)]
68 AfType::output(pin_config.output_type, pin_config.speed),
69 #[cfg(gpio_v2)]
70 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
71 );
72 });
73 PwmPin {
74 _pin: pin.into(),
42 phantom: PhantomData, 75 phantom: PhantomData,
43 } 76 }
44 } 77 }
@@ -46,10 +79,115 @@ macro_rules! channel_impl {
46 }; 79 };
47} 80}
48 81
49channel_impl!(new_ch1, Ch1, Channel1Pin); 82channel_impl!(new_ch1, new_ch1_with_config, Ch1, Channel1Pin);
50channel_impl!(new_ch2, Ch2, Channel2Pin); 83channel_impl!(new_ch2, new_ch2_with_config, Ch2, Channel2Pin);
51channel_impl!(new_ch3, Ch3, Channel3Pin); 84channel_impl!(new_ch3, new_ch3_with_config, Ch3, Channel3Pin);
52channel_impl!(new_ch4, Ch4, Channel4Pin); 85channel_impl!(new_ch4, new_ch4_with_config, Ch4, Channel4Pin);
86
87/// A single channel of a pwm, obtained from [`SimplePwm::split`],
88/// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc.
89///
90/// It is not possible to change the pwm frequency because
91/// the frequency configuration is shared with all four channels.
92pub struct SimplePwmChannel<'d, T: GeneralInstance4Channel> {
93 timer: ManuallyDrop<Timer<'d, T>>,
94 channel: Channel,
95}
96
97// TODO: check for RMW races
98impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
99 /// Enable the given channel.
100 pub fn enable(&mut self) {
101 self.timer.enable_channel(self.channel, true);
102 }
103
104 /// Disable the given channel.
105 pub fn disable(&mut self) {
106 self.timer.enable_channel(self.channel, false);
107 }
108
109 /// Check whether given channel is enabled
110 pub fn is_enabled(&self) -> bool {
111 self.timer.get_channel_enable_state(self.channel)
112 }
113
114 /// Get max duty value.
115 ///
116 /// This value depends on the configured frequency and the timer's clock rate from RCC.
117 pub fn max_duty_cycle(&self) -> u16 {
118 let max = self.timer.get_max_compare_value();
119 assert!(max < u16::MAX as u32);
120 max as u16 + 1
121 }
122
123 /// Set the duty for a given channel.
124 ///
125 /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included.
126 pub fn set_duty_cycle(&mut self, duty: u16) {
127 assert!(duty <= (*self).max_duty_cycle());
128 self.timer.set_compare_value(self.channel, duty.into())
129 }
130
131 /// Set the duty cycle to 0%, or always inactive.
132 pub fn set_duty_cycle_fully_off(&mut self) {
133 self.set_duty_cycle(0);
134 }
135
136 /// Set the duty cycle to 100%, or always active.
137 pub fn set_duty_cycle_fully_on(&mut self) {
138 self.set_duty_cycle((*self).max_duty_cycle());
139 }
140
141 /// Set the duty cycle to `num / denom`.
142 ///
143 /// The caller is responsible for ensuring that `num` is less than or equal to `denom`,
144 /// and that `denom` is not zero.
145 pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) {
146 assert!(denom != 0);
147 assert!(num <= denom);
148 let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom);
149
150 // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16)
151 #[allow(clippy::cast_possible_truncation)]
152 self.set_duty_cycle(duty as u16);
153 }
154
155 /// Set the duty cycle to `percent / 100`
156 ///
157 /// The caller is responsible for ensuring that `percent` is less than or equal to 100.
158 pub fn set_duty_cycle_percent(&mut self, percent: u8) {
159 self.set_duty_cycle_fraction(u16::from(percent), 100)
160 }
161
162 /// Get the duty for a given channel.
163 ///
164 /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included.
165 pub fn current_duty_cycle(&self) -> u16 {
166 unwrap!(self.timer.get_compare_value(self.channel).try_into())
167 }
168
169 /// Set the output polarity for a given channel.
170 pub fn set_polarity(&mut self, polarity: OutputPolarity) {
171 self.timer.set_output_polarity(self.channel, polarity);
172 }
173
174 /// Set the output compare mode for a given channel.
175 pub fn set_output_compare_mode(&mut self, mode: OutputCompareMode) {
176 self.timer.set_output_compare_mode(self.channel, mode);
177 }
178}
179
180/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`].
181pub struct SimplePwmChannels<'d, T: GeneralInstance4Channel> {
182 /// Channel 1
183 pub ch1: SimplePwmChannel<'d, T>,
184 /// Channel 2
185 pub ch2: SimplePwmChannel<'d, T>,
186 /// Channel 3
187 pub ch3: SimplePwmChannel<'d, T>,
188 /// Channel 4
189 pub ch4: SimplePwmChannel<'d, T>,
190}
53 191
54/// Simple PWM driver. 192/// Simple PWM driver.
55pub struct SimplePwm<'d, T: GeneralInstance4Channel> { 193pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
@@ -59,7 +197,7 @@ pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
59impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { 197impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
60 /// Create a new simple PWM driver. 198 /// Create a new simple PWM driver.
61 pub fn new( 199 pub fn new(
62 tim: impl Peripheral<P = T> + 'd, 200 tim: Peri<'d, T>,
63 _ch1: Option<PwmPin<'d, T, Ch1>>, 201 _ch1: Option<PwmPin<'d, T, Ch1>>,
64 _ch2: Option<PwmPin<'d, T, Ch2>>, 202 _ch2: Option<PwmPin<'d, T, Ch2>>,
65 _ch3: Option<PwmPin<'d, T, Ch3>>, 203 _ch3: Option<PwmPin<'d, T, Ch3>>,
@@ -70,7 +208,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
70 Self::new_inner(tim, freq, counting_mode) 208 Self::new_inner(tim, freq, counting_mode)
71 } 209 }
72 210
73 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { 211 fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self {
74 let mut this = Self { inner: Timer::new(tim) }; 212 let mut this = Self { inner: Timer::new(tim) };
75 213
76 this.inner.set_counting_mode(counting_mode); 214 this.inner.set_counting_mode(counting_mode);
@@ -89,19 +227,76 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
89 this 227 this
90 } 228 }
91 229
92 /// Enable the given channel. 230 /// Get a single channel
93 pub fn enable(&mut self, channel: Channel) { 231 ///
94 self.inner.enable_channel(channel, true); 232 /// If you need to use multiple channels, use [`Self::split`].
233 pub fn channel(&mut self, channel: Channel) -> SimplePwmChannel<'_, T> {
234 SimplePwmChannel {
235 timer: unsafe { self.inner.clone_unchecked() },
236 channel,
237 }
95 } 238 }
96 239
97 /// Disable the given channel. 240 /// Channel 1
98 pub fn disable(&mut self, channel: Channel) { 241 ///
99 self.inner.enable_channel(channel, false); 242 /// This is just a convenience wrapper around [`Self::channel`].
243 ///
244 /// If you need to use multiple channels, use [`Self::split`].
245 pub fn ch1(&mut self) -> SimplePwmChannel<'_, T> {
246 self.channel(Channel::Ch1)
100 } 247 }
101 248
102 /// Check whether given channel is enabled 249 /// Channel 2
103 pub fn is_enabled(&self, channel: Channel) -> bool { 250 ///
104 self.inner.get_channel_enable_state(channel) 251 /// This is just a convenience wrapper around [`Self::channel`].
252 ///
253 /// If you need to use multiple channels, use [`Self::split`].
254 pub fn ch2(&mut self) -> SimplePwmChannel<'_, T> {
255 self.channel(Channel::Ch2)
256 }
257
258 /// Channel 3
259 ///
260 /// This is just a convenience wrapper around [`Self::channel`].
261 ///
262 /// If you need to use multiple channels, use [`Self::split`].
263 pub fn ch3(&mut self) -> SimplePwmChannel<'_, T> {
264 self.channel(Channel::Ch3)
265 }
266
267 /// Channel 4
268 ///
269 /// This is just a convenience wrapper around [`Self::channel`].
270 ///
271 /// If you need to use multiple channels, use [`Self::split`].
272 pub fn ch4(&mut self) -> SimplePwmChannel<'_, T> {
273 self.channel(Channel::Ch4)
274 }
275
276 /// Splits a [`SimplePwm`] into four pwm channels.
277 ///
278 /// This returns all four channels, including channels that
279 /// aren't configured with a [`PwmPin`].
280 // TODO: I hate the name "split"
281 pub fn split(self) -> SimplePwmChannels<'static, T>
282 where
283 // must be static because the timer will never be dropped/disabled
284 'd: 'static,
285 {
286 // without this, the timer would be disabled at the end of this function
287 let timer = ManuallyDrop::new(self.inner);
288
289 let ch = |channel| SimplePwmChannel {
290 timer: unsafe { timer.clone_unchecked() },
291 channel,
292 };
293
294 SimplePwmChannels {
295 ch1: ch(Channel::Ch1),
296 ch2: ch(Channel::Ch2),
297 ch3: ch(Channel::Ch3),
298 ch4: ch(Channel::Ch4),
299 }
105 } 300 }
106 301
107 /// Set PWM frequency. 302 /// Set PWM frequency.
@@ -109,63 +304,34 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
109 /// Note: when you call this, the max duty value changes, so you will have to 304 /// Note: when you call this, the max duty value changes, so you will have to
110 /// call `set_duty` on all channels with the duty calculated based on the new max duty. 305 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
111 pub fn set_frequency(&mut self, freq: Hertz) { 306 pub fn set_frequency(&mut self, freq: Hertz) {
307 // TODO: prevent ARR = u16::MAX?
112 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 308 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
113 2u8 309 2u8
114 } else { 310 } else {
115 1u8 311 1u8
116 }; 312 };
117 self.inner.set_frequency(freq * multiplier); 313 self.inner.set_frequency_internal(freq * multiplier, 16);
118 } 314 }
119 315
120 /// Get max duty value. 316 /// Get max duty value.
121 /// 317 ///
122 /// This value depends on the configured frequency and the timer's clock rate from RCC. 318 /// This value depends on the configured frequency and the timer's clock rate from RCC.
123 pub fn get_max_duty(&self) -> u32 { 319 pub fn max_duty_cycle(&self) -> u16 {
124 self.inner.get_max_compare_value() + 1 320 let max = self.inner.get_max_compare_value();
125 } 321 assert!(max < u16::MAX as u32);
126 322 max as u16 + 1
127 /// Set the duty for a given channel.
128 ///
129 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
130 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
131 assert!(duty <= self.get_max_duty());
132 self.inner.set_compare_value(channel, duty)
133 }
134
135 /// Get the duty for a given channel.
136 ///
137 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
138 pub fn get_duty(&self, channel: Channel) -> u32 {
139 self.inner.get_compare_value(channel)
140 }
141
142 /// Set the output polarity for a given channel.
143 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
144 self.inner.set_output_polarity(channel, polarity);
145 }
146
147 /// Set the output compare mode for a given channel.
148 pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
149 self.inner.set_output_compare_mode(channel, mode);
150 } 323 }
151 324
152 /// Generate a sequence of PWM waveform 325 /// Generate a sequence of PWM waveform
153 /// 326 ///
154 /// Note: 327 /// Note:
155 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 328 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
156 pub async fn waveform_up( 329 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
157 &mut self,
158 dma: impl Peripheral<P = impl super::UpDma<T>>,
159 channel: Channel,
160 duty: &[u16],
161 ) {
162 into_ref!(dma);
163
164 #[allow(clippy::let_unit_value)] // eg. stm32f334 330 #[allow(clippy::let_unit_value)] // eg. stm32f334
165 let req = dma.request(); 331 let req = dma.request();
166 332
167 let original_duty_state = self.get_duty(channel); 333 let original_duty_state = self.channel(channel).current_duty_cycle();
168 let original_enable_state = self.is_enabled(channel); 334 let original_enable_state = self.channel(channel).is_enabled();
169 let original_update_dma_state = self.inner.get_update_dma_state(); 335 let original_update_dma_state = self.inner.get_update_dma_state();
170 336
171 if !original_update_dma_state { 337 if !original_update_dma_state {
@@ -173,7 +339,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
173 } 339 }
174 340
175 if !original_enable_state { 341 if !original_enable_state {
176 self.enable(channel); 342 self.channel(channel).enable();
177 } 343 }
178 344
179 unsafe { 345 unsafe {
@@ -190,10 +356,10 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
190 }; 356 };
191 357
192 Transfer::new_write( 358 Transfer::new_write(
193 &mut dma, 359 dma,
194 req, 360 req,
195 duty, 361 duty,
196 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _, 362 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
197 dma_transfer_option, 363 dma_transfer_option,
198 ) 364 )
199 .await 365 .await
@@ -201,10 +367,10 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
201 367
202 // restore output compare state 368 // restore output compare state
203 if !original_enable_state { 369 if !original_enable_state {
204 self.disable(channel); 370 self.channel(channel).disable();
205 } 371 }
206 372
207 self.set_duty(channel, original_duty_state); 373 self.channel(channel).set_duty_cycle(original_duty_state);
208 374
209 // Since DMA is closed before timer update event trigger DMA is turn off, 375 // Since DMA is closed before timer update event trigger DMA is turn off,
210 // this can almost always trigger a DMA FIFO error. 376 // this can almost always trigger a DMA FIFO error.
@@ -215,33 +381,111 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
215 self.inner.enable_update_dma(false); 381 self.inner.enable_update_dma(false);
216 } 382 }
217 } 383 }
384
385 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
386 ///
387 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
388 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
389 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
390 ///
391 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
392 /// represents a single update event and each column corresponds to a specific timer channel (starting
393 /// from `starting_channel` up to and including `ending_channel`).
394 ///
395 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
396 ///
397 /// let dma_buf: [u16; 16] = [
398 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
399 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
400 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
401 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
402 /// ];
403 ///
404 /// Each group of N values (where N = number of channels) is transferred on one update event,
405 /// updating the duty cycles of all selected channels simultaneously.
406 ///
407 /// Note:
408 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
409 pub async fn waveform_up_multi_channel(
410 &mut self,
411 dma: Peri<'_, impl super::UpDma<T>>,
412 starting_channel: Channel,
413 ending_channel: Channel,
414 duty: &[u16],
415 ) {
416 let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32;
417 let start_ch_index = starting_channel.index();
418 let end_ch_index = ending_channel.index();
419
420 assert!(start_ch_index <= end_ch_index);
421
422 let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
423 self.inner
424 .regs_gp16()
425 .dcr()
426 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
427 self.inner
428 .regs_gp16()
429 .dcr()
430 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
431
432 #[allow(clippy::let_unit_value)] // eg. stm32f334
433 let req = dma.request();
434
435 let original_update_dma_state = self.inner.get_update_dma_state();
436 if !original_update_dma_state {
437 self.inner.enable_update_dma(true);
438 }
439
440 unsafe {
441 #[cfg(not(any(bdma, gpdma)))]
442 use crate::dma::{Burst, FifoThreshold};
443 use crate::dma::{Transfer, TransferOptions};
444
445 let dma_transfer_option = TransferOptions {
446 #[cfg(not(any(bdma, gpdma)))]
447 fifo_threshold: Some(FifoThreshold::Full),
448 #[cfg(not(any(bdma, gpdma)))]
449 mburst: Burst::Incr4,
450 ..Default::default()
451 };
452
453 Transfer::new_write(
454 dma,
455 req,
456 duty,
457 self.inner.regs_gp16().dmar().as_ptr() as *mut u16,
458 dma_transfer_option,
459 )
460 .await
461 };
462
463 if !original_update_dma_state {
464 self.inner.enable_update_dma(false);
465 }
466 }
218} 467}
219 468
220macro_rules! impl_waveform_chx { 469macro_rules! impl_waveform_chx {
221 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { 470 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
222 impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { 471 impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
223 /// Generate a sequence of PWM waveform 472 /// Generate a sequence of PWM waveform
224 /// 473 pub async fn $fn_name(&mut self, dma: Peri<'_, impl super::$dma_ch<T>>, duty: &[u16]) {
225 /// Note:
226 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
227 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
228 use crate::pac::timer::vals::Ccds; 474 use crate::pac::timer::vals::Ccds;
229 475
230 into_ref!(dma);
231
232 #[allow(clippy::let_unit_value)] // eg. stm32f334 476 #[allow(clippy::let_unit_value)] // eg. stm32f334
233 let req = dma.request(); 477 let req = dma.request();
234 478
235 let cc_channel = Channel::$cc_ch; 479 let cc_channel = Channel::$cc_ch;
236 480
237 let original_duty_state = self.get_duty(cc_channel); 481 let original_duty_state = self.channel(cc_channel).current_duty_cycle();
238 let original_enable_state = self.is_enabled(cc_channel); 482 let original_enable_state = self.channel(cc_channel).is_enabled();
239 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE; 483 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
240 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); 484 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
241 485
242 // redirect CC DMA request onto Update Event 486 // redirect CC DMA request onto Update Event
243 if !original_cc_dma_on_update { 487 if !original_cc_dma_on_update {
244 self.inner.set_cc_dma_selection(Ccds::ONUPDATE) 488 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
245 } 489 }
246 490
247 if !original_cc_dma_enabled { 491 if !original_cc_dma_enabled {
@@ -249,7 +493,7 @@ macro_rules! impl_waveform_chx {
249 } 493 }
250 494
251 if !original_enable_state { 495 if !original_enable_state {
252 self.enable(cc_channel); 496 self.channel(cc_channel).enable();
253 } 497 }
254 498
255 unsafe { 499 unsafe {
@@ -265,22 +509,41 @@ macro_rules! impl_waveform_chx {
265 ..Default::default() 509 ..Default::default()
266 }; 510 };
267 511
268 Transfer::new_write( 512 match self.inner.bits() {
269 &mut dma, 513 TimerBits::Bits16 => {
270 req, 514 Transfer::new_write(
271 duty, 515 dma,
272 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, 516 req,
273 dma_transfer_option, 517 duty,
274 ) 518 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
275 .await 519 dma_transfer_option,
520 )
521 .await
522 }
523 #[cfg(not(any(stm32l0)))]
524 TimerBits::Bits32 => {
525 #[cfg(not(any(bdma, gpdma)))]
526 panic!("unsupported timer bits");
527
528 #[cfg(any(bdma, gpdma))]
529 Transfer::new_write(
530 dma,
531 req,
532 duty,
533 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
534 dma_transfer_option,
535 )
536 .await
537 }
538 };
276 }; 539 };
277 540
278 // restore output compare state 541 // restore output compare state
279 if !original_enable_state { 542 if !original_enable_state {
280 self.disable(cc_channel); 543 self.channel(cc_channel).disable();
281 } 544 }
282 545
283 self.set_duty(cc_channel, original_duty_state); 546 self.channel(cc_channel).set_duty_cycle(original_duty_state);
284 547
285 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, 548 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
286 // this can almost always trigger a DMA FIFO error. 549 // this can almost always trigger a DMA FIFO error.
@@ -292,7 +555,7 @@ macro_rules! impl_waveform_chx {
292 } 555 }
293 556
294 if !original_cc_dma_on_update { 557 if !original_cc_dma_on_update {
295 self.inner.set_cc_dma_selection(Ccds::ONCOMPARE) 558 self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
296 } 559 }
297 } 560 }
298 } 561 }
@@ -304,6 +567,41 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
304impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); 567impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
305impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); 568impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
306 569
570impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> {
571 type Error = core::convert::Infallible;
572}
573
574impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> {
575 fn max_duty_cycle(&self) -> u16 {
576 self.max_duty_cycle()
577 }
578
579 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
580 self.set_duty_cycle(duty);
581 Ok(())
582 }
583
584 fn set_duty_cycle_fully_off(&mut self) -> Result<(), Self::Error> {
585 self.set_duty_cycle_fully_off();
586 Ok(())
587 }
588
589 fn set_duty_cycle_fully_on(&mut self) -> Result<(), Self::Error> {
590 self.set_duty_cycle_fully_on();
591 Ok(())
592 }
593
594 fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> {
595 self.set_duty_cycle_fraction(num, denom);
596 Ok(())
597 }
598
599 fn set_duty_cycle_percent(&mut self, percent: u8) -> Result<(), Self::Error> {
600 self.set_duty_cycle_percent(percent);
601 Ok(())
602 }
603}
604
307impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { 605impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
308 type Channel = Channel; 606 type Channel = Channel;
309 type Time = Hertz; 607 type Time = Hertz;
@@ -330,7 +628,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
330 } 628 }
331 629
332 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 630 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
333 assert!(duty <= self.get_max_duty()); 631 assert!(duty <= self.max_duty_cycle() as u32);
334 self.inner.set_compare_value(channel, duty) 632 self.inner.set_compare_value(channel, duty)
335 } 633 }
336 634
diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs
new file mode 100644
index 000000000..6791ef6c1
--- /dev/null
+++ b/embassy-stm32/src/tsc/acquisition_banks.rs
@@ -0,0 +1,209 @@
1use super::io_pin::*;
2#[cfg(any(tsc_v2, tsc_v3))]
3use super::pin_groups::G7;
4#[cfg(tsc_v3)]
5use super::pin_groups::G8;
6use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6};
7use super::types::{Group, GroupStatus};
8use super::TSC_NUM_GROUPS;
9
10/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank.
11///
12/// This struct holds optional `tsc::IOPin` values for each TSC group, allowing for flexible
13/// configuration of TSC acquisition banks. Each field corresponds to a specific TSC group
14/// and can be set to `Some(tsc::IOPin)` if that group is to be included in the acquisition,
15/// or `None` if it should be excluded.
16#[allow(missing_docs)]
17#[derive(Default)]
18pub struct AcquisitionBankPins {
19 pub g1_pin: Option<IOPinWithRole<G1, pin_roles::Channel>>,
20 pub g2_pin: Option<IOPinWithRole<G2, pin_roles::Channel>>,
21 pub g3_pin: Option<IOPinWithRole<G3, pin_roles::Channel>>,
22 pub g4_pin: Option<IOPinWithRole<G4, pin_roles::Channel>>,
23 pub g5_pin: Option<IOPinWithRole<G5, pin_roles::Channel>>,
24 pub g6_pin: Option<IOPinWithRole<G6, pin_roles::Channel>>,
25 #[cfg(any(tsc_v2, tsc_v3))]
26 pub g7_pin: Option<IOPinWithRole<G7, pin_roles::Channel>>,
27 #[cfg(tsc_v3)]
28 pub g8_pin: Option<IOPinWithRole<G8, pin_roles::Channel>>,
29}
30
31impl AcquisitionBankPins {
32 /// Returns an iterator over the pins in this acquisition bank.
33 ///
34 /// This method allows for easy traversal of all configured pins in the bank.
35 pub fn iter(&self) -> AcquisitionBankPinsIterator {
36 AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self))
37 }
38}
39
40/// Iterator for TSC acquisition banks.
41///
42/// This iterator allows traversing through the pins of a `AcquisitionBankPins` struct,
43/// yielding each configured pin in order of the TSC groups.
44pub struct AcquisitionBankIterator<'a> {
45 pins: &'a AcquisitionBankPins,
46 current_group: u8,
47}
48
49impl<'a> AcquisitionBankIterator<'a> {
50 fn new(pins: &'a AcquisitionBankPins) -> Self {
51 Self { pins, current_group: 0 }
52 }
53
54 fn next_pin(&mut self) -> Option<IOPin> {
55 while self.current_group < TSC_NUM_GROUPS as u8 {
56 let pin = match self.current_group {
57 0 => self.pins.g1_pin.map(IOPinWithRole::get_pin),
58 1 => self.pins.g2_pin.map(IOPinWithRole::get_pin),
59 2 => self.pins.g3_pin.map(IOPinWithRole::get_pin),
60 3 => self.pins.g4_pin.map(IOPinWithRole::get_pin),
61 4 => self.pins.g5_pin.map(IOPinWithRole::get_pin),
62 5 => self.pins.g6_pin.map(IOPinWithRole::get_pin),
63 #[cfg(any(tsc_v2, tsc_v3))]
64 6 => self.pins.g7_pin.map(IOPinWithRole::get_pin),
65 #[cfg(tsc_v3)]
66 7 => self.pins.g8_pin.map(IOPinWithRole::get_pin),
67 _ => None,
68 };
69 self.current_group += 1;
70 if pin.is_some() {
71 return pin;
72 }
73 }
74 None
75 }
76}
77
78/// Iterator for TSC acquisition bank pins.
79///
80/// This iterator yields `tsc::IOPin` values for each configured pin in the acquisition bank.
81pub struct AcquisitionBankPinsIterator<'a>(AcquisitionBankIterator<'a>);
82
83impl<'a> Iterator for AcquisitionBankPinsIterator<'a> {
84 type Item = IOPin;
85
86 fn next(&mut self) -> Option<Self::Item> {
87 self.0.next_pin()
88 }
89}
90
91impl AcquisitionBankPins {
92 /// Returns an iterator over the available pins in the bank
93 pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator {
94 AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self))
95 }
96}
97
98/// Represents a collection of TSC pins to be acquired simultaneously.
99///
100/// This struct contains a set of pins to be used in a TSC acquisition with a pre-computed and
101/// verified mask for efficiently setting up the TSC peripheral before performing an acquisition.
102/// It ensures that only one channel pin per TSC group is included, adhering to hardware limitations.
103pub struct AcquisitionBank {
104 pub(super) pins: AcquisitionBankPins,
105 pub(super) mask: u32,
106}
107
108impl AcquisitionBank {
109 /// Returns an iterator over the available pins in the bank.
110 pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator {
111 self.pins.pins_iterator()
112 }
113
114 /// Returns the mask for this bank.
115 pub fn mask(&self) -> u32 {
116 self.mask
117 }
118
119 /// Retrieves the TSC I/O pin for a given group in this acquisition bank.
120 ///
121 /// # Arguments
122 /// * `group` - The TSC group to retrieve the pin for.
123 ///
124 /// # Returns
125 /// An `Option<tsc::IOPin>` containing the pin if it exists for the given group, or `None` if not.
126 pub fn get_pin(&self, group: Group) -> Option<IOPin> {
127 match group {
128 Group::One => self.pins.g1_pin.map(|p| p.pin),
129 Group::Two => self.pins.g2_pin.map(|p| p.pin),
130 Group::Three => self.pins.g3_pin.map(|p| p.pin),
131 Group::Four => self.pins.g4_pin.map(|p| p.pin),
132 Group::Five => self.pins.g5_pin.map(|p| p.pin),
133 Group::Six => self.pins.g6_pin.map(|p| p.pin),
134 #[cfg(any(tsc_v2, tsc_v3))]
135 Group::Seven => self.pins.g7_pin.map(|p| p.pin),
136 #[cfg(tsc_v3)]
137 Group::Eight => self.pins.g8_pin.map(|p| p.pin),
138 }
139 }
140}
141
142/// Represents the status of all TSC groups in an acquisition bank
143#[derive(Default)]
144pub struct AcquisitionBankStatus {
145 pub(super) groups: [Option<GroupStatus>; TSC_NUM_GROUPS],
146}
147
148impl AcquisitionBankStatus {
149 /// Check if all groups in the bank are complete
150 pub fn all_complete(&self) -> bool {
151 self.groups
152 .iter()
153 .all(|&status| status.map_or(true, |s| s == GroupStatus::Complete))
154 }
155
156 /// Check if any group in the bank is ongoing
157 pub fn any_ongoing(&self) -> bool {
158 self.groups.iter().any(|&status| status == Some(GroupStatus::Ongoing))
159 }
160
161 /// Get the status of a specific group, if the group is present in the bank
162 pub fn get_group_status(&self, group: Group) -> Option<GroupStatus> {
163 let index: usize = group.into();
164 self.groups[index]
165 }
166
167 /// Iterator for groups present in the bank
168 pub fn iter(&self) -> impl Iterator<Item = (Group, GroupStatus)> + '_ {
169 self.groups.iter().enumerate().filter_map(|(group_num, status)| {
170 status.and_then(|s| Group::try_from(group_num).ok().map(|group| (group, s)))
171 })
172 }
173}
174
175/// Represents the result of a Touch Sensing Controller (TSC) acquisition for a specific pin.
176///
177/// This struct contains a reference to the `tsc::IOPin` from which a value was read,
178/// along with the actual sensor reading for that pin. It provides a convenient way
179/// to associate TSC readings with their corresponding pins after an acquisition.
180#[cfg_attr(feature = "defmt", derive(defmt::Format))]
181#[derive(Clone, Copy, Debug)]
182pub struct ChannelReading {
183 /// The sensor reading value obtained from the TSC acquisition.
184 /// Lower values typically indicate a detected touch, while higher values indicate no touch.
185 pub sensor_value: u16,
186
187 /// The `tsc::IOPin` associated with this reading.
188 /// This allows for easy identification of which pin the reading corresponds to.
189 pub tsc_pin: IOPin,
190}
191
192/// Represents the readings from all TSC groups
193#[derive(Default)]
194pub struct AcquisitionBankReadings {
195 pub(super) groups: [Option<ChannelReading>; TSC_NUM_GROUPS],
196}
197
198impl AcquisitionBankReadings {
199 /// Get the reading for a specific group, if the group is present in the bank
200 pub fn get_group_reading(&self, group: Group) -> Option<ChannelReading> {
201 let index: usize = group.into();
202 self.groups[index]
203 }
204
205 /// Iterator for readings for groups present in the bank
206 pub fn iter(&self) -> impl Iterator<Item = ChannelReading> + '_ {
207 self.groups.iter().filter_map(|&x| x)
208 }
209}
diff --git a/embassy-stm32/src/tsc/config.rs b/embassy-stm32/src/tsc/config.rs
new file mode 100644
index 000000000..efa1f9a0d
--- /dev/null
+++ b/embassy-stm32/src/tsc/config.rs
@@ -0,0 +1,175 @@
1/// Charge transfer pulse cycles
2#[allow(missing_docs)]
3#[derive(Copy, Clone, PartialEq)]
4pub enum ChargeTransferPulseCycle {
5 _1,
6 _2,
7 _3,
8 _4,
9 _5,
10 _6,
11 _7,
12 _8,
13 _9,
14 _10,
15 _11,
16 _12,
17 _13,
18 _14,
19 _15,
20 _16,
21}
22
23impl Into<u8> for ChargeTransferPulseCycle {
24 fn into(self) -> u8 {
25 match self {
26 ChargeTransferPulseCycle::_1 => 0,
27 ChargeTransferPulseCycle::_2 => 1,
28 ChargeTransferPulseCycle::_3 => 2,
29 ChargeTransferPulseCycle::_4 => 3,
30 ChargeTransferPulseCycle::_5 => 4,
31 ChargeTransferPulseCycle::_6 => 5,
32 ChargeTransferPulseCycle::_7 => 6,
33 ChargeTransferPulseCycle::_8 => 7,
34 ChargeTransferPulseCycle::_9 => 8,
35 ChargeTransferPulseCycle::_10 => 9,
36 ChargeTransferPulseCycle::_11 => 10,
37 ChargeTransferPulseCycle::_12 => 11,
38 ChargeTransferPulseCycle::_13 => 12,
39 ChargeTransferPulseCycle::_14 => 13,
40 ChargeTransferPulseCycle::_15 => 14,
41 ChargeTransferPulseCycle::_16 => 15,
42 }
43 }
44}
45
46/// Max count
47#[allow(missing_docs)]
48#[derive(Copy, Clone)]
49pub enum MaxCount {
50 _255,
51 _511,
52 _1023,
53 _2047,
54 _4095,
55 _8191,
56 _16383,
57}
58
59impl Into<u8> for MaxCount {
60 fn into(self) -> u8 {
61 match self {
62 MaxCount::_255 => 0,
63 MaxCount::_511 => 1,
64 MaxCount::_1023 => 2,
65 MaxCount::_2047 => 3,
66 MaxCount::_4095 => 4,
67 MaxCount::_8191 => 5,
68 MaxCount::_16383 => 6,
69 }
70 }
71}
72
73/// Prescaler divider
74#[allow(missing_docs)]
75#[derive(Copy, Clone, PartialEq)]
76pub enum PGPrescalerDivider {
77 _1,
78 _2,
79 _4,
80 _8,
81 _16,
82 _32,
83 _64,
84 _128,
85}
86
87impl Into<u8> for PGPrescalerDivider {
88 fn into(self) -> u8 {
89 match self {
90 PGPrescalerDivider::_1 => 0,
91 PGPrescalerDivider::_2 => 1,
92 PGPrescalerDivider::_4 => 2,
93 PGPrescalerDivider::_8 => 3,
94 PGPrescalerDivider::_16 => 4,
95 PGPrescalerDivider::_32 => 5,
96 PGPrescalerDivider::_64 => 6,
97 PGPrescalerDivider::_128 => 7,
98 }
99 }
100}
101
102/// Error type for SSDeviation
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub enum SSDeviationError {
105 /// The provided value is too low (0)
106 ValueTooLow,
107 /// The provided value is too high (greater than 128)
108 ValueTooHigh,
109}
110
111/// Spread Spectrum Deviation
112#[derive(Copy, Clone)]
113pub struct SSDeviation(u8);
114impl SSDeviation {
115 /// Create new deviation value, acceptable inputs are 1-128
116 pub fn new(val: u8) -> Result<Self, SSDeviationError> {
117 if val == 0 {
118 return Err(SSDeviationError::ValueTooLow);
119 } else if val > 128 {
120 return Err(SSDeviationError::ValueTooHigh);
121 }
122 Ok(Self(val - 1))
123 }
124}
125
126impl Into<u8> for SSDeviation {
127 fn into(self) -> u8 {
128 self.0
129 }
130}
131
132/// Peripheral configuration
133#[derive(Clone, Copy)]
134pub struct Config {
135 /// Duration of high state of the charge transfer pulse
136 pub ct_pulse_high_length: ChargeTransferPulseCycle,
137 /// Duration of the low state of the charge transfer pulse
138 pub ct_pulse_low_length: ChargeTransferPulseCycle,
139 /// Enable/disable of spread spectrum feature
140 pub spread_spectrum: bool,
141 /// Adds variable number of periods of the SS clk to pulse high state
142 pub spread_spectrum_deviation: SSDeviation,
143 /// Selects AHB clock divider used to generate SS clk
144 pub spread_spectrum_prescaler: bool,
145 /// Selects AHB clock divider used to generate pulse generator clk
146 pub pulse_generator_prescaler: PGPrescalerDivider,
147 /// Maximum number of charge transfer pulses that can be generated before error
148 pub max_count_value: MaxCount,
149 /// Defines config of all IOs when no ongoing acquisition
150 pub io_default_mode: bool,
151 /// Polarity of sync input pin
152 pub synchro_pin_polarity: bool,
153 /// Acquisition starts when start bit is set or with sync pin input
154 pub acquisition_mode: bool,
155 /// Enable max count interrupt
156 pub max_count_interrupt: bool,
157}
158
159impl Default for Config {
160 fn default() -> Self {
161 Self {
162 ct_pulse_high_length: ChargeTransferPulseCycle::_1,
163 ct_pulse_low_length: ChargeTransferPulseCycle::_1,
164 spread_spectrum: false,
165 spread_spectrum_deviation: SSDeviation::new(1).unwrap(),
166 spread_spectrum_prescaler: false,
167 pulse_generator_prescaler: PGPrescalerDivider::_1,
168 max_count_value: MaxCount::_255,
169 io_default_mode: false,
170 synchro_pin_polarity: false,
171 acquisition_mode: false,
172 max_count_interrupt: false,
173 }
174 }
175}
diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/enums.rs
deleted file mode 100644
index 0d34a43ec..000000000
--- a/embassy-stm32/src/tsc/enums.rs
+++ /dev/null
@@ -1,238 +0,0 @@
1use core::ops::BitOr;
2
3/// Pin defines
4#[allow(missing_docs)]
5pub enum TscIOPin {
6 Group1Io1,
7 Group1Io2,
8 Group1Io3,
9 Group1Io4,
10 Group2Io1,
11 Group2Io2,
12 Group2Io3,
13 Group2Io4,
14 Group3Io1,
15 Group3Io2,
16 Group3Io3,
17 Group3Io4,
18 Group4Io1,
19 Group4Io2,
20 Group4Io3,
21 Group4Io4,
22 Group5Io1,
23 Group5Io2,
24 Group5Io3,
25 Group5Io4,
26 Group6Io1,
27 Group6Io2,
28 Group6Io3,
29 Group6Io4,
30 #[cfg(any(tsc_v2, tsc_v3))]
31 Group7Io1,
32 #[cfg(any(tsc_v2, tsc_v3))]
33 Group7Io2,
34 #[cfg(any(tsc_v2, tsc_v3))]
35 Group7Io3,
36 #[cfg(any(tsc_v2, tsc_v3))]
37 Group7Io4,
38 #[cfg(tsc_v3)]
39 Group8Io1,
40 #[cfg(tsc_v3)]
41 Group8Io2,
42 #[cfg(tsc_v3)]
43 Group8Io3,
44 #[cfg(tsc_v3)]
45 Group8Io4,
46}
47
48impl BitOr<TscIOPin> for u32 {
49 type Output = u32;
50 fn bitor(self, rhs: TscIOPin) -> Self::Output {
51 let rhs: u32 = rhs.into();
52 self | rhs
53 }
54}
55
56impl BitOr<u32> for TscIOPin {
57 type Output = u32;
58 fn bitor(self, rhs: u32) -> Self::Output {
59 let val: u32 = self.into();
60 val | rhs
61 }
62}
63
64impl BitOr for TscIOPin {
65 type Output = u32;
66 fn bitor(self, rhs: Self) -> Self::Output {
67 let val: u32 = self.into();
68 let rhs: u32 = rhs.into();
69 val | rhs
70 }
71}
72
73impl Into<u32> for TscIOPin {
74 fn into(self) -> u32 {
75 match self {
76 TscIOPin::Group1Io1 => 0x00000001,
77 TscIOPin::Group1Io2 => 0x00000002,
78 TscIOPin::Group1Io3 => 0x00000004,
79 TscIOPin::Group1Io4 => 0x00000008,
80 TscIOPin::Group2Io1 => 0x00000010,
81 TscIOPin::Group2Io2 => 0x00000020,
82 TscIOPin::Group2Io3 => 0x00000040,
83 TscIOPin::Group2Io4 => 0x00000080,
84 TscIOPin::Group3Io1 => 0x00000100,
85 TscIOPin::Group3Io2 => 0x00000200,
86 TscIOPin::Group3Io3 => 0x00000400,
87 TscIOPin::Group3Io4 => 0x00000800,
88 TscIOPin::Group4Io1 => 0x00001000,
89 TscIOPin::Group4Io2 => 0x00002000,
90 TscIOPin::Group4Io3 => 0x00004000,
91 TscIOPin::Group4Io4 => 0x00008000,
92 TscIOPin::Group5Io1 => 0x00010000,
93 TscIOPin::Group5Io2 => 0x00020000,
94 TscIOPin::Group5Io3 => 0x00040000,
95 TscIOPin::Group5Io4 => 0x00080000,
96 TscIOPin::Group6Io1 => 0x00100000,
97 TscIOPin::Group6Io2 => 0x00200000,
98 TscIOPin::Group6Io3 => 0x00400000,
99 TscIOPin::Group6Io4 => 0x00800000,
100 #[cfg(any(tsc_v2, tsc_v3))]
101 TscIOPin::Group7Io1 => 0x01000000,
102 #[cfg(any(tsc_v2, tsc_v3))]
103 TscIOPin::Group7Io2 => 0x02000000,
104 #[cfg(any(tsc_v2, tsc_v3))]
105 TscIOPin::Group7Io3 => 0x04000000,
106 #[cfg(any(tsc_v2, tsc_v3))]
107 TscIOPin::Group7Io4 => 0x08000000,
108 #[cfg(tsc_v3)]
109 TscIOPin::Group8Io1 => 0x10000000,
110 #[cfg(tsc_v3)]
111 TscIOPin::Group8Io2 => 0x20000000,
112 #[cfg(tsc_v3)]
113 TscIOPin::Group8Io3 => 0x40000000,
114 #[cfg(tsc_v3)]
115 TscIOPin::Group8Io4 => 0x80000000,
116 }
117 }
118}
119
120/// Spread Spectrum Deviation
121#[derive(Copy, Clone)]
122pub struct SSDeviation(u8);
123impl SSDeviation {
124 /// Create new deviation value, acceptable inputs are 1-128
125 pub fn new(val: u8) -> Result<Self, ()> {
126 if val == 0 || val > 128 {
127 return Err(());
128 }
129 Ok(Self(val - 1))
130 }
131}
132
133impl Into<u8> for SSDeviation {
134 fn into(self) -> u8 {
135 self.0
136 }
137}
138
139/// Charge transfer pulse cycles
140#[allow(missing_docs)]
141#[derive(Copy, Clone, PartialEq)]
142pub enum ChargeTransferPulseCycle {
143 _1,
144 _2,
145 _3,
146 _4,
147 _5,
148 _6,
149 _7,
150 _8,
151 _9,
152 _10,
153 _11,
154 _12,
155 _13,
156 _14,
157 _15,
158 _16,
159}
160
161impl Into<u8> for ChargeTransferPulseCycle {
162 fn into(self) -> u8 {
163 match self {
164 ChargeTransferPulseCycle::_1 => 0,
165 ChargeTransferPulseCycle::_2 => 1,
166 ChargeTransferPulseCycle::_3 => 2,
167 ChargeTransferPulseCycle::_4 => 3,
168 ChargeTransferPulseCycle::_5 => 4,
169 ChargeTransferPulseCycle::_6 => 5,
170 ChargeTransferPulseCycle::_7 => 6,
171 ChargeTransferPulseCycle::_8 => 7,
172 ChargeTransferPulseCycle::_9 => 8,
173 ChargeTransferPulseCycle::_10 => 9,
174 ChargeTransferPulseCycle::_11 => 10,
175 ChargeTransferPulseCycle::_12 => 11,
176 ChargeTransferPulseCycle::_13 => 12,
177 ChargeTransferPulseCycle::_14 => 13,
178 ChargeTransferPulseCycle::_15 => 14,
179 ChargeTransferPulseCycle::_16 => 15,
180 }
181 }
182}
183
184/// Prescaler divider
185#[allow(missing_docs)]
186#[derive(Copy, Clone, PartialEq)]
187pub enum PGPrescalerDivider {
188 _1,
189 _2,
190 _4,
191 _8,
192 _16,
193 _32,
194 _64,
195 _128,
196}
197
198impl Into<u8> for PGPrescalerDivider {
199 fn into(self) -> u8 {
200 match self {
201 PGPrescalerDivider::_1 => 0,
202 PGPrescalerDivider::_2 => 1,
203 PGPrescalerDivider::_4 => 2,
204 PGPrescalerDivider::_8 => 3,
205 PGPrescalerDivider::_16 => 4,
206 PGPrescalerDivider::_32 => 5,
207 PGPrescalerDivider::_64 => 6,
208 PGPrescalerDivider::_128 => 7,
209 }
210 }
211}
212
213/// Max count
214#[allow(missing_docs)]
215#[derive(Copy, Clone)]
216pub enum MaxCount {
217 _255,
218 _511,
219 _1023,
220 _2047,
221 _4095,
222 _8191,
223 _16383,
224}
225
226impl Into<u8> for MaxCount {
227 fn into(self) -> u8 {
228 match self {
229 MaxCount::_255 => 0,
230 MaxCount::_511 => 1,
231 MaxCount::_1023 => 2,
232 MaxCount::_2047 => 3,
233 MaxCount::_4095 => 4,
234 MaxCount::_8191 => 5,
235 MaxCount::_16383 => 6,
236 }
237 }
238}
diff --git a/embassy-stm32/src/tsc/errors.rs b/embassy-stm32/src/tsc/errors.rs
new file mode 100644
index 000000000..21f6441ba
--- /dev/null
+++ b/embassy-stm32/src/tsc/errors.rs
@@ -0,0 +1,21 @@
1/// Represents errors that can occur when configuring or validating TSC pin groups.
2#[derive(Debug)]
3pub enum GroupError {
4 /// Error when a group has no sampling capacitor
5 NoSamplingCapacitor,
6 /// Error when a group has neither channel IOs nor a shield IO
7 NoChannelOrShield,
8 /// Error when a group has both channel IOs and a shield IO
9 MixedChannelAndShield,
10 /// Error when there is more than one shield IO across all groups
11 MultipleShields,
12}
13
14/// Error returned when attempting to set an invalid channel pin as active in the TSC.
15#[derive(Debug)]
16pub enum AcquisitionBankError {
17 /// Indicates that one or more of the provided pins is not a valid channel pin.
18 InvalidChannelPin,
19 /// Indicates that multiple channels from the same group were provided.
20 MultipleChannelsPerGroup,
21}
diff --git a/embassy-stm32/src/tsc/io_pin.rs b/embassy-stm32/src/tsc/io_pin.rs
new file mode 100644
index 000000000..ad2010ed7
--- /dev/null
+++ b/embassy-stm32/src/tsc/io_pin.rs
@@ -0,0 +1,200 @@
1use core::marker::PhantomData;
2use core::ops::{BitAnd, BitOr, BitOrAssign};
3
4use super::pin_roles;
5use super::types::Group;
6
7/// Pin defines
8#[allow(missing_docs)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10#[derive(PartialEq, Clone, Copy, Debug)]
11pub enum IOPin {
12 Group1Io1,
13 Group1Io2,
14 Group1Io3,
15 Group1Io4,
16 Group2Io1,
17 Group2Io2,
18 Group2Io3,
19 Group2Io4,
20 Group3Io1,
21 Group3Io2,
22 Group3Io3,
23 Group3Io4,
24 Group4Io1,
25 Group4Io2,
26 Group4Io3,
27 Group4Io4,
28 Group5Io1,
29 Group5Io2,
30 Group5Io3,
31 Group5Io4,
32 Group6Io1,
33 Group6Io2,
34 Group6Io3,
35 Group6Io4,
36 #[cfg(any(tsc_v2, tsc_v3))]
37 Group7Io1,
38 #[cfg(any(tsc_v2, tsc_v3))]
39 Group7Io2,
40 #[cfg(any(tsc_v2, tsc_v3))]
41 Group7Io3,
42 #[cfg(any(tsc_v2, tsc_v3))]
43 Group7Io4,
44 #[cfg(tsc_v3)]
45 Group8Io1,
46 #[cfg(tsc_v3)]
47 Group8Io2,
48 #[cfg(tsc_v3)]
49 Group8Io3,
50 #[cfg(tsc_v3)]
51 Group8Io4,
52}
53
54/// Represents a TSC I/O pin with associated group and role information.
55///
56/// This type combines an `tsc::IOPin` with phantom type parameters to statically
57/// encode the pin's group and role. This allows for type-safe operations
58/// on TSC pins within their specific contexts.
59///
60/// - `Group`: A type parameter representing the TSC group (e.g., `G1`, `G2`).
61/// - `Role`: A type parameter representing the pin's role (e.g., `Channel`, `Sample`).
62#[derive(Clone, Copy, Debug)]
63pub struct IOPinWithRole<Group, Role: pin_roles::Role> {
64 /// The underlying TSC I/O pin.
65 pub pin: IOPin,
66 pub(super) phantom: PhantomData<(Group, Role)>,
67}
68
69impl<G, R: pin_roles::Role> IOPinWithRole<G, R> {
70 pub(super) fn get_pin(wrapped_pin: IOPinWithRole<G, R>) -> IOPin {
71 wrapped_pin.pin
72 }
73}
74
75impl IOPin {
76 /// Maps this IOPin to the Group it belongs to.
77 ///
78 /// This method provides a convenient way to determine which Group
79 /// a specific TSC I/O pin is associated with.
80 pub const fn group(&self) -> Group {
81 match self {
82 IOPin::Group1Io1 | IOPin::Group1Io2 | IOPin::Group1Io3 | IOPin::Group1Io4 => Group::One,
83 IOPin::Group2Io1 | IOPin::Group2Io2 | IOPin::Group2Io3 | IOPin::Group2Io4 => Group::Two,
84 IOPin::Group3Io1 | IOPin::Group3Io2 | IOPin::Group3Io3 | IOPin::Group3Io4 => Group::Three,
85 IOPin::Group4Io1 | IOPin::Group4Io2 | IOPin::Group4Io3 | IOPin::Group4Io4 => Group::Four,
86 IOPin::Group5Io1 | IOPin::Group5Io2 | IOPin::Group5Io3 | IOPin::Group5Io4 => Group::Five,
87 IOPin::Group6Io1 | IOPin::Group6Io2 | IOPin::Group6Io3 | IOPin::Group6Io4 => Group::Six,
88 #[cfg(any(tsc_v2, tsc_v3))]
89 IOPin::Group7Io1 | IOPin::Group7Io2 | IOPin::Group7Io3 | IOPin::Group7Io4 => Group::Seven,
90 #[cfg(tsc_v3)]
91 IOPin::Group8Io1 | IOPin::Group8Io2 | IOPin::Group8Io3 | IOPin::Group8Io4 => Group::Eight,
92 }
93 }
94
95 /// Returns the `Group` associated with the given `IOPin`.
96 pub fn get_group(pin: IOPin) -> Group {
97 pin.group()
98 }
99}
100
101impl BitOr<IOPin> for u32 {
102 type Output = u32;
103 fn bitor(self, rhs: IOPin) -> Self::Output {
104 let rhs: u32 = rhs.into();
105 self | rhs
106 }
107}
108
109impl BitOr<u32> for IOPin {
110 type Output = u32;
111 fn bitor(self, rhs: u32) -> Self::Output {
112 let val: u32 = self.into();
113 val | rhs
114 }
115}
116
117impl BitOr for IOPin {
118 type Output = u32;
119 fn bitor(self, rhs: Self) -> Self::Output {
120 let val: u32 = self.into();
121 let rhs: u32 = rhs.into();
122 val | rhs
123 }
124}
125
126impl BitOrAssign<IOPin> for u32 {
127 fn bitor_assign(&mut self, rhs: IOPin) {
128 let rhs: u32 = rhs.into();
129 *self |= rhs;
130 }
131}
132
133impl BitAnd<IOPin> for u32 {
134 type Output = u32;
135 fn bitand(self, rhs: IOPin) -> Self::Output {
136 let rhs: u32 = rhs.into();
137 self & rhs
138 }
139}
140
141impl BitAnd<u32> for IOPin {
142 type Output = u32;
143 fn bitand(self, rhs: u32) -> Self::Output {
144 let val: u32 = self.into();
145 val & rhs
146 }
147}
148
149impl IOPin {
150 const fn to_u32(self) -> u32 {
151 match self {
152 IOPin::Group1Io1 => 0x00000001,
153 IOPin::Group1Io2 => 0x00000002,
154 IOPin::Group1Io3 => 0x00000004,
155 IOPin::Group1Io4 => 0x00000008,
156 IOPin::Group2Io1 => 0x00000010,
157 IOPin::Group2Io2 => 0x00000020,
158 IOPin::Group2Io3 => 0x00000040,
159 IOPin::Group2Io4 => 0x00000080,
160 IOPin::Group3Io1 => 0x00000100,
161 IOPin::Group3Io2 => 0x00000200,
162 IOPin::Group3Io3 => 0x00000400,
163 IOPin::Group3Io4 => 0x00000800,
164 IOPin::Group4Io1 => 0x00001000,
165 IOPin::Group4Io2 => 0x00002000,
166 IOPin::Group4Io3 => 0x00004000,
167 IOPin::Group4Io4 => 0x00008000,
168 IOPin::Group5Io1 => 0x00010000,
169 IOPin::Group5Io2 => 0x00020000,
170 IOPin::Group5Io3 => 0x00040000,
171 IOPin::Group5Io4 => 0x00080000,
172 IOPin::Group6Io1 => 0x00100000,
173 IOPin::Group6Io2 => 0x00200000,
174 IOPin::Group6Io3 => 0x00400000,
175 IOPin::Group6Io4 => 0x00800000,
176 #[cfg(any(tsc_v2, tsc_v3))]
177 IOPin::Group7Io1 => 0x01000000,
178 #[cfg(any(tsc_v2, tsc_v3))]
179 IOPin::Group7Io2 => 0x02000000,
180 #[cfg(any(tsc_v2, tsc_v3))]
181 IOPin::Group7Io3 => 0x04000000,
182 #[cfg(any(tsc_v2, tsc_v3))]
183 IOPin::Group7Io4 => 0x08000000,
184 #[cfg(tsc_v3)]
185 IOPin::Group8Io1 => 0x10000000,
186 #[cfg(tsc_v3)]
187 IOPin::Group8Io2 => 0x20000000,
188 #[cfg(tsc_v3)]
189 IOPin::Group8Io3 => 0x40000000,
190 #[cfg(tsc_v3)]
191 IOPin::Group8Io4 => 0x80000000,
192 }
193 }
194}
195
196impl Into<u32> for IOPin {
197 fn into(self) -> u32 {
198 self.to_u32()
199 }
200}
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 17240e6bc..9359d83e9 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -1,90 +1,120 @@
1//! TSC Peripheral Interface 1//! TSC Peripheral Interface
2//! 2//!
3//! This module provides an interface for the Touch Sensing Controller (TSC) peripheral.
4//! It supports both blocking and async modes of operation, as well as different TSC versions (v1, v2, v3).
3//! 5//!
4//! # Example (stm32) 6//! # Key Concepts
5//! ``` rust, ignore
6//! 7//!
7//! let mut device_config = embassy_stm32::Config::default(); 8//! - **Pin Groups**: TSC pins are organized into groups, each containing up to four IOs.
8//! { 9//! - **Pin Roles**: Each pin in a group can have a role: Channel, Sample, or Shield.
9//! device_config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_4MHZ); 10//! - **Acquisition Banks**: Used for efficient, repeated TSC acquisitions on specific sets of pins.
10//! } 11//!
12//! # Example (stm32)
11//! 13//!
14//! ```rust
15//! let device_config = embassy_stm32::Config::default();
12//! let context = embassy_stm32::init(device_config); 16//! let context = embassy_stm32::init(device_config);
13//! 17//!
14//! let config = tsc::Config { 18//! let config = tsc::Config {
15//! ct_pulse_high_length: ChargeTransferPulseCycle::_2, 19//! ct_pulse_high_length: ChargeTransferPulseCycle::_4,
16//! ct_pulse_low_length: ChargeTransferPulseCycle::_2, 20//! ct_pulse_low_length: ChargeTransferPulseCycle::_4,
17//! spread_spectrum: false, 21//! spread_spectrum: false,
18//! spread_spectrum_deviation: SSDeviation::new(2).unwrap(), 22//! spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
19//! spread_spectrum_prescaler: false, 23//! spread_spectrum_prescaler: false,
20//! pulse_generator_prescaler: PGPrescalerDivider::_4, 24//! pulse_generator_prescaler: PGPrescalerDivider::_16,
21//! max_count_value: MaxCount::_8191, 25//! max_count_value: MaxCount::_255,
22//! io_default_mode: false, 26//! io_default_mode: false,
23//! synchro_pin_polarity: false, 27//! synchro_pin_polarity: false,
24//! acquisition_mode: false, 28//! acquisition_mode: false,
25//! max_count_interrupt: false, 29//! max_count_interrupt: false,
26//! channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3,
27//! shield_ios: TscIOPin::Group1Io3.into(),
28//! sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2,
29//! }; 30//! };
30//! 31//!
31//! let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); 32//! let mut g2: PinGroupWithRoles<embassy_stm32::peripherals::TSC, G2> = PinGroupWithRoles::new();
32//! g1.set_io2(context.PB13, PinType::Sample); 33//! g2.set_io1::<tsc_pin_roles::Sample>(context.PB4);
33//! g1.set_io3(context.PB14, PinType::Shield); 34//! let sensor_pin = g2.set_io2::<tsc_pin_roles::Channel>(context.PB5);
34//!
35//! let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new();
36//! g2.set_io1(context.PB4, PinType::Sample);
37//! g2.set_io2(context.PB5, PinType::Channel);
38//! 35//!
39//! let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new(); 36//! let pin_groups = PinGroups {
40//! g7.set_io2(context.PE3, PinType::Sample); 37//! g2: Some(g2.pin_group),
41//! g7.set_io3(context.PE4, PinType::Channel); 38//! ..Default::default()
39//! };
42//! 40//!
43//! let mut touch_controller = tsc::Tsc::new_blocking( 41//! let mut touch_controller = tsc::Tsc::new_blocking(
44//! context.TSC, 42//! context.TSC,
45//! Some(g1), 43//! pin_groups,
46//! Some(g2),
47//! None,
48//! None,
49//! None,
50//! None,
51//! Some(g7),
52//! None,
53//! config, 44//! config,
54//! ); 45//! ).unwrap();
55//! 46//!
56//! touch_controller.discharge_io(true); 47//! let discharge_delay = 5; // ms
57//! Timer::after_millis(1).await;
58//! 48//!
59//! touch_controller.start(); 49//! loop {
50//! touch_controller.set_active_channels_mask(sensor_pin.pin.into());
51//! touch_controller.start();
52//! touch_controller.poll_for_acquisition();
53//! touch_controller.discharge_io(true);
54//! Timer::after_millis(discharge_delay).await;
60//! 55//!
56//! match touch_controller.group_get_status(sensor_pin.pin.group()) {
57//! GroupStatus::Complete => {
58//! let group_val = touch_controller.group_get_value(sensor_pin.pin.group());
59//! // Process the touch value
60//! // ...
61//! }
62//! GroupStatus::Ongoing => {
63//! // Handle ongoing acquisition
64//! // ...
65//! }
66//! }
67//! }
61//! ``` 68//! ```
69//!
70//! # Async Usage
71//!
72//! For async operation, use `Tsc::new_async` and `pend_for_acquisition` instead of polling.
62 73
63#![macro_use] 74#![macro_use]
64 75
65/// Enums defined for peripheral parameters 76/// Configuration structures and enums for the TSC peripheral.
66pub mod enums; 77pub mod config;
78
79/// Definitions and implementations for TSC pin groups.
80pub mod pin_groups;
81
82/// Definitions and implementations for individual TSC I/O pins.
83pub mod io_pin;
84
85/// Structures and implementations for TSC acquisition banks.
86pub mod acquisition_banks;
87
88/// Core implementation of the TSC (Touch Sensing Controller) driver.
89pub mod tsc;
90
91/// Type definitions used throughout the TSC module.
92pub mod types;
93
94/// Error types and definitions for the TSC module.
95pub mod errors;
67 96
68use core::future::poll_fn;
69use core::marker::PhantomData; 97use core::marker::PhantomData;
70use core::task::Poll;
71 98
72use embassy_hal_internal::{into_ref, PeripheralRef}; 99pub use acquisition_banks::*;
100pub use config::*;
101use embassy_hal_internal::PeripheralType;
73use embassy_sync::waitqueue::AtomicWaker; 102use embassy_sync::waitqueue::AtomicWaker;
74pub use enums::*; 103pub use errors::*;
104pub use io_pin::*;
105pub use pin_groups::*;
106pub use tsc::*;
107pub use types::*;
75 108
76use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 109use crate::rcc::RccPeripheral;
77use crate::interrupt::typelevel::Interrupt; 110use crate::{interrupt, peripherals};
78use crate::mode::{Async, Blocking, Mode as PeriMode};
79use crate::rcc::{self, RccPeripheral};
80use crate::{interrupt, peripherals, Peripheral};
81 111
82#[cfg(tsc_v1)] 112#[cfg(tsc_v1)]
83const TSC_NUM_GROUPS: u32 = 6; 113const TSC_NUM_GROUPS: usize = 6;
84#[cfg(tsc_v2)] 114#[cfg(tsc_v2)]
85const TSC_NUM_GROUPS: u32 = 7; 115const TSC_NUM_GROUPS: usize = 7;
86#[cfg(tsc_v3)] 116#[cfg(tsc_v3)]
87const TSC_NUM_GROUPS: u32 = 8; 117const TSC_NUM_GROUPS: usize = 8;
88 118
89/// Error type defined for TSC 119/// Error type defined for TSC
90#[derive(Debug, Clone, Copy)] 120#[derive(Debug, Clone, Copy)]
@@ -106,859 +136,6 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
106 } 136 }
107} 137}
108 138
109/// Pin type definition to control IO parameters
110pub enum PinType {
111 /// Sensing channel pin connected to an electrode
112 Channel,
113 /// Sampling capacitor pin, one required for every pin group
114 Sample,
115 /// Shield pin connected to capacitive sensing shield
116 Shield,
117}
118
119/// Peripheral state
120#[derive(PartialEq, Clone, Copy)]
121pub enum State {
122 /// Peripheral is being setup or reconfigured
123 Reset,
124 /// Ready to start acquisition
125 Ready,
126 /// In process of sensor acquisition
127 Busy,
128 /// Error occured during acquisition
129 Error,
130}
131
132/// Individual group status checked after acquisition reported as complete
133/// For groups with multiple channel pins, may take longer because acquisitions
134/// are done sequentially. Check this status before pulling count for each
135/// sampled channel
136#[derive(PartialEq)]
137pub enum GroupStatus {
138 /// Acquisition for channel still in progress
139 Ongoing,
140 /// Acquisition either not started or complete
141 Complete,
142}
143
144/// Group identifier used to interrogate status
145#[allow(missing_docs)]
146pub enum Group {
147 One,
148 Two,
149 Three,
150 Four,
151 Five,
152 Six,
153 #[cfg(any(tsc_v2, tsc_v3))]
154 Seven,
155 #[cfg(tsc_v3)]
156 Eight,
157}
158
159impl Into<usize> for Group {
160 fn into(self) -> usize {
161 match self {
162 Group::One => 0,
163 Group::Two => 1,
164 Group::Three => 2,
165 Group::Four => 3,
166 Group::Five => 4,
167 Group::Six => 5,
168 #[cfg(any(tsc_v2, tsc_v3))]
169 Group::Seven => 6,
170 #[cfg(tsc_v3)]
171 Group::Eight => 7,
172 }
173 }
174}
175
176/// Peripheral configuration
177#[derive(Clone, Copy)]
178pub struct Config {
179 /// Duration of high state of the charge transfer pulse
180 pub ct_pulse_high_length: ChargeTransferPulseCycle,
181 /// Duration of the low state of the charge transfer pulse
182 pub ct_pulse_low_length: ChargeTransferPulseCycle,
183 /// Enable/disable of spread spectrum feature
184 pub spread_spectrum: bool,
185 /// Adds variable number of periods of the SS clk to pulse high state
186 pub spread_spectrum_deviation: SSDeviation,
187 /// Selects AHB clock divider used to generate SS clk
188 pub spread_spectrum_prescaler: bool,
189 /// Selects AHB clock divider used to generate pulse generator clk
190 pub pulse_generator_prescaler: PGPrescalerDivider,
191 /// Maximum number of charge transfer pulses that can be generated before error
192 pub max_count_value: MaxCount,
193 /// Defines config of all IOs when no ongoing acquisition
194 pub io_default_mode: bool,
195 /// Polarity of sync input pin
196 pub synchro_pin_polarity: bool,
197 /// Acquisition starts when start bit is set or with sync pin input
198 pub acquisition_mode: bool,
199 /// Enable max count interrupt
200 pub max_count_interrupt: bool,
201 /// Channel IO mask
202 pub channel_ios: u32,
203 /// Shield IO mask
204 pub shield_ios: u32,
205 /// Sampling IO mask
206 pub sampling_ios: u32,
207}
208
209impl Default for Config {
210 fn default() -> Self {
211 Self {
212 ct_pulse_high_length: ChargeTransferPulseCycle::_1,
213 ct_pulse_low_length: ChargeTransferPulseCycle::_1,
214 spread_spectrum: false,
215 spread_spectrum_deviation: SSDeviation::new(1).unwrap(),
216 spread_spectrum_prescaler: false,
217 pulse_generator_prescaler: PGPrescalerDivider::_1,
218 max_count_value: MaxCount::_255,
219 io_default_mode: false,
220 synchro_pin_polarity: false,
221 acquisition_mode: false,
222 max_count_interrupt: false,
223 channel_ios: 0,
224 shield_ios: 0,
225 sampling_ios: 0,
226 }
227 }
228}
229
230/// Pin struct that maintains usage
231#[allow(missing_docs)]
232pub struct TscPin<'d, T, C> {
233 _pin: PeripheralRef<'d, AnyPin>,
234 role: PinType,
235 phantom: PhantomData<(T, C)>,
236}
237
238enum GroupError {
239 NoSample,
240 ChannelShield,
241}
242
243/// Pin group definition
244/// Pins are organized into groups of four IOs, all groups with a
245/// sampling channel must also have a sampling capacitor channel.
246#[allow(missing_docs)]
247#[derive(Default)]
248pub struct PinGroup<'d, T, C> {
249 d1: Option<TscPin<'d, T, C>>,
250 d2: Option<TscPin<'d, T, C>>,
251 d3: Option<TscPin<'d, T, C>>,
252 d4: Option<TscPin<'d, T, C>>,
253}
254
255impl<'d, T: Instance, C> PinGroup<'d, T, C> {
256 /// Create new sensing group
257 pub fn new() -> Self {
258 Self {
259 d1: None,
260 d2: None,
261 d3: None,
262 d4: None,
263 }
264 }
265
266 fn contains_shield(&self) -> bool {
267 let mut shield_count = 0;
268
269 if let Some(pin) = &self.d1 {
270 if let PinType::Shield = pin.role {
271 shield_count += 1;
272 }
273 }
274
275 if let Some(pin) = &self.d2 {
276 if let PinType::Shield = pin.role {
277 shield_count += 1;
278 }
279 }
280
281 if let Some(pin) = &self.d3 {
282 if let PinType::Shield = pin.role {
283 shield_count += 1;
284 }
285 }
286
287 if let Some(pin) = &self.d4 {
288 if let PinType::Shield = pin.role {
289 shield_count += 1;
290 }
291 }
292
293 shield_count == 1
294 }
295
296 fn check_group(&self) -> Result<(), GroupError> {
297 let mut channel_count = 0;
298 let mut shield_count = 0;
299 let mut sample_count = 0;
300 if let Some(pin) = &self.d1 {
301 match pin.role {
302 PinType::Channel => {
303 channel_count += 1;
304 }
305 PinType::Shield => {
306 shield_count += 1;
307 }
308 PinType::Sample => {
309 sample_count += 1;
310 }
311 }
312 }
313
314 if let Some(pin) = &self.d2 {
315 match pin.role {
316 PinType::Channel => {
317 channel_count += 1;
318 }
319 PinType::Shield => {
320 shield_count += 1;
321 }
322 PinType::Sample => {
323 sample_count += 1;
324 }
325 }
326 }
327
328 if let Some(pin) = &self.d3 {
329 match pin.role {
330 PinType::Channel => {
331 channel_count += 1;
332 }
333 PinType::Shield => {
334 shield_count += 1;
335 }
336 PinType::Sample => {
337 sample_count += 1;
338 }
339 }
340 }
341
342 if let Some(pin) = &self.d4 {
343 match pin.role {
344 PinType::Channel => {
345 channel_count += 1;
346 }
347 PinType::Shield => {
348 shield_count += 1;
349 }
350 PinType::Sample => {
351 sample_count += 1;
352 }
353 }
354 }
355
356 // Every group requires one sampling capacitor
357 if sample_count != 1 {
358 return Err(GroupError::NoSample);
359 }
360
361 // Each group must have at least one shield or channel IO
362 if shield_count == 0 && channel_count == 0 {
363 return Err(GroupError::ChannelShield);
364 }
365
366 // Any group can either contain channel ios or a shield IO
367 if shield_count != 0 && channel_count != 0 {
368 return Err(GroupError::ChannelShield);
369 }
370
371 // No more than one shield IO is allow per group and amongst all groups
372 if shield_count > 1 {
373 return Err(GroupError::ChannelShield);
374 }
375
376 Ok(())
377 }
378}
379
380macro_rules! group_impl {
381 ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
382 impl<'d, T: Instance> PinGroup<'d, T, $group> {
383 #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")]
384 pub fn set_io1(&mut self, pin: impl Peripheral<P = impl $trait1<T>> + 'd, role: PinType) {
385 into_ref!(pin);
386 critical_section::with(|_| {
387 pin.set_low();
388 pin.set_as_af(
389 pin.af_num(),
390 AfType::output(
391 match role {
392 PinType::Channel => OutputType::PushPull,
393 PinType::Sample => OutputType::OpenDrain,
394 PinType::Shield => OutputType::PushPull,
395 },
396 Speed::VeryHigh,
397 ),
398 );
399 self.d1 = Some(TscPin {
400 _pin: pin.map_into(),
401 role: role,
402 phantom: PhantomData,
403 })
404 })
405 }
406
407 #[doc = concat!("Create a new pin2 for ", stringify!($group), " TSC group instance.")]
408 pub fn set_io2(&mut self, pin: impl Peripheral<P = impl $trait2<T>> + 'd, role: PinType) {
409 into_ref!(pin);
410 critical_section::with(|_| {
411 pin.set_low();
412 pin.set_as_af(
413 pin.af_num(),
414 AfType::output(
415 match role {
416 PinType::Channel => OutputType::PushPull,
417 PinType::Sample => OutputType::OpenDrain,
418 PinType::Shield => OutputType::PushPull,
419 },
420 Speed::VeryHigh,
421 ),
422 );
423 self.d2 = Some(TscPin {
424 _pin: pin.map_into(),
425 role: role,
426 phantom: PhantomData,
427 })
428 })
429 }
430
431 #[doc = concat!("Create a new pin3 for ", stringify!($group), " TSC group instance.")]
432 pub fn set_io3(&mut self, pin: impl Peripheral<P = impl $trait3<T>> + 'd, role: PinType) {
433 into_ref!(pin);
434 critical_section::with(|_| {
435 pin.set_low();
436 pin.set_as_af(
437 pin.af_num(),
438 AfType::output(
439 match role {
440 PinType::Channel => OutputType::PushPull,
441 PinType::Sample => OutputType::OpenDrain,
442 PinType::Shield => OutputType::PushPull,
443 },
444 Speed::VeryHigh,
445 ),
446 );
447 self.d3 = Some(TscPin {
448 _pin: pin.map_into(),
449 role: role,
450 phantom: PhantomData,
451 })
452 })
453 }
454
455 #[doc = concat!("Create a new pin4 for ", stringify!($group), " TSC group instance.")]
456 pub fn set_io4(&mut self, pin: impl Peripheral<P = impl $trait4<T>> + 'd, role: PinType) {
457 into_ref!(pin);
458 critical_section::with(|_| {
459 pin.set_low();
460 pin.set_as_af(
461 pin.af_num(),
462 AfType::output(
463 match role {
464 PinType::Channel => OutputType::PushPull,
465 PinType::Sample => OutputType::OpenDrain,
466 PinType::Shield => OutputType::PushPull,
467 },
468 Speed::VeryHigh,
469 ),
470 );
471 self.d4 = Some(TscPin {
472 _pin: pin.map_into(),
473 role: role,
474 phantom: PhantomData,
475 })
476 })
477 }
478 }
479 };
480}
481
482group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin);
483group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin);
484group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin);
485group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin);
486group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin);
487group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin);
488group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin);
489group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin);
490
491/// Group 1 marker type.
492pub enum G1 {}
493/// Group 2 marker type.
494pub enum G2 {}
495/// Group 3 marker type.
496pub enum G3 {}
497/// Group 4 marker type.
498pub enum G4 {}
499/// Group 5 marker type.
500pub enum G5 {}
501/// Group 6 marker type.
502pub enum G6 {}
503/// Group 7 marker type.
504pub enum G7 {}
505/// Group 8 marker type.
506pub enum G8 {}
507
508/// TSC driver
509pub struct Tsc<'d, T: Instance, K: PeriMode> {
510 _peri: PeripheralRef<'d, T>,
511 _g1: Option<PinGroup<'d, T, G1>>,
512 _g2: Option<PinGroup<'d, T, G2>>,
513 _g3: Option<PinGroup<'d, T, G3>>,
514 _g4: Option<PinGroup<'d, T, G4>>,
515 _g5: Option<PinGroup<'d, T, G5>>,
516 _g6: Option<PinGroup<'d, T, G6>>,
517 #[cfg(any(tsc_v2, tsc_v3))]
518 _g7: Option<PinGroup<'d, T, G7>>,
519 #[cfg(tsc_v3)]
520 _g8: Option<PinGroup<'d, T, G8>>,
521 state: State,
522 config: Config,
523 _kind: PhantomData<K>,
524}
525
526impl<'d, T: Instance> Tsc<'d, T, Async> {
527 /// Create a Tsc instance that can be awaited for completion
528 pub fn new_async(
529 peri: impl Peripheral<P = T> + 'd,
530 g1: Option<PinGroup<'d, T, G1>>,
531 g2: Option<PinGroup<'d, T, G2>>,
532 g3: Option<PinGroup<'d, T, G3>>,
533 g4: Option<PinGroup<'d, T, G4>>,
534 g5: Option<PinGroup<'d, T, G5>>,
535 g6: Option<PinGroup<'d, T, G6>>,
536 #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
537 #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
538 config: Config,
539 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
540 ) -> Self {
541 // Need to check valid pin configuration input
542 let g1 = g1.filter(|b| b.check_group().is_ok());
543 let g2 = g2.filter(|b| b.check_group().is_ok());
544 let g3 = g3.filter(|b| b.check_group().is_ok());
545 let g4 = g4.filter(|b| b.check_group().is_ok());
546 let g5 = g5.filter(|b| b.check_group().is_ok());
547 let g6 = g6.filter(|b| b.check_group().is_ok());
548 #[cfg(any(tsc_v2, tsc_v3))]
549 let g7 = g7.filter(|b| b.check_group().is_ok());
550 #[cfg(tsc_v3)]
551 let g8 = g8.filter(|b| b.check_group().is_ok());
552
553 match Self::check_shields(
554 &g1,
555 &g2,
556 &g3,
557 &g4,
558 &g5,
559 &g6,
560 #[cfg(any(tsc_v2, tsc_v3))]
561 &g7,
562 #[cfg(tsc_v3)]
563 &g8,
564 ) {
565 Ok(()) => Self::new_inner(
566 peri,
567 g1,
568 g2,
569 g3,
570 g4,
571 g5,
572 g6,
573 #[cfg(any(tsc_v2, tsc_v3))]
574 g7,
575 #[cfg(tsc_v3)]
576 g8,
577 config,
578 ),
579 Err(_) => Self::new_inner(
580 peri,
581 None,
582 None,
583 None,
584 None,
585 None,
586 None,
587 #[cfg(any(tsc_v2, tsc_v3))]
588 None,
589 #[cfg(tsc_v3)]
590 None,
591 config,
592 ),
593 }
594 }
595 /// Asyncronously wait for the end of an acquisition
596 pub async fn pend_for_acquisition(&mut self) {
597 poll_fn(|cx| match self.get_state() {
598 State::Busy => {
599 T::waker().register(cx.waker());
600 T::regs().ier().write(|w| w.set_eoaie(true));
601 if self.get_state() != State::Busy {
602 T::regs().ier().write(|w| w.set_eoaie(false));
603 return Poll::Ready(());
604 }
605 Poll::Pending
606 }
607 _ => {
608 T::regs().ier().write(|w| w.set_eoaie(false));
609 Poll::Ready(())
610 }
611 })
612 .await;
613 }
614}
615
616impl<'d, T: Instance> Tsc<'d, T, Blocking> {
617 /// Create a Tsc instance that must be polled for completion
618 pub fn new_blocking(
619 peri: impl Peripheral<P = T> + 'd,
620 g1: Option<PinGroup<'d, T, G1>>,
621 g2: Option<PinGroup<'d, T, G2>>,
622 g3: Option<PinGroup<'d, T, G3>>,
623 g4: Option<PinGroup<'d, T, G4>>,
624 g5: Option<PinGroup<'d, T, G5>>,
625 g6: Option<PinGroup<'d, T, G6>>,
626 #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
627 #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
628 config: Config,
629 ) -> Self {
630 // Need to check valid pin configuration input
631 let g1 = g1.filter(|b| b.check_group().is_ok());
632 let g2 = g2.filter(|b| b.check_group().is_ok());
633 let g3 = g3.filter(|b| b.check_group().is_ok());
634 let g4 = g4.filter(|b| b.check_group().is_ok());
635 let g5 = g5.filter(|b| b.check_group().is_ok());
636 let g6 = g6.filter(|b| b.check_group().is_ok());
637 #[cfg(any(tsc_v2, tsc_v3))]
638 let g7 = g7.filter(|b| b.check_group().is_ok());
639 #[cfg(tsc_v3)]
640 let g8 = g8.filter(|b| b.check_group().is_ok());
641
642 match Self::check_shields(
643 &g1,
644 &g2,
645 &g3,
646 &g4,
647 &g5,
648 &g6,
649 #[cfg(any(tsc_v2, tsc_v3))]
650 &g7,
651 #[cfg(tsc_v3)]
652 &g8,
653 ) {
654 Ok(()) => Self::new_inner(
655 peri,
656 g1,
657 g2,
658 g3,
659 g4,
660 g5,
661 g6,
662 #[cfg(any(tsc_v2, tsc_v3))]
663 g7,
664 #[cfg(tsc_v3)]
665 g8,
666 config,
667 ),
668 Err(_) => Self::new_inner(
669 peri,
670 None,
671 None,
672 None,
673 None,
674 None,
675 None,
676 #[cfg(any(tsc_v2, tsc_v3))]
677 None,
678 #[cfg(tsc_v3)]
679 None,
680 config,
681 ),
682 }
683 }
684 /// Wait for end of acquisition
685 pub fn poll_for_acquisition(&mut self) {
686 while self.get_state() == State::Busy {}
687 }
688}
689
690impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> {
691 /// Create new TSC driver
692 fn check_shields(
693 g1: &Option<PinGroup<'d, T, G1>>,
694 g2: &Option<PinGroup<'d, T, G2>>,
695 g3: &Option<PinGroup<'d, T, G3>>,
696 g4: &Option<PinGroup<'d, T, G4>>,
697 g5: &Option<PinGroup<'d, T, G5>>,
698 g6: &Option<PinGroup<'d, T, G6>>,
699 #[cfg(any(tsc_v2, tsc_v3))] g7: &Option<PinGroup<'d, T, G7>>,
700 #[cfg(tsc_v3)] g8: &Option<PinGroup<'d, T, G8>>,
701 ) -> Result<(), GroupError> {
702 let mut shield_count = 0;
703
704 if let Some(pin_group) = g1 {
705 if pin_group.contains_shield() {
706 shield_count += 1;
707 }
708 };
709 if let Some(pin_group) = g2 {
710 if pin_group.contains_shield() {
711 shield_count += 1;
712 }
713 };
714 if let Some(pin_group) = g3 {
715 if pin_group.contains_shield() {
716 shield_count += 1;
717 }
718 };
719 if let Some(pin_group) = g4 {
720 if pin_group.contains_shield() {
721 shield_count += 1;
722 }
723 };
724 if let Some(pin_group) = g5 {
725 if pin_group.contains_shield() {
726 shield_count += 1;
727 }
728 };
729 if let Some(pin_group) = g6 {
730 if pin_group.contains_shield() {
731 shield_count += 1;
732 }
733 };
734 #[cfg(any(tsc_v2, tsc_v3))]
735 if let Some(pin_group) = g7 {
736 if pin_group.contains_shield() {
737 shield_count += 1;
738 }
739 };
740 #[cfg(tsc_v3)]
741 if let Some(pin_group) = g8 {
742 if pin_group.contains_shield() {
743 shield_count += 1;
744 }
745 };
746
747 if shield_count > 1 {
748 return Err(GroupError::ChannelShield);
749 }
750
751 Ok(())
752 }
753
754 fn extract_groups(io_mask: u32) -> u32 {
755 let mut groups: u32 = 0;
756 for idx in 0..TSC_NUM_GROUPS {
757 if io_mask & (0x0F << idx * 4) != 0 {
758 groups |= 1 << idx
759 }
760 }
761 groups
762 }
763
764 fn new_inner(
765 peri: impl Peripheral<P = T> + 'd,
766 g1: Option<PinGroup<'d, T, G1>>,
767 g2: Option<PinGroup<'d, T, G2>>,
768 g3: Option<PinGroup<'d, T, G3>>,
769 g4: Option<PinGroup<'d, T, G4>>,
770 g5: Option<PinGroup<'d, T, G5>>,
771 g6: Option<PinGroup<'d, T, G6>>,
772 #[cfg(any(tsc_v2, tsc_v3))] g7: Option<PinGroup<'d, T, G7>>,
773 #[cfg(tsc_v3)] g8: Option<PinGroup<'d, T, G8>>,
774 config: Config,
775 ) -> Self {
776 into_ref!(peri);
777
778 rcc::enable_and_reset::<T>();
779
780 T::regs().cr().modify(|w| {
781 w.set_tsce(true);
782 w.set_ctph(config.ct_pulse_high_length.into());
783 w.set_ctpl(config.ct_pulse_low_length.into());
784 w.set_sse(config.spread_spectrum);
785 // Prevent invalid configuration for pulse generator prescaler
786 if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1
787 && (config.pulse_generator_prescaler == PGPrescalerDivider::_1
788 || config.pulse_generator_prescaler == PGPrescalerDivider::_2)
789 {
790 w.set_pgpsc(PGPrescalerDivider::_4.into());
791 } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2
792 && config.pulse_generator_prescaler == PGPrescalerDivider::_1
793 {
794 w.set_pgpsc(PGPrescalerDivider::_2.into());
795 } else {
796 w.set_pgpsc(config.pulse_generator_prescaler.into());
797 }
798 w.set_ssd(config.spread_spectrum_deviation.into());
799 w.set_sspsc(config.spread_spectrum_prescaler);
800
801 w.set_mcv(config.max_count_value.into());
802 w.set_syncpol(config.synchro_pin_polarity);
803 w.set_am(config.acquisition_mode);
804 });
805
806 // Set IO configuration
807 // Disable Schmitt trigger hysteresis on all used TSC IOs
808 T::regs()
809 .iohcr()
810 .write(|w| w.0 = !(config.channel_ios | config.shield_ios | config.sampling_ios));
811
812 // Set channel and shield IOs
813 T::regs()
814 .ioccr()
815 .write(|w| w.0 = config.channel_ios | config.shield_ios);
816
817 // Set sampling IOs
818 T::regs().ioscr().write(|w| w.0 = config.sampling_ios);
819
820 // Set the groups to be acquired
821 T::regs()
822 .iogcsr()
823 .write(|w| w.0 = Self::extract_groups(config.channel_ios));
824
825 // Disable interrupts
826 T::regs().ier().modify(|w| {
827 w.set_eoaie(false);
828 w.set_mceie(false);
829 });
830
831 // Clear flags
832 T::regs().icr().modify(|w| {
833 w.set_eoaic(true);
834 w.set_mceic(true);
835 });
836
837 unsafe {
838 T::Interrupt::enable();
839 }
840
841 Self {
842 _peri: peri,
843 _g1: g1,
844 _g2: g2,
845 _g3: g3,
846 _g4: g4,
847 _g5: g5,
848 _g6: g6,
849 #[cfg(any(tsc_v2, tsc_v3))]
850 _g7: g7,
851 #[cfg(tsc_v3)]
852 _g8: g8,
853 state: State::Ready,
854 config,
855 _kind: PhantomData,
856 }
857 }
858
859 /// Start charge transfer acquisition
860 pub fn start(&mut self) {
861 self.state = State::Busy;
862
863 // Disable interrupts
864 T::regs().ier().modify(|w| {
865 w.set_eoaie(false);
866 w.set_mceie(false);
867 });
868
869 // Clear flags
870 T::regs().icr().modify(|w| {
871 w.set_eoaic(true);
872 w.set_mceic(true);
873 });
874
875 // Set the touch sensing IOs not acquired to the default mode
876 T::regs().cr().modify(|w| {
877 w.set_iodef(self.config.io_default_mode);
878 });
879
880 // Start the acquisition
881 T::regs().cr().modify(|w| {
882 w.set_start(true);
883 });
884 }
885
886 /// Stop charge transfer acquisition
887 pub fn stop(&mut self) {
888 T::regs().cr().modify(|w| {
889 w.set_start(false);
890 });
891
892 // Set the touch sensing IOs in low power mode
893 T::regs().cr().modify(|w| {
894 w.set_iodef(false);
895 });
896
897 // Clear flags
898 T::regs().icr().modify(|w| {
899 w.set_eoaic(true);
900 w.set_mceic(true);
901 });
902
903 self.state = State::Ready;
904 }
905
906 /// Get current state of acquisition
907 pub fn get_state(&mut self) -> State {
908 if self.state == State::Busy {
909 if T::regs().isr().read().eoaf() {
910 if T::regs().isr().read().mcef() {
911 self.state = State::Error
912 } else {
913 self.state = State::Ready
914 }
915 }
916 }
917 self.state
918 }
919
920 /// Get the individual group status to check acquisition complete
921 pub fn group_get_status(&mut self, index: Group) -> GroupStatus {
922 // Status bits are set by hardware when the acquisition on the corresponding
923 // enabled analog IO group is complete, cleared when new acquisition is started
924 let status = match index {
925 Group::One => T::regs().iogcsr().read().g1s(),
926 Group::Two => T::regs().iogcsr().read().g2s(),
927 Group::Three => T::regs().iogcsr().read().g3s(),
928 Group::Four => T::regs().iogcsr().read().g4s(),
929 Group::Five => T::regs().iogcsr().read().g5s(),
930 Group::Six => T::regs().iogcsr().read().g6s(),
931 #[cfg(any(tsc_v2, tsc_v3))]
932 Group::Seven => T::regs().iogcsr().read().g7s(),
933 #[cfg(tsc_v3)]
934 Group::Eight => T::regs().iogcsr().read().g8s(),
935 };
936 match status {
937 true => GroupStatus::Complete,
938 false => GroupStatus::Ongoing,
939 }
940 }
941
942 /// Get the count for the acquisiton, valid once group status is set
943 pub fn group_get_value(&mut self, index: Group) -> u16 {
944 T::regs().iogcr(index.into()).read().cnt()
945 }
946
947 /// Discharge the IOs for subsequent acquisition
948 pub fn discharge_io(&mut self, status: bool) {
949 // Set the touch sensing IOs in low power mode
950 T::regs().cr().modify(|w| {
951 w.set_iodef(!status);
952 });
953 }
954}
955
956impl<'d, T: Instance, K: PeriMode> Drop for Tsc<'d, T, K> {
957 fn drop(&mut self) {
958 rcc::disable::<T>();
959 }
960}
961
962pub(crate) trait SealedInstance { 139pub(crate) trait SealedInstance {
963 fn regs() -> crate::pac::tsc::Tsc; 140 fn regs() -> crate::pac::tsc::Tsc;
964 fn waker() -> &'static AtomicWaker; 141 fn waker() -> &'static AtomicWaker;
@@ -966,7 +143,7 @@ pub(crate) trait SealedInstance {
966 143
967/// TSC instance trait 144/// TSC instance trait
968#[allow(private_bounds)] 145#[allow(private_bounds)]
969pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral { 146pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {
970 /// Interrupt for this TSC instance 147 /// Interrupt for this TSC instance
971 type Interrupt: interrupt::typelevel::Interrupt; 148 type Interrupt: interrupt::typelevel::Interrupt;
972} 149}
@@ -988,36 +165,3 @@ foreach_interrupt!(
988 } 165 }
989 }; 166 };
990); 167);
991
992pin_trait!(G1IO1Pin, Instance);
993pin_trait!(G1IO2Pin, Instance);
994pin_trait!(G1IO3Pin, Instance);
995pin_trait!(G1IO4Pin, Instance);
996pin_trait!(G2IO1Pin, Instance);
997pin_trait!(G2IO2Pin, Instance);
998pin_trait!(G2IO3Pin, Instance);
999pin_trait!(G2IO4Pin, Instance);
1000pin_trait!(G3IO1Pin, Instance);
1001pin_trait!(G3IO2Pin, Instance);
1002pin_trait!(G3IO3Pin, Instance);
1003pin_trait!(G3IO4Pin, Instance);
1004pin_trait!(G4IO1Pin, Instance);
1005pin_trait!(G4IO2Pin, Instance);
1006pin_trait!(G4IO3Pin, Instance);
1007pin_trait!(G4IO4Pin, Instance);
1008pin_trait!(G5IO1Pin, Instance);
1009pin_trait!(G5IO2Pin, Instance);
1010pin_trait!(G5IO3Pin, Instance);
1011pin_trait!(G5IO4Pin, Instance);
1012pin_trait!(G6IO1Pin, Instance);
1013pin_trait!(G6IO2Pin, Instance);
1014pin_trait!(G6IO3Pin, Instance);
1015pin_trait!(G6IO4Pin, Instance);
1016pin_trait!(G7IO1Pin, Instance);
1017pin_trait!(G7IO2Pin, Instance);
1018pin_trait!(G7IO3Pin, Instance);
1019pin_trait!(G7IO4Pin, Instance);
1020pin_trait!(G8IO1Pin, Instance);
1021pin_trait!(G8IO2Pin, Instance);
1022pin_trait!(G8IO3Pin, Instance);
1023pin_trait!(G8IO4Pin, Instance);
diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs
new file mode 100644
index 000000000..6f914a94e
--- /dev/null
+++ b/embassy-stm32/src/tsc/pin_groups.rs
@@ -0,0 +1,663 @@
1use core::marker::PhantomData;
2use core::ops::BitOr;
3
4use super::errors::GroupError;
5use super::io_pin::*;
6use super::Instance;
7use crate::gpio::{AfType, AnyPin, OutputType, Speed};
8use crate::Peri;
9
10/// Pin type definition to control IO parameters
11#[derive(PartialEq, Clone, Copy)]
12pub enum PinType {
13 /// Sensing channel pin connected to an electrode
14 Channel,
15 /// Sampling capacitor pin, one required for every pin group
16 Sample,
17 /// Shield pin connected to capacitive sensing shield
18 Shield,
19}
20
21/// Pin struct that maintains usage
22#[allow(missing_docs)]
23pub struct Pin<'d, T, Group> {
24 _pin: Peri<'d, AnyPin>,
25 role: PinType,
26 tsc_io_pin: IOPin,
27 phantom: PhantomData<(T, Group)>,
28}
29
30impl<'d, T, Group> Pin<'d, T, Group> {
31 /// Returns the role of this TSC pin.
32 ///
33 /// The role indicates whether this pin is configured as a channel,
34 /// sampling capacitor, or shield in the TSC group.
35 ///
36 /// # Returns
37 /// The `PinType` representing the role of this pin.
38 pub fn role(&self) -> PinType {
39 self.role
40 }
41
42 /// Returns the TSC IO pin associated with this pin.
43 ///
44 /// This method provides access to the specific TSC IO pin configuration,
45 /// which includes information about the pin's group and position within that group.
46 ///
47 /// # Returns
48 /// The `IOPin` representing this pin's TSC-specific configuration.
49 pub fn tsc_io_pin(&self) -> IOPin {
50 self.tsc_io_pin
51 }
52}
53
54/// Represents a group of TSC (Touch Sensing Controller) pins.
55///
56/// In the TSC peripheral, pins are organized into groups of four IOs. Each group
57/// must have exactly one sampling capacitor pin and can have multiple channel pins
58/// or a single shield pin. This structure encapsulates these pin configurations
59/// for a single TSC group.
60///
61/// # Pin Roles
62/// - Sampling Capacitor: One required per group, used for charge transfer.
63/// - Channel: Sensing pins connected to electrodes for touch detection.
64/// - Shield: Optional, used for active shielding to improve sensitivity.
65///
66/// # Constraints
67/// - Each group must have exactly one sampling capacitor pin.
68/// - A group can have either channel pins or a shield pin, but not both.
69/// - No more than one shield pin is allowed across all groups.
70#[allow(missing_docs)]
71pub struct PinGroup<'d, T, Group> {
72 pin1: Option<Pin<'d, T, Group>>,
73 pin2: Option<Pin<'d, T, Group>>,
74 pin3: Option<Pin<'d, T, Group>>,
75 pin4: Option<Pin<'d, T, Group>>,
76}
77
78impl<'d, T, G> Default for PinGroup<'d, T, G> {
79 fn default() -> Self {
80 Self {
81 pin1: None,
82 pin2: None,
83 pin3: None,
84 pin4: None,
85 }
86 }
87}
88
89/// Defines roles and traits for TSC (Touch Sensing Controller) pins.
90///
91/// This module contains marker types and traits that represent different roles
92/// a TSC pin can have, such as channel, sample, or shield.
93pub mod pin_roles {
94 use super::{OutputType, PinType};
95
96 /// Marker type for a TSC channel pin.
97 #[derive(PartialEq, Clone, Copy, Debug)]
98 pub struct Channel;
99
100 /// Marker type for a TSC sampling pin.
101 #[derive(PartialEq, Clone, Copy, Debug)]
102 pub struct Sample;
103
104 /// Marker type for a TSC shield pin.
105 #[derive(PartialEq, Clone, Copy, Debug)]
106 pub struct Shield;
107
108 /// Trait for TSC pin roles.
109 ///
110 /// This trait defines the behavior and properties of different TSC pin roles.
111 /// It is implemented by the marker types `Channel`, `Sample`, and `Shield`.
112 pub trait Role {
113 /// Returns the `PinType` associated with this role.
114 fn pin_type() -> PinType;
115
116 /// Returns the `OutputType` associated with this role.
117 fn output_type() -> OutputType;
118 }
119
120 impl Role for Channel {
121 fn pin_type() -> PinType {
122 PinType::Channel
123 }
124 fn output_type() -> OutputType {
125 OutputType::PushPull
126 }
127 }
128
129 impl Role for Sample {
130 fn pin_type() -> PinType {
131 PinType::Sample
132 }
133 fn output_type() -> OutputType {
134 OutputType::OpenDrain
135 }
136 }
137
138 impl Role for Shield {
139 fn pin_type() -> PinType {
140 PinType::Shield
141 }
142 fn output_type() -> OutputType {
143 OutputType::PushPull
144 }
145 }
146}
147
148/// Represents a group of TSC pins with their associated roles.
149///
150/// This struct allows for type-safe configuration of TSC pin groups,
151/// ensuring that pins are assigned appropriate roles within their group.
152/// This type is essentially just a wrapper type around a `PinGroup` value.
153///
154/// # Type Parameters
155/// - `'d`: Lifetime of the pin group.
156/// - `T`: The TSC instance type.
157/// - `G`: The group identifier.
158/// - `R1`, `R2`, `R3`, `R4`: Role types for each pin in the group, defaulting to `Channel`.
159pub struct PinGroupWithRoles<
160 'd,
161 T: Instance,
162 G,
163 R1 = pin_roles::Channel,
164 R2 = pin_roles::Channel,
165 R3 = pin_roles::Channel,
166 R4 = pin_roles::Channel,
167> {
168 /// The underlying pin group without role information.
169 pub pin_group: PinGroup<'d, T, G>,
170 _phantom: PhantomData<(R1, R2, R3, R4)>,
171}
172
173impl<'d, T: Instance, G, R1, R2, R3, R4> Default for PinGroupWithRoles<'d, T, G, R1, R2, R3, R4> {
174 fn default() -> Self {
175 Self {
176 pin_group: PinGroup::default(),
177 _phantom: PhantomData,
178 }
179 }
180}
181
182impl<'d, T: Instance, G> PinGroup<'d, T, G> {
183 fn contains_exactly_one_shield_pin(&self) -> bool {
184 let shield_count = self.shield_pins().count();
185 shield_count == 1
186 }
187
188 fn check_group(&self) -> Result<(), GroupError> {
189 let mut channel_count = 0;
190 let mut shield_count = 0;
191 let mut sample_count = 0;
192 for pin in self.pins().into_iter().flatten() {
193 match pin.role {
194 PinType::Channel => {
195 channel_count += 1;
196 }
197 PinType::Shield => {
198 shield_count += 1;
199 }
200 PinType::Sample => {
201 sample_count += 1;
202 }
203 }
204 }
205
206 // Every group requires exactly one sampling capacitor
207 if sample_count != 1 {
208 return Err(GroupError::NoSamplingCapacitor);
209 }
210
211 // Each group must have at least one shield or channel IO
212 if shield_count == 0 && channel_count == 0 {
213 return Err(GroupError::NoChannelOrShield);
214 }
215
216 // Any group can either contain channel ios or a shield IO.
217 // (An active shield requires its own sampling capacitor)
218 if shield_count != 0 && channel_count != 0 {
219 return Err(GroupError::MixedChannelAndShield);
220 }
221
222 // No more than one shield IO is allow per group and amongst all groups
223 if shield_count > 1 {
224 return Err(GroupError::MultipleShields);
225 }
226
227 Ok(())
228 }
229
230 /// Returns a reference to the first pin in the group, if configured.
231 pub fn pin1(&self) -> Option<&Pin<'d, T, G>> {
232 self.pin1.as_ref()
233 }
234
235 /// Returns a reference to the second pin in the group, if configured.
236 pub fn pin2(&self) -> Option<&Pin<'d, T, G>> {
237 self.pin2.as_ref()
238 }
239
240 /// Returns a reference to the third pin in the group, if configured.
241 pub fn pin3(&self) -> Option<&Pin<'d, T, G>> {
242 self.pin3.as_ref()
243 }
244
245 /// Returns a reference to the fourth pin in the group, if configured.
246 pub fn pin4(&self) -> Option<&Pin<'d, T, G>> {
247 self.pin4.as_ref()
248 }
249
250 fn sample_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
251 self.pins_filtered(PinType::Sample)
252 }
253
254 fn shield_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
255 self.pins_filtered(PinType::Shield)
256 }
257
258 fn channel_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
259 self.pins_filtered(PinType::Channel)
260 }
261
262 fn pins_filtered(&self, pin_type: PinType) -> impl Iterator<Item = IOPin> + '_ {
263 self.pins().into_iter().filter_map(move |pin| {
264 pin.as_ref()
265 .and_then(|p| if p.role == pin_type { Some(p.tsc_io_pin) } else { None })
266 })
267 }
268
269 fn make_channel_ios_mask(&self) -> u32 {
270 self.channel_pins().fold(0, u32::bitor)
271 }
272
273 fn make_shield_ios_mask(&self) -> u32 {
274 self.shield_pins().fold(0, u32::bitor)
275 }
276
277 fn make_sample_ios_mask(&self) -> u32 {
278 self.sample_pins().fold(0, u32::bitor)
279 }
280
281 fn pins(&self) -> [&Option<Pin<'d, T, G>>; 4] {
282 [&self.pin1, &self.pin2, &self.pin3, &self.pin4]
283 }
284
285 fn pins_mut(&mut self) -> [&mut Option<Pin<'d, T, G>>; 4] {
286 [&mut self.pin1, &mut self.pin2, &mut self.pin3, &mut self.pin4]
287 }
288}
289
290#[cfg(any(tsc_v2, tsc_v3))]
291macro_rules! TSC_V2_V3_GUARD {
292 ($e:expr) => {{
293 #[cfg(any(tsc_v2, tsc_v3))]
294 {
295 $e
296 }
297 #[cfg(not(any(tsc_v2, tsc_v3)))]
298 {
299 compile_error!("Group 7 is not supported in this TSC version")
300 }
301 }};
302}
303
304#[cfg(tsc_v3)]
305macro_rules! TSC_V3_GUARD {
306 ($e:expr) => {{
307 #[cfg(tsc_v3)]
308 {
309 $e
310 }
311 #[cfg(not(tsc_v3))]
312 {
313 compile_error!("Group 8 is not supported in this TSC version")
314 }
315 }};
316}
317
318macro_rules! trait_to_io_pin {
319 (G1IO1Pin) => {
320 IOPin::Group1Io1
321 };
322 (G1IO2Pin) => {
323 IOPin::Group1Io2
324 };
325 (G1IO3Pin) => {
326 IOPin::Group1Io3
327 };
328 (G1IO4Pin) => {
329 IOPin::Group1Io4
330 };
331
332 (G2IO1Pin) => {
333 IOPin::Group2Io1
334 };
335 (G2IO2Pin) => {
336 IOPin::Group2Io2
337 };
338 (G2IO3Pin) => {
339 IOPin::Group2Io3
340 };
341 (G2IO4Pin) => {
342 IOPin::Group2Io4
343 };
344
345 (G3IO1Pin) => {
346 IOPin::Group3Io1
347 };
348 (G3IO2Pin) => {
349 IOPin::Group3Io2
350 };
351 (G3IO3Pin) => {
352 IOPin::Group3Io3
353 };
354 (G3IO4Pin) => {
355 IOPin::Group3Io4
356 };
357
358 (G4IO1Pin) => {
359 IOPin::Group4Io1
360 };
361 (G4IO2Pin) => {
362 IOPin::Group4Io2
363 };
364 (G4IO3Pin) => {
365 IOPin::Group4Io3
366 };
367 (G4IO4Pin) => {
368 IOPin::Group4Io4
369 };
370
371 (G5IO1Pin) => {
372 IOPin::Group5Io1
373 };
374 (G5IO2Pin) => {
375 IOPin::Group5Io2
376 };
377 (G5IO3Pin) => {
378 IOPin::Group5Io3
379 };
380 (G5IO4Pin) => {
381 IOPin::Group5Io4
382 };
383
384 (G6IO1Pin) => {
385 IOPin::Group6Io1
386 };
387 (G6IO2Pin) => {
388 IOPin::Group6Io2
389 };
390 (G6IO3Pin) => {
391 IOPin::Group6Io3
392 };
393 (G6IO4Pin) => {
394 IOPin::Group6Io4
395 };
396
397 (G7IO1Pin) => {
398 TSC_V2_V3_GUARD!(IOPin::Group7Io1)
399 };
400 (G7IO2Pin) => {
401 TSC_V2_V3_GUARD!(IOPin::Group7Io2)
402 };
403 (G7IO3Pin) => {
404 TSC_V2_V3_GUARD!(IOPin::Group7Io3)
405 };
406 (G7IO4Pin) => {
407 TSC_V2_V3_GUARD!(IOPin::Group7Io4)
408 };
409
410 (G8IO1Pin) => {
411 TSC_V3_GUARD!(IOPin::Group8Io1)
412 };
413 (G8IO2Pin) => {
414 TSC_V3_GUARD!(IOPin::Group8Io2)
415 };
416 (G8IO3Pin) => {
417 TSC_V3_GUARD!(IOPin::Group8Io3)
418 };
419 (G8IO4Pin) => {
420 TSC_V3_GUARD!(IOPin::Group8Io4)
421 };
422}
423
424macro_rules! impl_set_io {
425 ($method:ident, $group:ident, $trait:ident, $index:expr) => {
426 #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")]
427 pub fn $method<Role: pin_roles::Role>(&mut self, pin: Peri<'d, impl $trait<T>>) -> IOPinWithRole<$group, Role> {
428 critical_section::with(|_| {
429 pin.set_low();
430 pin.set_as_af(pin.af_num(), AfType::output(Role::output_type(), Speed::VeryHigh));
431 let tsc_io_pin = trait_to_io_pin!($trait);
432 let new_pin = Pin {
433 _pin: pin.into(),
434 role: Role::pin_type(),
435 tsc_io_pin,
436 phantom: PhantomData,
437 };
438 *self.pin_group.pins_mut()[$index] = Some(new_pin);
439 IOPinWithRole {
440 pin: tsc_io_pin,
441 phantom: PhantomData,
442 }
443 })
444 }
445 };
446}
447
448macro_rules! group_impl {
449 ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
450 impl<'d, T: Instance, R1: pin_roles::Role, R2: pin_roles::Role, R3: pin_roles::Role, R4: pin_roles::Role>
451 PinGroupWithRoles<'d, T, $group, R1, R2, R3, R4>
452 {
453 impl_set_io!(set_io1, $group, $trait1, 0);
454 impl_set_io!(set_io2, $group, $trait2, 1);
455 impl_set_io!(set_io3, $group, $trait3, 2);
456 impl_set_io!(set_io4, $group, $trait4, 3);
457 }
458 };
459}
460
461group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin);
462group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin);
463group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin);
464group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin);
465group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin);
466group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin);
467#[cfg(any(tsc_v2, tsc_v3))]
468group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin);
469#[cfg(tsc_v3)]
470group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin);
471
472/// Group 1 marker type.
473#[derive(Clone, Copy, Debug)]
474pub enum G1 {}
475/// Group 2 marker type.
476#[derive(Clone, Copy, Debug)]
477pub enum G2 {}
478/// Group 3 marker type.
479#[derive(Clone, Copy, Debug)]
480pub enum G3 {}
481/// Group 4 marker type.
482#[derive(Clone, Copy, Debug)]
483pub enum G4 {}
484/// Group 5 marker type.
485#[derive(Clone, Copy, Debug)]
486pub enum G5 {}
487/// Group 6 marker type.
488#[derive(Clone, Copy, Debug)]
489pub enum G6 {}
490/// Group 7 marker type.
491#[derive(Clone, Copy, Debug)]
492pub enum G7 {}
493/// Group 8 marker type.
494#[derive(Clone, Copy, Debug)]
495pub enum G8 {}
496
497/// Represents the collection of pin groups for the Touch Sensing Controller (TSC).
498///
499/// Each field corresponds to a specific group of TSC pins:
500#[allow(missing_docs)]
501pub struct PinGroups<'d, T: Instance> {
502 pub g1: Option<PinGroup<'d, T, G1>>,
503 pub g2: Option<PinGroup<'d, T, G2>>,
504 pub g3: Option<PinGroup<'d, T, G3>>,
505 pub g4: Option<PinGroup<'d, T, G4>>,
506 pub g5: Option<PinGroup<'d, T, G5>>,
507 pub g6: Option<PinGroup<'d, T, G6>>,
508 #[cfg(any(tsc_v2, tsc_v3))]
509 pub g7: Option<PinGroup<'d, T, G7>>,
510 #[cfg(tsc_v3)]
511 pub g8: Option<PinGroup<'d, T, G8>>,
512}
513
514impl<'d, T: Instance> PinGroups<'d, T> {
515 pub(super) fn check(&self) -> Result<(), GroupError> {
516 let mut shield_count = 0;
517
518 // Helper function to check a single group
519 fn check_group<C, T: Instance>(
520 group: &Option<PinGroup<'_, T, C>>,
521 shield_count: &mut u32,
522 ) -> Result<(), GroupError> {
523 if let Some(group) = group {
524 group.check_group()?;
525 if group.contains_exactly_one_shield_pin() {
526 *shield_count += 1;
527 if *shield_count > 1 {
528 return Err(GroupError::MultipleShields);
529 }
530 }
531 }
532 Ok(())
533 }
534
535 // Check each group
536 check_group(&self.g1, &mut shield_count)?;
537 check_group(&self.g2, &mut shield_count)?;
538 check_group(&self.g3, &mut shield_count)?;
539 check_group(&self.g4, &mut shield_count)?;
540 check_group(&self.g5, &mut shield_count)?;
541 check_group(&self.g6, &mut shield_count)?;
542 #[cfg(any(tsc_v2, tsc_v3))]
543 check_group(&self.g7, &mut shield_count)?;
544 #[cfg(tsc_v3)]
545 check_group(&self.g8, &mut shield_count)?;
546
547 Ok(())
548 }
549
550 pub(super) fn make_channel_ios_mask(&self) -> u32 {
551 #[allow(unused_mut)]
552 let mut mask = self.g1.as_ref().map_or(0, |g| g.make_channel_ios_mask())
553 | self.g2.as_ref().map_or(0, |g| g.make_channel_ios_mask())
554 | self.g3.as_ref().map_or(0, |g| g.make_channel_ios_mask())
555 | self.g4.as_ref().map_or(0, |g| g.make_channel_ios_mask())
556 | self.g5.as_ref().map_or(0, |g| g.make_channel_ios_mask())
557 | self.g6.as_ref().map_or(0, |g| g.make_channel_ios_mask());
558 #[cfg(any(tsc_v2, tsc_v3))]
559 {
560 mask |= self.g7.as_ref().map_or(0, |g| g.make_channel_ios_mask());
561 }
562 #[cfg(tsc_v3)]
563 {
564 mask |= self.g8.as_ref().map_or(0, |g| g.make_channel_ios_mask());
565 }
566 mask
567 }
568
569 pub(super) fn make_shield_ios_mask(&self) -> u32 {
570 #[allow(unused_mut)]
571 let mut mask = self.g1.as_ref().map_or(0, |g| g.make_shield_ios_mask())
572 | self.g2.as_ref().map_or(0, |g| g.make_shield_ios_mask())
573 | self.g3.as_ref().map_or(0, |g| g.make_shield_ios_mask())
574 | self.g4.as_ref().map_or(0, |g| g.make_shield_ios_mask())
575 | self.g5.as_ref().map_or(0, |g| g.make_shield_ios_mask())
576 | self.g6.as_ref().map_or(0, |g| g.make_shield_ios_mask());
577 #[cfg(any(tsc_v2, tsc_v3))]
578 {
579 mask |= self.g7.as_ref().map_or(0, |g| g.make_shield_ios_mask());
580 }
581 #[cfg(tsc_v3)]
582 {
583 mask |= self.g8.as_ref().map_or(0, |g| g.make_shield_ios_mask());
584 }
585 mask
586 }
587
588 pub(super) fn make_sample_ios_mask(&self) -> u32 {
589 #[allow(unused_mut)]
590 let mut mask = self.g1.as_ref().map_or(0, |g| g.make_sample_ios_mask())
591 | self.g2.as_ref().map_or(0, |g| g.make_sample_ios_mask())
592 | self.g3.as_ref().map_or(0, |g| g.make_sample_ios_mask())
593 | self.g4.as_ref().map_or(0, |g| g.make_sample_ios_mask())
594 | self.g5.as_ref().map_or(0, |g| g.make_sample_ios_mask())
595 | self.g6.as_ref().map_or(0, |g| g.make_sample_ios_mask());
596 #[cfg(any(tsc_v2, tsc_v3))]
597 {
598 mask |= self.g7.as_ref().map_or(0, |g| g.make_sample_ios_mask());
599 }
600 #[cfg(tsc_v3)]
601 {
602 mask |= self.g8.as_ref().map_or(0, |g| g.make_sample_ios_mask());
603 }
604 mask
605 }
606}
607
608impl<'d, T: Instance> Default for PinGroups<'d, T> {
609 fn default() -> Self {
610 Self {
611 g1: None,
612 g2: None,
613 g3: None,
614 g4: None,
615 g5: None,
616 g6: None,
617 #[cfg(any(tsc_v2, tsc_v3))]
618 g7: None,
619 #[cfg(tsc_v3)]
620 g8: None,
621 }
622 }
623}
624
625pin_trait!(G1IO1Pin, Instance);
626pin_trait!(G1IO2Pin, Instance);
627pin_trait!(G1IO3Pin, Instance);
628pin_trait!(G1IO4Pin, Instance);
629
630pin_trait!(G2IO1Pin, Instance);
631pin_trait!(G2IO2Pin, Instance);
632pin_trait!(G2IO3Pin, Instance);
633pin_trait!(G2IO4Pin, Instance);
634
635pin_trait!(G3IO1Pin, Instance);
636pin_trait!(G3IO2Pin, Instance);
637pin_trait!(G3IO3Pin, Instance);
638pin_trait!(G3IO4Pin, Instance);
639
640pin_trait!(G4IO1Pin, Instance);
641pin_trait!(G4IO2Pin, Instance);
642pin_trait!(G4IO3Pin, Instance);
643pin_trait!(G4IO4Pin, Instance);
644
645pin_trait!(G5IO1Pin, Instance);
646pin_trait!(G5IO2Pin, Instance);
647pin_trait!(G5IO3Pin, Instance);
648pin_trait!(G5IO4Pin, Instance);
649
650pin_trait!(G6IO1Pin, Instance);
651pin_trait!(G6IO2Pin, Instance);
652pin_trait!(G6IO3Pin, Instance);
653pin_trait!(G6IO4Pin, Instance);
654
655pin_trait!(G7IO1Pin, Instance);
656pin_trait!(G7IO2Pin, Instance);
657pin_trait!(G7IO3Pin, Instance);
658pin_trait!(G7IO4Pin, Instance);
659
660pin_trait!(G8IO1Pin, Instance);
661pin_trait!(G8IO2Pin, Instance);
662pin_trait!(G8IO3Pin, Instance);
663pin_trait!(G8IO4Pin, Instance);
diff --git a/embassy-stm32/src/tsc/tsc.rs b/embassy-stm32/src/tsc/tsc.rs
new file mode 100644
index 000000000..e92479c26
--- /dev/null
+++ b/embassy-stm32/src/tsc/tsc.rs
@@ -0,0 +1,446 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::ops::BitOr;
4use core::task::Poll;
5
6use embassy_hal_internal::Peri;
7
8use super::acquisition_banks::*;
9use super::config::*;
10use super::errors::*;
11use super::io_pin::*;
12use super::pin_groups::*;
13use super::types::*;
14use super::{Instance, InterruptHandler, TSC_NUM_GROUPS};
15use crate::interrupt::typelevel::Interrupt;
16use crate::mode::{Async, Blocking, Mode as PeriMode};
17use crate::{interrupt, rcc};
18
19/// Internal structure holding masks for different types of TSC IOs.
20///
21/// These masks are used during the initial configuration of the TSC peripheral
22/// and for validating pin types during operations like creating acquisition banks.
23struct IOMasks {
24 /// Mask representing all configured channel IOs
25 channel_ios: u32,
26 /// Mask representing all configured shield IOs
27 shield_ios: u32,
28 /// Mask representing all configured sampling IOs
29 sampling_ios: u32,
30}
31
32/// TSC driver
33pub struct Tsc<'d, T: Instance, K: PeriMode> {
34 _peri: Peri<'d, T>,
35 _pin_groups: PinGroups<'d, T>,
36 state: State,
37 config: Config,
38 masks: IOMasks,
39 _kind: PhantomData<K>,
40}
41
42impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> {
43 // Helper method to check if a pin is a channel pin
44 fn is_channel_pin(&self, pin: IOPin) -> bool {
45 (self.masks.channel_ios & pin) != 0
46 }
47
48 /// Get the status of all groups involved in a AcquisitionBank
49 pub fn get_acquisition_bank_status(&self, bank: &AcquisitionBank) -> AcquisitionBankStatus {
50 let mut bank_status = AcquisitionBankStatus::default();
51 for pin in bank.pins_iterator() {
52 let group = pin.group();
53 let group_status = self.group_get_status(group);
54 let index: usize = group.into();
55 bank_status.groups[index] = Some(group_status);
56 }
57 bank_status
58 }
59
60 /// Get the values for all channels involved in a AcquisitionBank
61 pub fn get_acquisition_bank_values(&self, bank: &AcquisitionBank) -> AcquisitionBankReadings {
62 let mut bank_readings = AcquisitionBankReadings::default();
63 for pin in bank.pins_iterator() {
64 let group = pin.group();
65 let value = self.group_get_value(group);
66 let reading = ChannelReading {
67 sensor_value: value,
68 tsc_pin: pin,
69 };
70 let index: usize = group.into();
71 bank_readings.groups[index] = Some(reading);
72 }
73 bank_readings
74 }
75
76 /// Creates a new TSC acquisition bank from the provided pin configuration.
77 ///
78 /// This method creates a `AcquisitionBank` that can be used for efficient,
79 /// repeated TSC acquisitions. It automatically generates the appropriate mask
80 /// for the provided pins.
81 ///
82 /// # Note on TSC Hardware Limitation
83 ///
84 /// The TSC hardware can only read one channel pin from each TSC group per acquisition.
85 ///
86 /// # Arguments
87 /// * `acquisition_bank_pins` - The pin configuration for the acquisition bank.
88 ///
89 /// # Returns
90 /// A new `AcquisitionBank` instance.
91 ///
92 /// # Example
93 ///
94 /// ```
95 /// let tsc = // ... initialize TSC
96 /// let tsc_sensor1: tsc::IOPinWithRole<G1, tsc_pin_roles::Channel> = ...;
97 /// let tsc_sensor2: tsc::IOPinWithRole<G2, tsc_pin_roles::Channel> = ...;
98 ///
99 /// let bank = tsc.create_acquisition_bank(AcquisitionBankPins {
100 /// g1_pin: Some(tsc_sensor1),
101 /// g2_pin: Some(tsc_sensor2),
102 /// ..Default::default()
103 /// });
104 ///
105 /// // Use the bank for acquisitions
106 /// tsc.set_active_channels_bank(&bank);
107 /// tsc.start();
108 /// // ... perform acquisition ...
109 /// ```
110 pub fn create_acquisition_bank(&self, acquisition_bank_pins: AcquisitionBankPins) -> AcquisitionBank {
111 let bank_mask = acquisition_bank_pins.iter().fold(0u32, BitOr::bitor);
112
113 AcquisitionBank {
114 pins: acquisition_bank_pins,
115 mask: bank_mask,
116 }
117 }
118
119 fn make_channels_mask<Itt>(&self, channels: Itt) -> Result<u32, AcquisitionBankError>
120 where
121 Itt: IntoIterator<Item = IOPin>,
122 {
123 let mut group_mask = 0u32;
124 let mut channel_mask = 0u32;
125
126 for channel in channels {
127 if !self.is_channel_pin(channel) {
128 return Err(AcquisitionBankError::InvalidChannelPin);
129 }
130
131 let group = channel.group();
132 let group_bit: u32 = 1 << Into::<usize>::into(group);
133 if group_mask & group_bit != 0 {
134 return Err(AcquisitionBankError::MultipleChannelsPerGroup);
135 }
136
137 group_mask |= group_bit;
138 channel_mask |= channel;
139 }
140
141 Ok(channel_mask)
142 }
143
144 /// Sets the active channels for the next TSC acquisition.
145 ///
146 /// This is a low-level method that directly sets the channel mask. For most use cases,
147 /// consider using `set_active_channels_bank` with a `AcquisitionBank` instead, which
148 /// provides a higher-level interface and additional safety checks.
149 ///
150 /// This method configures which sensor channels will be read during the next
151 /// touch sensing acquisition cycle. It should be called before starting a new
152 /// acquisition with the start() method.
153 ///
154 /// # Arguments
155 /// * `mask` - A 32-bit mask where each bit represents a channel. Set bits indicate
156 /// active channels.
157 ///
158 /// # Note
159 /// Only one pin from each TSC group can be read for each acquisition. This method
160 /// does not perform checks to ensure this limitation is met. Incorrect masks may
161 /// lead to unexpected behavior.
162 ///
163 /// # Safety
164 /// This method doesn't perform extensive checks on the provided mask. Ensure that
165 /// the mask is valid and adheres to hardware limitations to avoid undefined behavior.
166 pub fn set_active_channels_mask(&mut self, mask: u32) {
167 T::regs().ioccr().write(|w| w.0 = mask | self.masks.shield_ios);
168 }
169
170 /// Convenience method for setting active channels directly from a slice of tsc::IOPin.
171 /// This method performs safety checks but is less efficient for repeated use.
172 pub fn set_active_channels(&mut self, channels: &[IOPin]) -> Result<(), AcquisitionBankError> {
173 let mask = self.make_channels_mask(channels.iter().cloned())?;
174 self.set_active_channels_mask(mask);
175 Ok(())
176 }
177
178 /// Sets the active channels for the next TSC acquisition using a pre-configured acquisition bank.
179 ///
180 /// This method efficiently configures the TSC peripheral to read the channels specified
181 /// in the provided `AcquisitionBank`. It's the recommended way to set up
182 /// channel configurations for acquisition, especially when using the same set of channels repeatedly.
183 ///
184 /// # Arguments
185 ///
186 /// * `bank` - A reference to a `AcquisitionBank` containing the pre-configured
187 /// TSC channel mask.
188 ///
189 /// # Example
190 ///
191 /// ```
192 /// let tsc_sensor1: tsc::IOPinWithRole<G1, Channel> = ...;
193 /// let tsc_sensor2: tsc::IOPinWithRole<G5, Channel> = ...;
194 /// let mut touch_controller: Tsc<'_, TSC, Async> = ...;
195 /// let bank = touch_controller.create_acquisition_bank(AcquisitionBankPins {
196 /// g1_pin: Some(tsc_sensor1),
197 /// g2_pin: Some(tsc_sensor2),
198 /// ..Default::default()
199 /// });
200 ///
201 /// touch_controller.set_active_channels_bank(&bank);
202 /// touch_controller.start();
203 /// // ... perform acquisition ...
204 /// ```
205 ///
206 /// This method should be called before starting a new acquisition with the `start()` method.
207 pub fn set_active_channels_bank(&mut self, bank: &AcquisitionBank) {
208 self.set_active_channels_mask(bank.mask)
209 }
210
211 fn extract_groups(io_mask: u32) -> u32 {
212 let mut groups: u32 = 0;
213 for idx in 0..TSC_NUM_GROUPS {
214 if io_mask & (0x0F << (idx * 4)) != 0 {
215 groups |= 1 << idx
216 }
217 }
218 groups
219 }
220
221 fn new_inner(peri: Peri<'d, T>, pin_groups: PinGroups<'d, T>, config: Config) -> Result<Self, GroupError> {
222 pin_groups.check()?;
223
224 let masks = IOMasks {
225 channel_ios: pin_groups.make_channel_ios_mask(),
226 shield_ios: pin_groups.make_shield_ios_mask(),
227 sampling_ios: pin_groups.make_sample_ios_mask(),
228 };
229
230 rcc::enable_and_reset::<T>();
231
232 T::regs().cr().modify(|w| {
233 w.set_tsce(true);
234 w.set_ctph(config.ct_pulse_high_length.into());
235 w.set_ctpl(config.ct_pulse_low_length.into());
236 w.set_sse(config.spread_spectrum);
237 // Prevent invalid configuration for pulse generator prescaler
238 if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1
239 && (config.pulse_generator_prescaler == PGPrescalerDivider::_1
240 || config.pulse_generator_prescaler == PGPrescalerDivider::_2)
241 {
242 w.set_pgpsc(PGPrescalerDivider::_4.into());
243 } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2
244 && config.pulse_generator_prescaler == PGPrescalerDivider::_1
245 {
246 w.set_pgpsc(PGPrescalerDivider::_2.into());
247 } else {
248 w.set_pgpsc(config.pulse_generator_prescaler.into());
249 }
250 w.set_ssd(config.spread_spectrum_deviation.into());
251 w.set_sspsc(config.spread_spectrum_prescaler);
252
253 w.set_mcv(config.max_count_value.into());
254 w.set_syncpol(config.synchro_pin_polarity);
255 w.set_am(config.acquisition_mode);
256 });
257
258 // Set IO configuration
259 // Disable Schmitt trigger hysteresis on all used TSC IOs
260 T::regs()
261 .iohcr()
262 .write(|w| w.0 = !(masks.channel_ios | masks.shield_ios | masks.sampling_ios));
263
264 // Set channel and shield IOs
265 T::regs().ioccr().write(|w| w.0 = masks.channel_ios | masks.shield_ios);
266
267 // Set sampling IOs
268 T::regs().ioscr().write(|w| w.0 = masks.sampling_ios);
269
270 // Set the groups to be acquired
271 // Lower bits of `iogcsr` are for enabling groups, while the higher bits are for reading
272 // status of acquisiton for a group, see method `Tsc::group_get_status`.
273 T::regs()
274 .iogcsr()
275 .write(|w| w.0 = Self::extract_groups(masks.channel_ios));
276
277 // Disable interrupts
278 T::regs().ier().modify(|w| {
279 w.set_eoaie(false);
280 w.set_mceie(false);
281 });
282
283 // Clear flags
284 T::regs().icr().modify(|w| {
285 w.set_eoaic(true);
286 w.set_mceic(true);
287 });
288
289 unsafe {
290 T::Interrupt::enable();
291 }
292
293 Ok(Self {
294 _peri: peri,
295 _pin_groups: pin_groups,
296 state: State::Ready,
297 config,
298 masks,
299 _kind: PhantomData,
300 })
301 }
302
303 /// Start charge transfer acquisition
304 pub fn start(&mut self) {
305 self.state = State::Busy;
306
307 // Disable interrupts
308 T::regs().ier().modify(|w| {
309 w.set_eoaie(false);
310 w.set_mceie(false);
311 });
312
313 // Clear flags
314 T::regs().icr().modify(|w| {
315 w.set_eoaic(true);
316 w.set_mceic(true);
317 });
318
319 // Set the touch sensing IOs not acquired to the default mode
320 T::regs().cr().modify(|w| {
321 w.set_iodef(self.config.io_default_mode);
322 });
323
324 // Start the acquisition
325 T::regs().cr().modify(|w| {
326 w.set_start(true);
327 });
328 }
329
330 /// Stop charge transfer acquisition
331 pub fn stop(&mut self) {
332 T::regs().cr().modify(|w| {
333 w.set_start(false);
334 });
335
336 // Set the touch sensing IOs in low power mode
337 T::regs().cr().modify(|w| {
338 w.set_iodef(false);
339 });
340
341 // Clear flags
342 T::regs().icr().modify(|w| {
343 w.set_eoaic(true);
344 w.set_mceic(true);
345 });
346
347 self.state = State::Ready;
348 }
349
350 /// Get current state of acquisition
351 pub fn get_state(&mut self) -> State {
352 if self.state == State::Busy && T::regs().isr().read().eoaf() {
353 if T::regs().isr().read().mcef() {
354 self.state = State::Error
355 } else {
356 self.state = State::Ready
357 }
358 }
359 self.state
360 }
361
362 /// Get the individual group status to check acquisition complete
363 pub fn group_get_status(&self, index: Group) -> GroupStatus {
364 // Status bits are set by hardware when the acquisition on the corresponding
365 // enabled analog IO group is complete, cleared when new acquisition is started
366 let status = match index {
367 Group::One => T::regs().iogcsr().read().g1s(),
368 Group::Two => T::regs().iogcsr().read().g2s(),
369 Group::Three => T::regs().iogcsr().read().g3s(),
370 Group::Four => T::regs().iogcsr().read().g4s(),
371 Group::Five => T::regs().iogcsr().read().g5s(),
372 Group::Six => T::regs().iogcsr().read().g6s(),
373 #[cfg(any(tsc_v2, tsc_v3))]
374 Group::Seven => T::regs().iogcsr().read().g7s(),
375 #[cfg(tsc_v3)]
376 Group::Eight => T::regs().iogcsr().read().g8s(),
377 };
378 match status {
379 true => GroupStatus::Complete,
380 false => GroupStatus::Ongoing,
381 }
382 }
383
384 /// Get the count for the acquisiton, valid once group status is set
385 pub fn group_get_value(&self, index: Group) -> u16 {
386 T::regs().iogcr(index.into()).read().cnt()
387 }
388
389 /// Discharge the IOs for subsequent acquisition
390 pub fn discharge_io(&mut self, status: bool) {
391 // Set the touch sensing IOs in low power mode
392 T::regs().cr().modify(|w| {
393 w.set_iodef(!status);
394 });
395 }
396}
397
398impl<'d, T: Instance, K: PeriMode> Drop for Tsc<'d, T, K> {
399 fn drop(&mut self) {
400 rcc::disable::<T>();
401 }
402}
403
404impl<'d, T: Instance> Tsc<'d, T, Async> {
405 /// Create a Tsc instance that can be awaited for completion
406 pub fn new_async(
407 peri: Peri<'d, T>,
408 pin_groups: PinGroups<'d, T>,
409 config: Config,
410 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
411 ) -> Result<Self, GroupError> {
412 Self::new_inner(peri, pin_groups, config)
413 }
414
415 /// Asyncronously wait for the end of an acquisition
416 pub async fn pend_for_acquisition(&mut self) {
417 poll_fn(|cx| match self.get_state() {
418 State::Busy => {
419 T::waker().register(cx.waker());
420 T::regs().ier().write(|w| w.set_eoaie(true));
421 if self.get_state() != State::Busy {
422 T::regs().ier().write(|w| w.set_eoaie(false));
423 return Poll::Ready(());
424 }
425 Poll::Pending
426 }
427 _ => {
428 T::regs().ier().write(|w| w.set_eoaie(false));
429 Poll::Ready(())
430 }
431 })
432 .await;
433 }
434}
435
436impl<'d, T: Instance> Tsc<'d, T, Blocking> {
437 /// Create a Tsc instance that must be polled for completion
438 pub fn new_blocking(peri: Peri<'d, T>, pin_groups: PinGroups<'d, T>, config: Config) -> Result<Self, GroupError> {
439 Self::new_inner(peri, pin_groups, config)
440 }
441
442 /// Wait for end of acquisition
443 pub fn poll_for_acquisition(&mut self) {
444 while self.get_state() == State::Busy {}
445 }
446}
diff --git a/embassy-stm32/src/tsc/types.rs b/embassy-stm32/src/tsc/types.rs
new file mode 100644
index 000000000..0e8fa7f28
--- /dev/null
+++ b/embassy-stm32/src/tsc/types.rs
@@ -0,0 +1,93 @@
1/// Peripheral state
2#[cfg_attr(feature = "defmt", derive(defmt::Format))]
3#[derive(PartialEq, Clone, Copy)]
4pub enum State {
5 /// Peripheral is being setup or reconfigured
6 Reset,
7 /// Ready to start acquisition
8 Ready,
9 /// In process of sensor acquisition
10 Busy,
11 /// Error occured during acquisition
12 Error,
13}
14
15/// Individual group status checked after acquisition reported as complete
16/// For groups with multiple channel pins, may take longer because acquisitions
17/// are done sequentially. Check this status before pulling count for each
18/// sampled channel
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20#[derive(PartialEq, Clone, Copy)]
21pub enum GroupStatus {
22 /// Acquisition for channel still in progress
23 Ongoing,
24 /// Acquisition either not started or complete
25 Complete,
26}
27
28/// Group identifier used to interrogate status
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30#[allow(missing_docs)]
31#[derive(PartialEq, Clone, Copy)]
32pub enum Group {
33 One,
34 Two,
35 Three,
36 Four,
37 Five,
38 Six,
39 #[cfg(any(tsc_v2, tsc_v3))]
40 Seven,
41 #[cfg(tsc_v3)]
42 Eight,
43}
44
45impl Into<usize> for Group {
46 fn into(self) -> usize {
47 match self {
48 Group::One => 0,
49 Group::Two => 1,
50 Group::Three => 2,
51 Group::Four => 3,
52 Group::Five => 4,
53 Group::Six => 5,
54 #[cfg(any(tsc_v2, tsc_v3))]
55 Group::Seven => 6,
56 #[cfg(tsc_v3)]
57 Group::Eight => 7,
58 }
59 }
60}
61
62/// Error returned when attempting to create a Group from an invalid numeric value.
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub struct InvalidGroupError {
65 invalid_value: usize,
66}
67
68impl InvalidGroupError {
69 #[allow(missing_docs)]
70 pub fn new(value: usize) -> Self {
71 Self { invalid_value: value }
72 }
73}
74
75impl TryFrom<usize> for Group {
76 type Error = InvalidGroupError;
77
78 fn try_from(value: usize) -> Result<Self, Self::Error> {
79 match value {
80 0 => Ok(Group::One),
81 1 => Ok(Group::Two),
82 2 => Ok(Group::Three),
83 3 => Ok(Group::Four),
84 4 => Ok(Group::Five),
85 5 => Ok(Group::Six),
86 #[cfg(any(tsc_v2, tsc_v3))]
87 6 => Ok(Group::Two),
88 #[cfg(tsc_v3)]
89 7 => Ok(Group::Two),
90 n => Err(InvalidGroupError::new(n)),
91 }
92 }
93}
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 40aea75cb..87693f148 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -20,15 +20,15 @@ use core::sync::atomic::{AtomicBool, Ordering};
20use core::task::Poll; 20use core::task::Poll;
21 21
22use embassy_hal_internal::drop::OnDrop; 22use embassy_hal_internal::drop::OnDrop;
23use embassy_hal_internal::{into_ref, Peripheral}; 23use embassy_hal_internal::PeripheralType;
24use embassy_sync::waitqueue::AtomicWaker; 24use embassy_sync::waitqueue::AtomicWaker;
25 25
26use crate::dma::{ChannelAndRequest, TransferOptions}; 26use crate::dma::{ChannelAndRequest, TransferOptions};
27use crate::interrupt;
28use crate::interrupt::typelevel::Interrupt; 27use crate::interrupt::typelevel::Interrupt;
29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; 28use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; 29pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState};
31use crate::rcc::{self, RccPeripheral}; 30use crate::rcc::{self, RccPeripheral};
31use crate::{interrupt, Peri};
32 32
33pub(crate) fn init( 33pub(crate) fn init(
34 _cs: critical_section::CriticalSection, 34 _cs: critical_section::CriticalSection,
@@ -86,6 +86,34 @@ pub enum CcPull {
86 Source3_0A, 86 Source3_0A,
87} 87}
88 88
89/// UCPD configuration
90#[non_exhaustive]
91#[derive(Copy, Clone, Debug)]
92pub struct Config {
93 /// Receive SOP packets
94 pub sop: bool,
95 /// Receive SOP' packets
96 pub sop_prime: bool,
97 /// Receive SOP'' packets
98 pub sop_double_prime: bool,
99 /// Receive SOP'_Debug packets
100 pub sop_prime_debug: bool,
101 /// Receive SOP''_Debug packets
102 pub sop_double_prime_debug: bool,
103}
104
105impl Default for Config {
106 fn default() -> Self {
107 Self {
108 sop: true,
109 sop_prime: false,
110 sop_double_prime: false,
111 sop_prime_debug: false,
112 sop_double_prime_debug: false,
113 }
114 }
115}
116
89/// UCPD driver. 117/// UCPD driver.
90pub struct Ucpd<'d, T: Instance> { 118pub struct Ucpd<'d, T: Instance> {
91 cc_phy: CcPhy<'d, T>, 119 cc_phy: CcPhy<'d, T>,
@@ -94,12 +122,12 @@ pub struct Ucpd<'d, T: Instance> {
94impl<'d, T: Instance> Ucpd<'d, T> { 122impl<'d, T: Instance> Ucpd<'d, T> {
95 /// Creates a new UCPD driver instance. 123 /// Creates a new UCPD driver instance.
96 pub fn new( 124 pub fn new(
97 _peri: impl Peripheral<P = T> + 'd, 125 _peri: Peri<'d, T>,
98 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 126 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
99 cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd, 127 cc1: Peri<'d, impl Cc1Pin<T>>,
100 cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd, 128 cc2: Peri<'d, impl Cc2Pin<T>>,
129 config: Config,
101 ) -> Self { 130 ) -> Self {
102 into_ref!(cc1, cc2);
103 cc1.set_as_analog(); 131 cc1.set_as_analog();
104 cc2.set_as_analog(); 132 cc2.set_as_analog();
105 133
@@ -108,6 +136,13 @@ impl<'d, T: Instance> Ucpd<'d, T> {
108 unsafe { T::Interrupt::enable() }; 136 unsafe { T::Interrupt::enable() };
109 137
110 let r = T::REGS; 138 let r = T::REGS;
139
140 #[cfg(stm32h5)]
141 r.cfgr2().write(|w| {
142 // Only takes effect, when UCPDEN=0.
143 w.set_rxafilten(true);
144 });
145
111 r.cfgr1().write(|w| { 146 r.cfgr1().write(|w| {
112 // "The receiver is designed to work in the clock frequency range from 6 to 18 MHz. 147 // "The receiver is designed to work in the clock frequency range from 6 to 18 MHz.
113 // However, the optimum performance is ensured in the range from 6 to 12 MHz" 148 // However, the optimum performance is ensured in the range from 6 to 12 MHz"
@@ -129,9 +164,15 @@ impl<'d, T: Instance> Ucpd<'d, T> {
129 // 1.75us * 17 = ~30us 164 // 1.75us * 17 = ~30us
130 w.set_ifrgap(17 - 1); 165 w.set_ifrgap(17 - 1);
131 166
132 // TODO: Currently only hard reset and SOP messages can be received.
133 // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing). 167 // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing).
134 w.set_rxordseten(0b1001); 168 let rxordset = (config.sop as u16) << 0
169 | (config.sop_prime as u16) << 1
170 | (config.sop_double_prime as u16) << 2
171 // Hard reset
172 | 0x1 << 3
173 | (config.sop_prime_debug as u16) << 4
174 | (config.sop_double_prime_debug as u16) << 5;
175 w.set_rxordseten(rxordset);
135 176
136 // Enable DMA 177 // Enable DMA
137 w.set_txdmaen(true); 178 w.set_txdmaen(true);
@@ -140,6 +181,18 @@ impl<'d, T: Instance> Ucpd<'d, T> {
140 w.set_ucpden(true); 181 w.set_ucpden(true);
141 }); 182 });
142 183
184 // Software trim according to RM0481, p. 2650/2668
185 #[cfg(stm32h5)]
186 {
187 let trim_rd_cc1 = unsafe { *(0x4002_242C as *const u32) & 0xF };
188 let trim_rd_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 8) & 0xF };
189
190 r.cfgr3().write(|w| {
191 w.set_trim_cc1_rd(trim_rd_cc1 as u8);
192 w.set_trim_cc2_rd(trim_rd_cc2 as u8);
193 });
194 }
195
143 Self { 196 Self {
144 cc_phy: CcPhy { _lifetime: PhantomData }, 197 cc_phy: CcPhy { _lifetime: PhantomData },
145 } 198 }
@@ -154,8 +207,8 @@ impl<'d, T: Instance> Ucpd<'d, T> {
154 /// and a Power Delivery (PD) PHY with receiver and transmitter. 207 /// and a Power Delivery (PD) PHY with receiver and transmitter.
155 pub fn split_pd_phy( 208 pub fn split_pd_phy(
156 self, 209 self,
157 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 210 rx_dma: Peri<'d, impl RxDma<T>>,
158 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 211 tx_dma: Peri<'d, impl TxDma<T>>,
159 cc_sel: CcSel, 212 cc_sel: CcSel,
160 ) -> (CcPhy<'d, T>, PdPhy<'d, T>) { 213 ) -> (CcPhy<'d, T>, PdPhy<'d, T>) {
161 let r = T::REGS; 214 let r = T::REGS;
@@ -175,7 +228,6 @@ impl<'d, T: Instance> Ucpd<'d, T> {
175 // Both parts must be dropped before the peripheral can be disabled. 228 // Both parts must be dropped before the peripheral can be disabled.
176 T::state().drop_not_ready.store(true, Ordering::Relaxed); 229 T::state().drop_not_ready.store(true, Ordering::Relaxed);
177 230
178 into_ref!(rx_dma, tx_dma);
179 let rx_dma_req = rx_dma.request(); 231 let rx_dma_req = rx_dma.request();
180 let tx_dma_req = tx_dma.request(); 232 let tx_dma_req = tx_dma.request();
181 ( 233 (
@@ -183,11 +235,11 @@ impl<'d, T: Instance> Ucpd<'d, T> {
183 PdPhy { 235 PdPhy {
184 _lifetime: PhantomData, 236 _lifetime: PhantomData,
185 rx_dma: ChannelAndRequest { 237 rx_dma: ChannelAndRequest {
186 channel: rx_dma.map_into(), 238 channel: rx_dma.into(),
187 request: rx_dma_req, 239 request: rx_dma_req,
188 }, 240 },
189 tx_dma: ChannelAndRequest { 241 tx_dma: ChannelAndRequest {
190 channel: tx_dma.map_into(), 242 channel: tx_dma.into(),
191 request: tx_dma_req, 243 request: tx_dma_req,
192 }, 244 },
193 }, 245 },
@@ -212,7 +264,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> {
212 // Check if the PdPhy part was dropped already. 264 // Check if the PdPhy part was dropped already.
213 let drop_not_ready = &T::state().drop_not_ready; 265 let drop_not_ready = &T::state().drop_not_ready;
214 if drop_not_ready.load(Ordering::Relaxed) { 266 if drop_not_ready.load(Ordering::Relaxed) {
215 drop_not_ready.store(true, Ordering::Relaxed); 267 drop_not_ready.store(false, Ordering::Relaxed);
216 } else { 268 } else {
217 r.cfgr1().write(|w| w.set_ucpden(false)); 269 r.cfgr1().write(|w| w.set_ucpden(false));
218 rcc::disable::<T>(); 270 rcc::disable::<T>();
@@ -243,6 +295,25 @@ impl<'d, T: Instance> CcPhy<'d, T> {
243 }); 295 });
244 }); 296 });
245 297
298 // Software trim according to RM0481, p. 2650/2668
299 #[cfg(stm32h5)]
300 T::REGS.cfgr3().modify(|w| match cc_pull {
301 CcPull::Source1_5A => {
302 let trim_1a5_cc1 = unsafe { *(0x08FF_F844 as *const u32) & 0xF };
303 let trim_1a5_cc2 = unsafe { ((*(0x08FF_F844 as *const u32)) >> 16) & 0xF };
304
305 w.set_trim_cc1_rp(trim_1a5_cc1 as u8);
306 w.set_trim_cc2_rp(trim_1a5_cc2 as u8);
307 }
308 _ => {
309 let trim_3a0_cc1 = unsafe { (*(0x4002_242C as *const u32) >> 4) & 0xF };
310 let trim_3a0_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 12) & 0xF };
311
312 w.set_trim_cc1_rp(trim_3a0_cc1 as u8);
313 w.set_trim_cc2_rp(trim_3a0_cc2 as u8);
314 }
315 });
316
246 // Disable dead-battery pull-down resistors which are enabled by default on boot. 317 // Disable dead-battery pull-down resistors which are enabled by default on boot.
247 critical_section::with(|cs| { 318 critical_section::with(|cs| {
248 init( 319 init(
@@ -288,6 +359,22 @@ impl<'d, T: Instance> CcPhy<'d, T> {
288 } 359 }
289} 360}
290 361
362/// Receive SOP.
363#[derive(Debug, Clone, Copy)]
364#[cfg_attr(feature = "defmt", derive(defmt::Format))]
365pub enum Sop {
366 /// SOP
367 Sop,
368 /// SOP'
369 SopPrime,
370 /// SOP''
371 SopDoublePrime,
372 /// SOP'_Debug
373 SopPrimeDebug,
374 /// SOP''_Debug
375 SopDoublePrimeDebug,
376}
377
291/// Receive Error. 378/// Receive Error.
292#[derive(Debug, Clone, Copy)] 379#[derive(Debug, Clone, Copy)]
293#[cfg_attr(feature = "defmt", derive(defmt::Format))] 380#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -322,13 +409,14 @@ pub struct PdPhy<'d, T: Instance> {
322 409
323impl<'d, T: Instance> Drop for PdPhy<'d, T> { 410impl<'d, T: Instance> Drop for PdPhy<'d, T> {
324 fn drop(&mut self) { 411 fn drop(&mut self) {
325 T::REGS.cr().modify(|w| w.set_phyrxen(false)); 412 let r = T::REGS;
326 // Check if the Type-C part was dropped already. 413 r.cr().modify(|w| w.set_phyrxen(false));
414 // Check if the CcPhy part was dropped already.
327 let drop_not_ready = &T::state().drop_not_ready; 415 let drop_not_ready = &T::state().drop_not_ready;
328 if drop_not_ready.load(Ordering::Relaxed) { 416 if drop_not_ready.load(Ordering::Relaxed) {
329 drop_not_ready.store(true, Ordering::Relaxed); 417 drop_not_ready.store(false, Ordering::Relaxed);
330 } else { 418 } else {
331 T::REGS.cfgr1().write(|w| w.set_ucpden(false)); 419 r.cfgr1().write(|w| w.set_ucpden(false));
332 rcc::disable::<T>(); 420 rcc::disable::<T>();
333 T::Interrupt::disable(); 421 T::Interrupt::disable();
334 } 422 }
@@ -340,9 +428,16 @@ impl<'d, T: Instance> PdPhy<'d, T> {
340 /// 428 ///
341 /// Returns the number of received bytes or an error. 429 /// Returns the number of received bytes or an error.
342 pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> { 430 pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
431 self.receive_with_sop(buf).await.map(|(_sop, size)| size)
432 }
433
434 /// Receives SOP and a PD message into the provided buffer.
435 ///
436 /// Returns the start of packet type and number of received bytes or an error.
437 pub async fn receive_with_sop(&mut self, buf: &mut [u8]) -> Result<(Sop, usize), RxError> {
343 let r = T::REGS; 438 let r = T::REGS;
344 439
345 let dma = unsafe { 440 let mut dma = unsafe {
346 self.rx_dma 441 self.rx_dma
347 .read(r.rxdr().as_ptr() as *mut u8, buf, TransferOptions::default()) 442 .read(r.rxdr().as_ptr() as *mut u8, buf, TransferOptions::default())
348 }; 443 };
@@ -357,14 +452,24 @@ impl<'d, T: Instance> PdPhy<'d, T> {
357 }); 452 });
358 }); 453 });
359 454
455 let mut rxpaysz = 0;
456
457 // Stop DMA reception immediately after receiving a packet, to prevent storing multiple packets in the same buffer.
360 poll_fn(|cx| { 458 poll_fn(|cx| {
361 let sr = r.sr().read(); 459 let sr = r.sr().read();
460
362 if sr.rxhrstdet() { 461 if sr.rxhrstdet() {
462 dma.request_stop();
463
363 // Clean and re-enable hard reset receive interrupt. 464 // Clean and re-enable hard reset receive interrupt.
364 r.icr().write(|w| w.set_rxhrstdetcf(true)); 465 r.icr().write(|w| w.set_rxhrstdetcf(true));
365 r.imr().modify(|w| w.set_rxhrstdetie(true)); 466 r.imr().modify(|w| w.set_rxhrstdetie(true));
366 Poll::Ready(Err(RxError::HardReset)) 467 Poll::Ready(Err(RxError::HardReset))
367 } else if sr.rxmsgend() { 468 } else if sr.rxmsgend() {
469 dma.request_stop();
470 // Should be read immediately on interrupt.
471 rxpaysz = r.rx_payszr().read().rxpaysz().into();
472
368 let ret = if sr.rxovr() { 473 let ret = if sr.rxovr() {
369 Err(RxError::Overrun) 474 Err(RxError::Overrun)
370 } else if sr.rxerr() { 475 } else if sr.rxerr() {
@@ -388,7 +493,18 @@ impl<'d, T: Instance> PdPhy<'d, T> {
388 } 493 }
389 } 494 }
390 495
391 Ok(r.rx_payszr().read().rxpaysz().into()) 496 let sop = match r.rx_ordsetr().read().rxordset() {
497 Rxordset::SOP => Sop::Sop,
498 Rxordset::SOP_PRIME => Sop::SopPrime,
499 Rxordset::SOP_DOUBLE_PRIME => Sop::SopDoublePrime,
500 Rxordset::SOP_PRIME_DEBUG => Sop::SopPrimeDebug,
501 Rxordset::SOP_DOUBLE_PRIME_DEBUG => Sop::SopDoublePrimeDebug,
502 Rxordset::CABLE_RESET => return Err(RxError::HardReset),
503 // Extension headers are not supported
504 _ => unreachable!(),
505 };
506
507 Ok((sop, rxpaysz))
392 } 508 }
393 509
394 fn enable_rx_interrupt(enable: bool) { 510 fn enable_rx_interrupt(enable: bool) {
@@ -571,7 +687,7 @@ trait SealedInstance {
571 687
572/// UCPD instance trait. 688/// UCPD instance trait.
573#[allow(private_bounds)] 689#[allow(private_bounds)]
574pub trait Instance: SealedInstance + RccPeripheral { 690pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {
575 /// Interrupt for this instance. 691 /// Interrupt for this instance.
576 type Interrupt: crate::interrupt::typelevel::Interrupt; 692 type Interrupt: crate::interrupt::typelevel::Interrupt;
577} 693}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 06cc0e41d..73ab46404 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -6,16 +6,17 @@ use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 8use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
9use embassy_hal_internal::{Peripheral, PeripheralRef}; 9use embassy_hal_internal::Peri;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12#[cfg(not(any(usart_v1, usart_v2)))] 12#[cfg(not(any(usart_v1, usart_v2)))]
13use super::DePin; 13use super::DePin;
14use super::{ 14use super::{
15 clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance, 15 clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate,
16 Regs, RtsPin, RxPin, TxPin, 16 sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin,
17 TxPin,
17}; 18};
18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 19use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
19use crate::interrupt::{self, InterruptExt}; 20use crate::interrupt::{self, InterruptExt};
20use crate::time::Hertz; 21use crate::time::Hertz;
21 22
@@ -108,6 +109,8 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
108 }); 109 });
109 } 110 }
110 111
112 half_duplex_set_rx_tx_before_write(&r, state.half_duplex_readback.load(Ordering::Relaxed));
113
111 tdr(r).write_volatile(buf[0].into()); 114 tdr(r).write_volatile(buf[0].into());
112 tx_reader.pop_done(1); 115 tx_reader.pop_done(1);
113 } else { 116 } else {
@@ -126,6 +129,7 @@ pub(super) struct State {
126 tx_buf: RingBuffer, 129 tx_buf: RingBuffer,
127 tx_done: AtomicBool, 130 tx_done: AtomicBool,
128 tx_rx_refcount: AtomicU8, 131 tx_rx_refcount: AtomicU8,
132 half_duplex_readback: AtomicBool,
129} 133}
130 134
131impl State { 135impl State {
@@ -137,6 +141,7 @@ impl State {
137 tx_waker: AtomicWaker::new(), 141 tx_waker: AtomicWaker::new(),
138 tx_done: AtomicBool::new(true), 142 tx_done: AtomicBool::new(true),
139 tx_rx_refcount: AtomicU8::new(0), 143 tx_rx_refcount: AtomicU8::new(0),
144 half_duplex_readback: AtomicBool::new(false),
140 } 145 }
141 } 146 }
142} 147}
@@ -154,9 +159,10 @@ pub struct BufferedUartTx<'d> {
154 info: &'static Info, 159 info: &'static Info,
155 state: &'static State, 160 state: &'static State,
156 kernel_clock: Hertz, 161 kernel_clock: Hertz,
157 tx: Option<PeripheralRef<'d, AnyPin>>, 162 tx: Option<Peri<'d, AnyPin>>,
158 cts: Option<PeripheralRef<'d, AnyPin>>, 163 cts: Option<Peri<'d, AnyPin>>,
159 de: Option<PeripheralRef<'d, AnyPin>>, 164 de: Option<Peri<'d, AnyPin>>,
165 is_borrowed: bool,
160} 166}
161 167
162/// Rx-only buffered UART 168/// Rx-only buffered UART
@@ -166,8 +172,9 @@ pub struct BufferedUartRx<'d> {
166 info: &'static Info, 172 info: &'static Info,
167 state: &'static State, 173 state: &'static State,
168 kernel_clock: Hertz, 174 kernel_clock: Hertz,
169 rx: Option<PeripheralRef<'d, AnyPin>>, 175 rx: Option<Peri<'d, AnyPin>>,
170 rts: Option<PeripheralRef<'d, AnyPin>>, 176 rts: Option<Peri<'d, AnyPin>>,
177 is_borrowed: bool,
171} 178}
172 179
173impl<'d> SetConfig for BufferedUart<'d> { 180impl<'d> SetConfig for BufferedUart<'d> {
@@ -200,18 +207,18 @@ impl<'d> SetConfig for BufferedUartTx<'d> {
200impl<'d> BufferedUart<'d> { 207impl<'d> BufferedUart<'d> {
201 /// Create a new bidirectional buffered UART driver 208 /// Create a new bidirectional buffered UART driver
202 pub fn new<T: Instance>( 209 pub fn new<T: Instance>(
203 peri: impl Peripheral<P = T> + 'd, 210 peri: Peri<'d, T>,
204 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 211 rx: Peri<'d, impl RxPin<T>>,
205 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 212 tx: Peri<'d, impl TxPin<T>>,
206 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
207 tx_buffer: &'d mut [u8], 213 tx_buffer: &'d mut [u8],
208 rx_buffer: &'d mut [u8], 214 rx_buffer: &'d mut [u8],
215 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
209 config: Config, 216 config: Config,
210 ) -> Result<Self, ConfigError> { 217 ) -> Result<Self, ConfigError> {
211 Self::new_inner( 218 Self::new_inner(
212 peri, 219 peri,
213 new_pin!(rx, AfType::input(Pull::None)), 220 new_pin!(rx, config.rx_af()),
214 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 221 new_pin!(tx, config.tx_af()),
215 None, 222 None,
216 None, 223 None,
217 None, 224 None,
@@ -223,23 +230,71 @@ impl<'d> BufferedUart<'d> {
223 230
224 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins 231 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
225 pub fn new_with_rtscts<T: Instance>( 232 pub fn new_with_rtscts<T: Instance>(
226 peri: impl Peripheral<P = T> + 'd, 233 peri: Peri<'d, T>,
234 rx: Peri<'d, impl RxPin<T>>,
235 tx: Peri<'d, impl TxPin<T>>,
236 rts: Peri<'d, impl RtsPin<T>>,
237 cts: Peri<'d, impl CtsPin<T>>,
238 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
239 tx_buffer: &'d mut [u8],
240 rx_buffer: &'d mut [u8],
241 config: Config,
242 ) -> Result<Self, ConfigError> {
243 Self::new_inner(
244 peri,
245 new_pin!(rx, config.rx_af()),
246 new_pin!(tx, config.tx_af()),
247 new_pin!(rts, config.rts_config.af_type()),
248 new_pin!(cts, AfType::input(config.cts_pull)),
249 None,
250 tx_buffer,
251 rx_buffer,
252 config,
253 )
254 }
255
256 /// Create a new bidirectional buffered UART driver with only the RTS pin as the DE pin
257 pub fn new_with_rts_as_de<T: Instance>(
258 peri: Peri<'d, T>,
259 rx: Peri<'d, impl RxPin<T>>,
260 tx: Peri<'d, impl TxPin<T>>,
261 rts: Peri<'d, impl RtsPin<T>>,
227 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 262 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
228 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
229 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
230 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
231 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
232 tx_buffer: &'d mut [u8], 263 tx_buffer: &'d mut [u8],
233 rx_buffer: &'d mut [u8], 264 rx_buffer: &'d mut [u8],
234 config: Config, 265 config: Config,
235 ) -> Result<Self, ConfigError> { 266 ) -> Result<Self, ConfigError> {
236 Self::new_inner( 267 Self::new_inner(
237 peri, 268 peri,
238 new_pin!(rx, AfType::input(Pull::None)), 269 new_pin!(rx, config.rx_af()),
239 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 270 new_pin!(tx, config.tx_af()),
240 new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)),
241 new_pin!(cts, AfType::input(Pull::None)),
242 None, 271 None,
272 None,
273 new_pin!(rts, AfType::input(Pull::None)), // RTS mapped used as DE
274 tx_buffer,
275 rx_buffer,
276 config,
277 )
278 }
279
280 /// Create a new bidirectional buffered UART driver with only the request-to-send pin
281 pub fn new_with_rts<T: Instance>(
282 peri: Peri<'d, T>,
283 rx: Peri<'d, impl RxPin<T>>,
284 tx: Peri<'d, impl TxPin<T>>,
285 rts: Peri<'d, impl RtsPin<T>>,
286 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
287 tx_buffer: &'d mut [u8],
288 rx_buffer: &'d mut [u8],
289 config: Config,
290 ) -> Result<Self, ConfigError> {
291 Self::new_inner(
292 peri,
293 new_pin!(rx, config.rx_af()),
294 new_pin!(tx, config.tx_af()),
295 new_pin!(rts, AfType::input(Pull::None)),
296 None, // no CTS
297 None, // no DE
243 tx_buffer, 298 tx_buffer,
244 rx_buffer, 299 rx_buffer,
245 config, 300 config,
@@ -249,22 +304,98 @@ impl<'d> BufferedUart<'d> {
249 /// Create a new bidirectional buffered UART driver with a driver-enable pin 304 /// Create a new bidirectional buffered UART driver with a driver-enable pin
250 #[cfg(not(any(usart_v1, usart_v2)))] 305 #[cfg(not(any(usart_v1, usart_v2)))]
251 pub fn new_with_de<T: Instance>( 306 pub fn new_with_de<T: Instance>(
252 peri: impl Peripheral<P = T> + 'd, 307 peri: Peri<'d, T>,
308 rx: Peri<'d, impl RxPin<T>>,
309 tx: Peri<'d, impl TxPin<T>>,
310 de: Peri<'d, impl DePin<T>>,
253 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 311 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
254 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
255 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
256 de: impl Peripheral<P = impl DePin<T>> + 'd,
257 tx_buffer: &'d mut [u8], 312 tx_buffer: &'d mut [u8],
258 rx_buffer: &'d mut [u8], 313 rx_buffer: &'d mut [u8],
259 config: Config, 314 config: Config,
260 ) -> Result<Self, ConfigError> { 315 ) -> Result<Self, ConfigError> {
261 Self::new_inner( 316 Self::new_inner(
262 peri, 317 peri,
263 new_pin!(rx, AfType::input(Pull::None)), 318 new_pin!(rx, config.rx_af()),
264 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 319 new_pin!(tx, config.tx_af()),
320 None,
321 None,
322 new_pin!(de, config.de_config.af_type()),
323 tx_buffer,
324 rx_buffer,
325 config,
326 )
327 }
328
329 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
330 ///
331 /// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin
332 /// (when it is available for your chip). There is no functional difference between these methods, as both
333 /// allow bidirectional communication.
334 ///
335 /// The TX pin is always released when no data is transmitted. Thus, it acts as a standard
336 /// I/O in idle or in reception. It means that the I/O must be configured so that TX is
337 /// configured as alternate function open-drain with an external pull-up
338 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
339 /// on the line must be managed by software (for instance by using a centralized arbiter).
340 #[doc(alias("HDSEL"))]
341 pub fn new_half_duplex<T: Instance>(
342 peri: Peri<'d, T>,
343 tx: Peri<'d, impl TxPin<T>>,
344 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
345 tx_buffer: &'d mut [u8],
346 rx_buffer: &'d mut [u8],
347 mut config: Config,
348 readback: HalfDuplexReadback,
349 ) -> Result<Self, ConfigError> {
350 #[cfg(not(any(usart_v1, usart_v2)))]
351 {
352 config.swap_rx_tx = false;
353 }
354 config.duplex = Duplex::Half(readback);
355
356 Self::new_inner(
357 peri,
358 None,
359 new_pin!(tx, config.tx_af()),
360 None,
361 None,
362 None,
363 tx_buffer,
364 rx_buffer,
365 config,
366 )
367 }
368
369 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
370 ///
371 /// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin.
372 /// There is no functional difference between these methods, as both allow bidirectional communication.
373 ///
374 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
375 /// I/O in idle or in reception.
376 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
377 /// on the line must be managed by software (for instance by using a centralized arbiter).
378 #[cfg(not(any(usart_v1, usart_v2)))]
379 #[doc(alias("HDSEL"))]
380 pub fn new_half_duplex_on_rx<T: Instance>(
381 peri: Peri<'d, T>,
382 rx: Peri<'d, impl RxPin<T>>,
383 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
384 tx_buffer: &'d mut [u8],
385 rx_buffer: &'d mut [u8],
386 mut config: Config,
387 readback: HalfDuplexReadback,
388 ) -> Result<Self, ConfigError> {
389 config.swap_rx_tx = true;
390 config.duplex = Duplex::Half(readback);
391
392 Self::new_inner(
393 peri,
394 new_pin!(rx, config.rx_af()),
395 None,
396 None,
265 None, 397 None,
266 None, 398 None,
267 new_pin!(de, AfType::output(OutputType::PushPull, Speed::Medium)),
268 tx_buffer, 399 tx_buffer,
269 rx_buffer, 400 rx_buffer,
270 config, 401 config,
@@ -272,12 +403,12 @@ impl<'d> BufferedUart<'d> {
272 } 403 }
273 404
274 fn new_inner<T: Instance>( 405 fn new_inner<T: Instance>(
275 _peri: impl Peripheral<P = T> + 'd, 406 _peri: Peri<'d, T>,
276 rx: Option<PeripheralRef<'d, AnyPin>>, 407 rx: Option<Peri<'d, AnyPin>>,
277 tx: Option<PeripheralRef<'d, AnyPin>>, 408 tx: Option<Peri<'d, AnyPin>>,
278 rts: Option<PeripheralRef<'d, AnyPin>>, 409 rts: Option<Peri<'d, AnyPin>>,
279 cts: Option<PeripheralRef<'d, AnyPin>>, 410 cts: Option<Peri<'d, AnyPin>>,
280 de: Option<PeripheralRef<'d, AnyPin>>, 411 de: Option<Peri<'d, AnyPin>>,
281 tx_buffer: &'d mut [u8], 412 tx_buffer: &'d mut [u8],
282 rx_buffer: &'d mut [u8], 413 rx_buffer: &'d mut [u8],
283 config: Config, 414 config: Config,
@@ -286,6 +417,11 @@ impl<'d> BufferedUart<'d> {
286 let state = T::buffered_state(); 417 let state = T::buffered_state();
287 let kernel_clock = T::frequency(); 418 let kernel_clock = T::frequency();
288 419
420 state.half_duplex_readback.store(
421 config.duplex == Duplex::Half(HalfDuplexReadback::Readback),
422 Ordering::Relaxed,
423 );
424
289 let mut this = Self { 425 let mut this = Self {
290 rx: BufferedUartRx { 426 rx: BufferedUartRx {
291 info, 427 info,
@@ -293,6 +429,7 @@ impl<'d> BufferedUart<'d> {
293 kernel_clock, 429 kernel_clock,
294 rx, 430 rx,
295 rts, 431 rts,
432 is_borrowed: false,
296 }, 433 },
297 tx: BufferedUartTx { 434 tx: BufferedUartTx {
298 info, 435 info,
@@ -301,6 +438,7 @@ impl<'d> BufferedUart<'d> {
301 tx, 438 tx,
302 cts, 439 cts,
303 de, 440 de,
441 is_borrowed: false,
304 }, 442 },
305 }; 443 };
306 this.enable_and_configure(tx_buffer, rx_buffer, &config)?; 444 this.enable_and_configure(tx_buffer, rx_buffer, &config)?;
@@ -319,8 +457,10 @@ impl<'d> BufferedUart<'d> {
319 457
320 info.rcc.enable_and_reset(); 458 info.rcc.enable_and_reset();
321 459
460 assert!(!tx_buffer.is_empty());
322 let len = tx_buffer.len(); 461 let len = tx_buffer.len();
323 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 462 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
463 assert!(!rx_buffer.is_empty());
324 let len = rx_buffer.len(); 464 let len = rx_buffer.len();
325 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; 465 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
326 466
@@ -329,12 +469,20 @@ impl<'d> BufferedUart<'d> {
329 w.set_ctse(self.tx.cts.is_some()); 469 w.set_ctse(self.tx.cts.is_some());
330 #[cfg(not(any(usart_v1, usart_v2)))] 470 #[cfg(not(any(usart_v1, usart_v2)))]
331 w.set_dem(self.tx.de.is_some()); 471 w.set_dem(self.tx.de.is_some());
472 w.set_hdsel(config.duplex.is_half());
332 }); 473 });
333 configure(info, self.rx.kernel_clock, &config, true, true)?; 474 configure(info, self.rx.kernel_clock, &config, true, true)?;
334 475
335 info.regs.cr1().modify(|w| { 476 info.regs.cr1().modify(|w| {
336 w.set_rxneie(true); 477 w.set_rxneie(true);
337 w.set_idleie(true); 478 w.set_idleie(true);
479
480 if config.duplex.is_half() {
481 // The te and re bits will be set by write, read and flush methods.
482 // Receiver should be enabled by default for Half-Duplex.
483 w.set_te(false);
484 w.set_re(true);
485 }
338 }); 486 });
339 487
340 info.interrupt.unpend(); 488 info.interrupt.unpend();
@@ -348,6 +496,31 @@ impl<'d> BufferedUart<'d> {
348 (self.tx, self.rx) 496 (self.tx, self.rx)
349 } 497 }
350 498
499 /// Split the Uart into a transmitter and receiver,
500 /// which is particularly useful when having two tasks correlating to
501 /// transmitting and receiving.
502 pub fn split_ref(&mut self) -> (BufferedUartTx<'_>, BufferedUartRx<'_>) {
503 (
504 BufferedUartTx {
505 info: self.tx.info,
506 state: self.tx.state,
507 kernel_clock: self.tx.kernel_clock,
508 tx: self.tx.tx.as_mut().map(Peri::reborrow),
509 cts: self.tx.cts.as_mut().map(Peri::reborrow),
510 de: self.tx.de.as_mut().map(Peri::reborrow),
511 is_borrowed: true,
512 },
513 BufferedUartRx {
514 info: self.rx.info,
515 state: self.rx.state,
516 kernel_clock: self.rx.kernel_clock,
517 rx: self.rx.rx.as_mut().map(Peri::reborrow),
518 rts: self.rx.rts.as_mut().map(Peri::reborrow),
519 is_borrowed: true,
520 },
521 )
522 }
523
351 /// Reconfigure the driver 524 /// Reconfigure the driver
352 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 525 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
353 reconfigure(self.rx.info, self.rx.kernel_clock, config)?; 526 reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
@@ -359,6 +532,18 @@ impl<'d> BufferedUart<'d> {
359 532
360 Ok(()) 533 Ok(())
361 } 534 }
535
536 /// Send break character
537 pub fn send_break(&self) {
538 self.tx.send_break()
539 }
540
541 /// Set baudrate
542 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
543 self.tx.set_baudrate(baudrate)?;
544 self.rx.set_baudrate(baudrate)?;
545 Ok(())
546 }
362} 547}
363 548
364impl<'d> BufferedUartRx<'d> { 549impl<'d> BufferedUartRx<'d> {
@@ -453,6 +638,11 @@ impl<'d> BufferedUartRx<'d> {
453 638
454 Ok(()) 639 Ok(())
455 } 640 }
641
642 /// Set baudrate
643 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
644 set_baudrate(self.info, self.kernel_clock, baudrate)
645 }
456} 646}
457 647
458impl<'d> BufferedUartTx<'d> { 648impl<'d> BufferedUartTx<'d> {
@@ -538,44 +728,58 @@ impl<'d> BufferedUartTx<'d> {
538 728
539 Ok(()) 729 Ok(())
540 } 730 }
731
732 /// Send break character
733 pub fn send_break(&self) {
734 send_break(&self.info.regs);
735 }
736
737 /// Set baudrate
738 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
739 set_baudrate(self.info, self.kernel_clock, baudrate)
740 }
541} 741}
542 742
543impl<'d> Drop for BufferedUartRx<'d> { 743impl<'d> Drop for BufferedUartRx<'d> {
544 fn drop(&mut self) { 744 fn drop(&mut self) {
545 let state = self.state; 745 if !self.is_borrowed {
546 unsafe { 746 let state = self.state;
547 state.rx_buf.deinit(); 747 unsafe {
748 state.rx_buf.deinit();
548 749
549 // TX is inactive if the the buffer is not available. 750 // TX is inactive if the buffer is not available.
550 // We can now unregister the interrupt handler 751 // We can now unregister the interrupt handler
551 if state.tx_buf.len() == 0 { 752 if state.tx_buf.len() == 0 {
552 self.info.interrupt.disable(); 753 self.info.interrupt.disable();
754 }
553 } 755 }
554 }
555 756
556 self.rx.as_ref().map(|x| x.set_as_disconnected()); 757 self.rx.as_ref().map(|x| x.set_as_disconnected());
557 self.rts.as_ref().map(|x| x.set_as_disconnected()); 758 self.rts.as_ref().map(|x| x.set_as_disconnected());
558 drop_tx_rx(self.info, state); 759 drop_tx_rx(self.info, state);
760 }
559 } 761 }
560} 762}
561 763
562impl<'d> Drop for BufferedUartTx<'d> { 764impl<'d> Drop for BufferedUartTx<'d> {
563 fn drop(&mut self) { 765 fn drop(&mut self) {
564 let state = self.state; 766 if !self.is_borrowed {
565 unsafe { 767 let state = self.state;
566 state.tx_buf.deinit(); 768 unsafe {
769 state.tx_buf.deinit();
567 770
568 // RX is inactive if the the buffer is not available. 771 // RX is inactive if the buffer is not available.
569 // We can now unregister the interrupt handler 772 // We can now unregister the interrupt handler
570 if state.rx_buf.len() == 0 { 773 if state.rx_buf.len() == 0 {
571 self.info.interrupt.disable(); 774 self.info.interrupt.disable();
775 }
572 } 776 }
573 }
574 777
575 self.tx.as_ref().map(|x| x.set_as_disconnected()); 778 self.tx.as_ref().map(|x| x.set_as_disconnected());
576 self.cts.as_ref().map(|x| x.set_as_disconnected()); 779 self.cts.as_ref().map(|x| x.set_as_disconnected());
577 self.de.as_ref().map(|x| x.set_as_disconnected()); 780 self.de.as_ref().map(|x| x.set_as_disconnected());
578 drop_tx_rx(self.info, state); 781 drop_tx_rx(self.info, state);
782 }
579 } 783 }
580} 784}
581 785
@@ -704,26 +908,17 @@ impl<'d> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d> {
704 type Error = Error; 908 type Error = Error;
705 909
706 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 910 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
707 let r = self.info.regs; 911 let state = self.state;
708 unsafe { 912 let mut rx_reader = unsafe { state.rx_buf.reader() };
709 let sr = sr(r).read(); 913
710 if sr.pe() { 914 let do_pend = state.rx_buf.is_full();
711 rdr(r).read_volatile(); 915 if let Some(data) = rx_reader.pop_one() {
712 Err(nb::Error::Other(Error::Parity)) 916 if do_pend {
713 } else if sr.fe() { 917 self.info.interrupt.pend();
714 rdr(r).read_volatile();
715 Err(nb::Error::Other(Error::Framing))
716 } else if sr.ne() {
717 rdr(r).read_volatile();
718 Err(nb::Error::Other(Error::Noise))
719 } else if sr.ore() {
720 rdr(r).read_volatile();
721 Err(nb::Error::Other(Error::Overrun))
722 } else if sr.rxne() {
723 Ok(rdr(r).read_volatile())
724 } else {
725 Err(nb::Error::WouldBlock)
726 } 918 }
919 Ok(data)
920 } else {
921 Err(nb::Error::WouldBlock)
727 } 922 }
728 } 923 }
729} 924}
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 7ed3793a1..b3f8bc00c 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -9,7 +9,7 @@ use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_hal_internal::drop::OnDrop; 11use embassy_hal_internal::drop::OnDrop;
12use embassy_hal_internal::PeripheralRef; 12use embassy_hal_internal::PeripheralType;
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14use futures_util::future::{select, Either}; 14use futures_util::future::{select, Either};
15 15
@@ -18,11 +18,6 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
18use crate::interrupt::typelevel::Interrupt as _; 18use crate::interrupt::typelevel::Interrupt as _;
19use crate::interrupt::{self, Interrupt, InterruptExt}; 19use crate::interrupt::{self, Interrupt, InterruptExt};
20use crate::mode::{Async, Blocking, Mode}; 20use crate::mode::{Async, Blocking, Mode};
21#[allow(unused_imports)]
22#[cfg(not(any(usart_v1, usart_v2)))]
23use crate::pac::usart::regs::Isr as Sr;
24#[cfg(any(usart_v1, usart_v2))]
25use crate::pac::usart::regs::Sr;
26#[cfg(not(any(usart_v1, usart_v2)))] 21#[cfg(not(any(usart_v1, usart_v2)))]
27use crate::pac::usart::Lpuart as Regs; 22use crate::pac::usart::Lpuart as Regs;
28#[cfg(any(usart_v1, usart_v2))] 23#[cfg(any(usart_v1, usart_v2))]
@@ -30,7 +25,7 @@ use crate::pac::usart::Usart as Regs;
30use crate::pac::usart::{regs, vals}; 25use crate::pac::usart::{regs, vals};
31use crate::rcc::{RccInfo, SealedRccPeripheral}; 26use crate::rcc::{RccInfo, SealedRccPeripheral};
32use crate::time::Hertz; 27use crate::time::Hertz;
33use crate::Peripheral; 28use crate::Peri;
34 29
35/// Interrupt handler. 30/// Interrupt handler.
36pub struct InterruptHandler<T: Instance> { 31pub struct InterruptHandler<T: Instance> {
@@ -69,6 +64,12 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) {
69 // disable idle line detection 64 // disable idle line detection
70 w.set_idleie(false); 65 w.set_idleie(false);
71 }); 66 });
67 } else if cr1.tcie() && sr.tc() {
68 // Transmission complete detected
69 r.cr1().modify(|w| {
70 // disable Transmission complete interrupt
71 w.set_tcie(false);
72 });
72 } else if cr1.rxneie() { 73 } else if cr1.rxneie() {
73 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller 74 // We cannot check the RXNE flag as it is auto-cleared by the DMA controller
74 75
@@ -79,12 +80,15 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) {
79 80
80 compiler_fence(Ordering::SeqCst); 81 compiler_fence(Ordering::SeqCst);
81 s.rx_waker.wake(); 82 s.rx_waker.wake();
83 s.tx_waker.wake();
82} 84}
83 85
84#[derive(Clone, Copy, PartialEq, Eq, Debug)] 86#[derive(Clone, Copy, PartialEq, Eq, Debug)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))] 87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86/// Number of data bits 88/// Number of data bits
87pub enum DataBits { 89pub enum DataBits {
90 /// 7 Data Bits
91 DataBits7,
88 /// 8 Data Bits 92 /// 8 Data Bits
89 DataBits8, 93 DataBits8,
90 /// 9 Data Bits 94 /// 9 Data Bits
@@ -117,6 +121,57 @@ pub enum StopBits {
117 STOP1P5, 121 STOP1P5,
118} 122}
119 123
124#[derive(Clone, Copy, PartialEq, Eq, Debug)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126/// Enables or disables receiver so written data are read back in half-duplex mode
127pub enum HalfDuplexReadback {
128 /// Disables receiver so written data are not read back
129 NoReadback,
130 /// Enables receiver so written data are read back
131 Readback,
132}
133
134#[derive(Clone, Copy, PartialEq, Eq, Debug)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136/// Half duplex IO mode
137pub enum OutputConfig {
138 /// Push pull allows for faster baudrates, no internal pullup
139 PushPull,
140 /// Open drain output (external pull up needed)
141 OpenDrain,
142 #[cfg(not(gpio_v1))]
143 /// Open drain output with internal pull up resistor
144 OpenDrainPullUp,
145}
146
147impl OutputConfig {
148 const fn af_type(self) -> AfType {
149 match self {
150 OutputConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium),
151 OutputConfig::OpenDrain => AfType::output(OutputType::OpenDrain, Speed::Medium),
152 #[cfg(not(gpio_v1))]
153 OutputConfig::OpenDrainPullUp => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up),
154 }
155 }
156}
157
158#[derive(Clone, Copy, PartialEq, Eq, Debug)]
159#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160/// Duplex mode
161pub enum Duplex {
162 /// Full duplex
163 Full,
164 /// Half duplex with possibility to read back written data
165 Half(HalfDuplexReadback),
166}
167
168impl Duplex {
169 /// Returns true if half-duplex
170 fn is_half(&self) -> bool {
171 matches!(self, Duplex::Half(_))
172 }
173}
174
120#[non_exhaustive] 175#[non_exhaustive]
121#[derive(Clone, Copy, PartialEq, Eq, Debug)] 176#[derive(Clone, Copy, PartialEq, Eq, Debug)]
122#[cfg_attr(feature = "defmt", derive(defmt::Format))] 177#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -128,6 +183,8 @@ pub enum ConfigError {
128 BaudrateTooHigh, 183 BaudrateTooHigh,
129 /// Rx or Tx not enabled 184 /// Rx or Tx not enabled
130 RxOrTxNotEnabled, 185 RxOrTxNotEnabled,
186 /// Data bits and parity combination not supported
187 DataParityNotSupported,
131} 188}
132 189
133#[non_exhaustive] 190#[non_exhaustive]
@@ -167,25 +224,40 @@ pub struct Config {
167 #[cfg(any(usart_v3, usart_v4))] 224 #[cfg(any(usart_v3, usart_v4))]
168 pub invert_rx: bool, 225 pub invert_rx: bool,
169 226
227 /// Set the pull configuration for the RX pin.
228 pub rx_pull: Pull,
229
230 /// Set the pull configuration for the CTS pin.
231 pub cts_pull: Pull,
232
233 /// Set the pin configuration for the TX pin.
234 pub tx_config: OutputConfig,
235
236 /// Set the pin configuration for the RTS pin.
237 pub rts_config: OutputConfig,
238
239 /// Set the pin configuration for the DE pin.
240 pub de_config: OutputConfig,
241
170 // private: set by new_half_duplex, not by the user. 242 // private: set by new_half_duplex, not by the user.
171 half_duplex: bool, 243 duplex: Duplex,
172} 244}
173 245
174impl Config { 246impl Config {
175 fn tx_af(&self) -> AfType { 247 fn tx_af(&self) -> AfType {
176 #[cfg(any(usart_v3, usart_v4))] 248 #[cfg(any(usart_v3, usart_v4))]
177 if self.swap_rx_tx { 249 if self.swap_rx_tx {
178 return AfType::input(Pull::None); 250 return AfType::input(self.rx_pull);
179 }; 251 };
180 AfType::output(OutputType::PushPull, Speed::Medium) 252 self.tx_config.af_type()
181 } 253 }
182 254
183 fn rx_af(&self) -> AfType { 255 fn rx_af(&self) -> AfType {
184 #[cfg(any(usart_v3, usart_v4))] 256 #[cfg(any(usart_v3, usart_v4))]
185 if self.swap_rx_tx { 257 if self.swap_rx_tx {
186 return AfType::output(OutputType::PushPull, Speed::Medium); 258 return self.tx_config.af_type();
187 }; 259 };
188 AfType::input(Pull::None) 260 AfType::input(self.rx_pull)
189 } 261 }
190} 262}
191 263
@@ -206,7 +278,12 @@ impl Default for Config {
206 invert_tx: false, 278 invert_tx: false,
207 #[cfg(any(usart_v3, usart_v4))] 279 #[cfg(any(usart_v3, usart_v4))]
208 invert_rx: false, 280 invert_rx: false,
209 half_duplex: false, 281 rx_pull: Pull::None,
282 cts_pull: Pull::None,
283 tx_config: OutputConfig::PushPull,
284 rts_config: OutputConfig::PushPull,
285 de_config: OutputConfig::PushPull,
286 duplex: Duplex::Full,
210 } 287 }
211 } 288 }
212} 289}
@@ -228,6 +305,22 @@ pub enum Error {
228 BufferTooLong, 305 BufferTooLong,
229} 306}
230 307
308impl core::fmt::Display for Error {
309 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
310 let message = match self {
311 Self::Framing => "Framing Error",
312 Self::Noise => "Noise Error",
313 Self::Overrun => "RX Buffer Overrun",
314 Self::Parity => "Parity Check Error",
315 Self::BufferTooLong => "Buffer too large for DMA",
316 };
317
318 write!(f, "{}", message)
319 }
320}
321
322impl core::error::Error for Error {}
323
231enum ReadCompletionEvent { 324enum ReadCompletionEvent {
232 // DMA Read transfer completed first 325 // DMA Read transfer completed first
233 DmaCompleted, 326 DmaCompleted,
@@ -266,10 +359,11 @@ pub struct UartTx<'d, M: Mode> {
266 info: &'static Info, 359 info: &'static Info,
267 state: &'static State, 360 state: &'static State,
268 kernel_clock: Hertz, 361 kernel_clock: Hertz,
269 tx: Option<PeripheralRef<'d, AnyPin>>, 362 tx: Option<Peri<'d, AnyPin>>,
270 cts: Option<PeripheralRef<'d, AnyPin>>, 363 cts: Option<Peri<'d, AnyPin>>,
271 de: Option<PeripheralRef<'d, AnyPin>>, 364 de: Option<Peri<'d, AnyPin>>,
272 tx_dma: Option<ChannelAndRequest<'d>>, 365 tx_dma: Option<ChannelAndRequest<'d>>,
366 duplex: Duplex,
273 _phantom: PhantomData<M>, 367 _phantom: PhantomData<M>,
274} 368}
275 369
@@ -315,12 +409,12 @@ pub struct UartRx<'d, M: Mode> {
315 info: &'static Info, 409 info: &'static Info,
316 state: &'static State, 410 state: &'static State,
317 kernel_clock: Hertz, 411 kernel_clock: Hertz,
318 rx: Option<PeripheralRef<'d, AnyPin>>, 412 rx: Option<Peri<'d, AnyPin>>,
319 rts: Option<PeripheralRef<'d, AnyPin>>, 413 rts: Option<Peri<'d, AnyPin>>,
320 rx_dma: Option<ChannelAndRequest<'d>>, 414 rx_dma: Option<ChannelAndRequest<'d>>,
321 detect_previous_overrun: bool, 415 detect_previous_overrun: bool,
322 #[cfg(any(usart_v1, usart_v2))] 416 #[cfg(any(usart_v1, usart_v2))]
323 buffered_sr: stm32_metapac::usart::regs::Sr, 417 buffered_sr: regs::Sr,
324 _phantom: PhantomData<M>, 418 _phantom: PhantomData<M>,
325} 419}
326 420
@@ -336,32 +430,26 @@ impl<'d, M: Mode> SetConfig for UartRx<'d, M> {
336impl<'d> UartTx<'d, Async> { 430impl<'d> UartTx<'d, Async> {
337 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. 431 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
338 pub fn new<T: Instance>( 432 pub fn new<T: Instance>(
339 peri: impl Peripheral<P = T> + 'd, 433 peri: Peri<'d, T>,
340 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 434 tx: Peri<'d, impl TxPin<T>>,
341 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 435 tx_dma: Peri<'d, impl TxDma<T>>,
342 config: Config, 436 config: Config,
343 ) -> Result<Self, ConfigError> { 437 ) -> Result<Self, ConfigError> {
344 Self::new_inner( 438 Self::new_inner(peri, new_pin!(tx, config.tx_af()), None, new_dma!(tx_dma), config)
345 peri,
346 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)),
347 None,
348 new_dma!(tx_dma),
349 config,
350 )
351 } 439 }
352 440
353 /// Create a new tx-only UART with a clear-to-send pin 441 /// Create a new tx-only UART with a clear-to-send pin
354 pub fn new_with_cts<T: Instance>( 442 pub fn new_with_cts<T: Instance>(
355 peri: impl Peripheral<P = T> + 'd, 443 peri: Peri<'d, T>,
356 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 444 tx: Peri<'d, impl TxPin<T>>,
357 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 445 cts: Peri<'d, impl CtsPin<T>>,
358 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 446 tx_dma: Peri<'d, impl TxDma<T>>,
359 config: Config, 447 config: Config,
360 ) -> Result<Self, ConfigError> { 448 ) -> Result<Self, ConfigError> {
361 Self::new_inner( 449 Self::new_inner(
362 peri, 450 peri,
363 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 451 new_pin!(tx, config.tx_af()),
364 new_pin!(cts, AfType::input(Pull::None)), 452 new_pin!(cts, AfType::input(config.cts_pull)),
365 new_dma!(tx_dma), 453 new_dma!(tx_dma),
366 config, 454 config,
367 ) 455 )
@@ -371,13 +459,7 @@ impl<'d> UartTx<'d, Async> {
371 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 459 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
372 let r = self.info.regs; 460 let r = self.info.regs;
373 461
374 // Enable Transmitter and disable Receiver for Half-Duplex mode 462 half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback));
375 let mut cr1 = r.cr1().read();
376 if r.cr3().read().hdsel() && !cr1.te() {
377 cr1.set_te(true);
378 cr1.set_re(false);
379 r.cr1().write_value(cr1);
380 }
381 463
382 let ch = self.tx_dma.as_mut().unwrap(); 464 let ch = self.tx_dma.as_mut().unwrap();
383 r.cr3().modify(|reg| { 465 r.cr3().modify(|reg| {
@@ -392,7 +474,7 @@ impl<'d> UartTx<'d, Async> {
392 474
393 /// Wait until transmission complete 475 /// Wait until transmission complete
394 pub async fn flush(&mut self) -> Result<(), Error> { 476 pub async fn flush(&mut self) -> Result<(), Error> {
395 self.blocking_flush() 477 flush(&self.info, &self.state).await
396 } 478 }
397} 479}
398 480
@@ -401,30 +483,24 @@ impl<'d> UartTx<'d, Blocking> {
401 /// 483 ///
402 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. 484 /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
403 pub fn new_blocking<T: Instance>( 485 pub fn new_blocking<T: Instance>(
404 peri: impl Peripheral<P = T> + 'd, 486 peri: Peri<'d, T>,
405 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 487 tx: Peri<'d, impl TxPin<T>>,
406 config: Config, 488 config: Config,
407 ) -> Result<Self, ConfigError> { 489 ) -> Result<Self, ConfigError> {
408 Self::new_inner( 490 Self::new_inner(peri, new_pin!(tx, config.tx_af()), None, None, config)
409 peri,
410 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)),
411 None,
412 None,
413 config,
414 )
415 } 491 }
416 492
417 /// Create a new blocking tx-only UART with a clear-to-send pin 493 /// Create a new blocking tx-only UART with a clear-to-send pin
418 pub fn new_blocking_with_cts<T: Instance>( 494 pub fn new_blocking_with_cts<T: Instance>(
419 peri: impl Peripheral<P = T> + 'd, 495 peri: Peri<'d, T>,
420 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 496 tx: Peri<'d, impl TxPin<T>>,
421 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 497 cts: Peri<'d, impl CtsPin<T>>,
422 config: Config, 498 config: Config,
423 ) -> Result<Self, ConfigError> { 499 ) -> Result<Self, ConfigError> {
424 Self::new_inner( 500 Self::new_inner(
425 peri, 501 peri,
426 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 502 new_pin!(tx, config.tx_af()),
427 new_pin!(cts, AfType::input(Pull::None)), 503 new_pin!(cts, AfType::input(config.cts_pull)),
428 None, 504 None,
429 config, 505 config,
430 ) 506 )
@@ -433,9 +509,9 @@ impl<'d> UartTx<'d, Blocking> {
433 509
434impl<'d, M: Mode> UartTx<'d, M> { 510impl<'d, M: Mode> UartTx<'d, M> {
435 fn new_inner<T: Instance>( 511 fn new_inner<T: Instance>(
436 _peri: impl Peripheral<P = T> + 'd, 512 _peri: Peri<'d, T>,
437 tx: Option<PeripheralRef<'d, AnyPin>>, 513 tx: Option<Peri<'d, AnyPin>>,
438 cts: Option<PeripheralRef<'d, AnyPin>>, 514 cts: Option<Peri<'d, AnyPin>>,
439 tx_dma: Option<ChannelAndRequest<'d>>, 515 tx_dma: Option<ChannelAndRequest<'d>>,
440 config: Config, 516 config: Config,
441 ) -> Result<Self, ConfigError> { 517 ) -> Result<Self, ConfigError> {
@@ -447,6 +523,7 @@ impl<'d, M: Mode> UartTx<'d, M> {
447 cts, 523 cts,
448 de: None, 524 de: None,
449 tx_dma, 525 tx_dma,
526 duplex: config.duplex,
450 _phantom: PhantomData, 527 _phantom: PhantomData,
451 }; 528 };
452 this.enable_and_configure(&config)?; 529 this.enable_and_configure(&config)?;
@@ -477,13 +554,7 @@ impl<'d, M: Mode> UartTx<'d, M> {
477 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 554 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
478 let r = self.info.regs; 555 let r = self.info.regs;
479 556
480 // Enable Transmitter and disable Receiver for Half-Duplex mode 557 half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback));
481 let mut cr1 = r.cr1().read();
482 if r.cr3().read().hdsel() && !cr1.te() {
483 cr1.set_te(true);
484 cr1.set_re(false);
485 r.cr1().write_value(cr1);
486 }
487 558
488 for &b in buffer { 559 for &b in buffer {
489 while !sr(r).read().txe() {} 560 while !sr(r).read().txe() {}
@@ -496,53 +567,110 @@ impl<'d, M: Mode> UartTx<'d, M> {
496 pub fn blocking_flush(&mut self) -> Result<(), Error> { 567 pub fn blocking_flush(&mut self) -> Result<(), Error> {
497 blocking_flush(self.info) 568 blocking_flush(self.info)
498 } 569 }
570
571 /// Send break character
572 pub fn send_break(&self) {
573 send_break(&self.info.regs);
574 }
575
576 /// Set baudrate
577 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
578 set_baudrate(self.info, self.kernel_clock, baudrate)
579 }
499} 580}
500 581
501fn blocking_flush(info: &Info) -> Result<(), Error> { 582/// Wait until transmission complete
583async fn flush(info: &Info, state: &State) -> Result<(), Error> {
502 let r = info.regs; 584 let r = info.regs;
503 while !sr(r).read().tc() {} 585 if r.cr1().read().te() && !sr(r).read().tc() {
586 r.cr1().modify(|w| {
587 // enable Transmission Complete interrupt
588 w.set_tcie(true);
589 });
590
591 compiler_fence(Ordering::SeqCst);
592
593 // future which completes when Transmission complete is detected
594 let abort = poll_fn(move |cx| {
595 state.tx_waker.register(cx.waker());
504 596
505 // Enable Receiver after transmission complete for Half-Duplex mode 597 let sr = sr(r).read();
506 if r.cr3().read().hdsel() { 598 if sr.tc() {
507 r.cr1().modify(|reg| reg.set_re(true)); 599 // Transmission complete detected
600 return Poll::Ready(());
601 }
602
603 Poll::Pending
604 });
605
606 abort.await;
508 } 607 }
509 608
510 Ok(()) 609 Ok(())
511} 610}
512 611
612fn blocking_flush(info: &Info) -> Result<(), Error> {
613 let r = info.regs;
614 if r.cr1().read().te() {
615 while !sr(r).read().tc() {}
616 }
617
618 Ok(())
619}
620
621/// Send break character
622pub fn send_break(regs: &Regs) {
623 // Busy wait until previous break has been sent
624 #[cfg(any(usart_v1, usart_v2))]
625 while regs.cr1().read().sbk() {}
626 #[cfg(any(usart_v3, usart_v4))]
627 while regs.isr().read().sbkf() {}
628
629 // Send break right after completing the current character transmission
630 #[cfg(any(usart_v1, usart_v2))]
631 regs.cr1().modify(|w| w.set_sbk(true));
632 #[cfg(any(usart_v3, usart_v4))]
633 regs.rqr().write(|w| w.set_sbkrq(true));
634}
635
636/// Enable Transmitter and disable Receiver for Half-Duplex mode
637/// In case of readback, keep Receiver enabled
638fn half_duplex_set_rx_tx_before_write(r: &Regs, enable_readback: bool) {
639 let mut cr1 = r.cr1().read();
640 if r.cr3().read().hdsel() && !cr1.te() {
641 cr1.set_te(true);
642 cr1.set_re(enable_readback);
643 r.cr1().write_value(cr1);
644 }
645}
646
513impl<'d> UartRx<'d, Async> { 647impl<'d> UartRx<'d, Async> {
514 /// Create a new rx-only UART with no hardware flow control. 648 /// Create a new rx-only UART with no hardware flow control.
515 /// 649 ///
516 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 650 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
517 pub fn new<T: Instance>( 651 pub fn new<T: Instance>(
518 peri: impl Peripheral<P = T> + 'd, 652 peri: Peri<'d, T>,
519 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 653 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
520 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 654 rx: Peri<'d, impl RxPin<T>>,
521 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 655 rx_dma: Peri<'d, impl RxDma<T>>,
522 config: Config, 656 config: Config,
523 ) -> Result<Self, ConfigError> { 657 ) -> Result<Self, ConfigError> {
524 Self::new_inner( 658 Self::new_inner(peri, new_pin!(rx, config.rx_af()), None, new_dma!(rx_dma), config)
525 peri,
526 new_pin!(rx, AfType::input(Pull::None)),
527 None,
528 new_dma!(rx_dma),
529 config,
530 )
531 } 659 }
532 660
533 /// Create a new rx-only UART with a request-to-send pin 661 /// Create a new rx-only UART with a request-to-send pin
534 pub fn new_with_rts<T: Instance>( 662 pub fn new_with_rts<T: Instance>(
535 peri: impl Peripheral<P = T> + 'd, 663 peri: Peri<'d, T>,
536 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 664 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
537 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 665 rx: Peri<'d, impl RxPin<T>>,
538 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 666 rts: Peri<'d, impl RtsPin<T>>,
539 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 667 rx_dma: Peri<'d, impl RxDma<T>>,
540 config: Config, 668 config: Config,
541 ) -> Result<Self, ConfigError> { 669 ) -> Result<Self, ConfigError> {
542 Self::new_inner( 670 Self::new_inner(
543 peri, 671 peri,
544 new_pin!(rx, AfType::input(Pull::None)), 672 new_pin!(rx, config.rx_af()),
545 new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), 673 new_pin!(rts, config.rts_config.af_type()),
546 new_dma!(rx_dma), 674 new_dma!(rx_dma),
547 config, 675 config,
548 ) 676 )
@@ -570,12 +698,17 @@ impl<'d> UartRx<'d, Async> {
570 // Call flush for Half-Duplex mode if some bytes were written and flush was not called. 698 // Call flush for Half-Duplex mode if some bytes were written and flush was not called.
571 // It prevents reading of bytes which have just been written. 699 // It prevents reading of bytes which have just been written.
572 if r.cr3().read().hdsel() && r.cr1().read().te() { 700 if r.cr3().read().hdsel() && r.cr1().read().te() {
573 blocking_flush(self.info)?; 701 flush(&self.info, &self.state).await?;
702
703 // Disable Transmitter and enable Receiver after flush
704 r.cr1().modify(|reg| {
705 reg.set_re(true);
706 reg.set_te(false);
707 });
574 } 708 }
575 709
576 // make sure USART state is restored to neutral state when this future is dropped 710 // make sure USART state is restored to neutral state when this future is dropped
577 let on_drop = OnDrop::new(move || { 711 let on_drop = OnDrop::new(move || {
578 // defmt::trace!("Clear all USART interrupts and DMA Read Request");
579 // clear all interrupts and DMA Rx Request 712 // clear all interrupts and DMA Rx Request
580 r.cr1().modify(|w| { 713 r.cr1().modify(|w| {
581 // disable RXNE interrupt 714 // disable RXNE interrupt
@@ -767,24 +900,24 @@ impl<'d> UartRx<'d, Blocking> {
767 /// 900 ///
768 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. 901 /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
769 pub fn new_blocking<T: Instance>( 902 pub fn new_blocking<T: Instance>(
770 peri: impl Peripheral<P = T> + 'd, 903 peri: Peri<'d, T>,
771 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 904 rx: Peri<'d, impl RxPin<T>>,
772 config: Config, 905 config: Config,
773 ) -> Result<Self, ConfigError> { 906 ) -> Result<Self, ConfigError> {
774 Self::new_inner(peri, new_pin!(rx, AfType::input(Pull::None)), None, None, config) 907 Self::new_inner(peri, new_pin!(rx, config.rx_af()), None, None, config)
775 } 908 }
776 909
777 /// Create a new rx-only UART with a request-to-send pin 910 /// Create a new rx-only UART with a request-to-send pin
778 pub fn new_blocking_with_rts<T: Instance>( 911 pub fn new_blocking_with_rts<T: Instance>(
779 peri: impl Peripheral<P = T> + 'd, 912 peri: Peri<'d, T>,
780 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 913 rx: Peri<'d, impl RxPin<T>>,
781 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 914 rts: Peri<'d, impl RtsPin<T>>,
782 config: Config, 915 config: Config,
783 ) -> Result<Self, ConfigError> { 916 ) -> Result<Self, ConfigError> {
784 Self::new_inner( 917 Self::new_inner(
785 peri, 918 peri,
786 new_pin!(rx, AfType::input(Pull::None)), 919 new_pin!(rx, config.rx_af()),
787 new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), 920 new_pin!(rts, config.rts_config.af_type()),
788 None, 921 None,
789 config, 922 config,
790 ) 923 )
@@ -793,9 +926,9 @@ impl<'d> UartRx<'d, Blocking> {
793 926
794impl<'d, M: Mode> UartRx<'d, M> { 927impl<'d, M: Mode> UartRx<'d, M> {
795 fn new_inner<T: Instance>( 928 fn new_inner<T: Instance>(
796 _peri: impl Peripheral<P = T> + 'd, 929 _peri: Peri<'d, T>,
797 rx: Option<PeripheralRef<'d, AnyPin>>, 930 rx: Option<Peri<'d, AnyPin>>,
798 rts: Option<PeripheralRef<'d, AnyPin>>, 931 rts: Option<Peri<'d, AnyPin>>,
799 rx_dma: Option<ChannelAndRequest<'d>>, 932 rx_dma: Option<ChannelAndRequest<'d>>,
800 config: Config, 933 config: Config,
801 ) -> Result<Self, ConfigError> { 934 ) -> Result<Self, ConfigError> {
@@ -809,7 +942,7 @@ impl<'d, M: Mode> UartRx<'d, M> {
809 rx_dma, 942 rx_dma,
810 detect_previous_overrun: config.detect_previous_overrun, 943 detect_previous_overrun: config.detect_previous_overrun,
811 #[cfg(any(usart_v1, usart_v2))] 944 #[cfg(any(usart_v1, usart_v2))]
812 buffered_sr: stm32_metapac::usart::regs::Sr(0), 945 buffered_sr: regs::Sr(0),
813 }; 946 };
814 this.enable_and_configure(&config)?; 947 this.enable_and_configure(&config)?;
815 Ok(this) 948 Ok(this)
@@ -909,6 +1042,12 @@ impl<'d, M: Mode> UartRx<'d, M> {
909 // It prevents reading of bytes which have just been written. 1042 // It prevents reading of bytes which have just been written.
910 if r.cr3().read().hdsel() && r.cr1().read().te() { 1043 if r.cr3().read().hdsel() && r.cr1().read().te() {
911 blocking_flush(self.info)?; 1044 blocking_flush(self.info)?;
1045
1046 // Disable Transmitter and enable Receiver after flush
1047 r.cr1().modify(|reg| {
1048 reg.set_re(true);
1049 reg.set_te(false);
1050 });
912 } 1051 }
913 1052
914 for b in buffer { 1053 for b in buffer {
@@ -917,6 +1056,11 @@ impl<'d, M: Mode> UartRx<'d, M> {
917 } 1056 }
918 Ok(()) 1057 Ok(())
919 } 1058 }
1059
1060 /// Set baudrate
1061 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
1062 set_baudrate(self.info, self.kernel_clock, baudrate)
1063 }
920} 1064}
921 1065
922impl<'d, M: Mode> Drop for UartTx<'d, M> { 1066impl<'d, M: Mode> Drop for UartTx<'d, M> {
@@ -952,12 +1096,12 @@ fn drop_tx_rx(info: &Info, state: &State) {
952impl<'d> Uart<'d, Async> { 1096impl<'d> Uart<'d, Async> {
953 /// Create a new bidirectional UART 1097 /// Create a new bidirectional UART
954 pub fn new<T: Instance>( 1098 pub fn new<T: Instance>(
955 peri: impl Peripheral<P = T> + 'd, 1099 peri: Peri<'d, T>,
956 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1100 rx: Peri<'d, impl RxPin<T>>,
957 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1101 tx: Peri<'d, impl TxPin<T>>,
958 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1102 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
959 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 1103 tx_dma: Peri<'d, impl TxDma<T>>,
960 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 1104 rx_dma: Peri<'d, impl RxDma<T>>,
961 config: Config, 1105 config: Config,
962 ) -> Result<Self, ConfigError> { 1106 ) -> Result<Self, ConfigError> {
963 Self::new_inner( 1107 Self::new_inner(
@@ -975,22 +1119,22 @@ impl<'d> Uart<'d, Async> {
975 1119
976 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 1120 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
977 pub fn new_with_rtscts<T: Instance>( 1121 pub fn new_with_rtscts<T: Instance>(
978 peri: impl Peripheral<P = T> + 'd, 1122 peri: Peri<'d, T>,
979 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1123 rx: Peri<'d, impl RxPin<T>>,
980 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1124 tx: Peri<'d, impl TxPin<T>>,
981 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1125 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
982 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 1126 rts: Peri<'d, impl RtsPin<T>>,
983 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 1127 cts: Peri<'d, impl CtsPin<T>>,
984 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 1128 tx_dma: Peri<'d, impl TxDma<T>>,
985 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 1129 rx_dma: Peri<'d, impl RxDma<T>>,
986 config: Config, 1130 config: Config,
987 ) -> Result<Self, ConfigError> { 1131 ) -> Result<Self, ConfigError> {
988 Self::new_inner( 1132 Self::new_inner(
989 peri, 1133 peri,
990 new_pin!(rx, config.rx_af()), 1134 new_pin!(rx, config.rx_af()),
991 new_pin!(tx, config.tx_af()), 1135 new_pin!(tx, config.tx_af()),
992 new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), 1136 new_pin!(rts, config.rts_config.af_type()),
993 new_pin!(cts, AfType::input(Pull::None)), 1137 new_pin!(cts, AfType::input(config.cts_pull)),
994 None, 1138 None,
995 new_dma!(tx_dma), 1139 new_dma!(tx_dma),
996 new_dma!(rx_dma), 1140 new_dma!(rx_dma),
@@ -1001,13 +1145,13 @@ impl<'d> Uart<'d, Async> {
1001 #[cfg(not(any(usart_v1, usart_v2)))] 1145 #[cfg(not(any(usart_v1, usart_v2)))]
1002 /// Create a new bidirectional UART with a driver-enable pin 1146 /// Create a new bidirectional UART with a driver-enable pin
1003 pub fn new_with_de<T: Instance>( 1147 pub fn new_with_de<T: Instance>(
1004 peri: impl Peripheral<P = T> + 'd, 1148 peri: Peri<'d, T>,
1005 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1149 rx: Peri<'d, impl RxPin<T>>,
1006 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1150 tx: Peri<'d, impl TxPin<T>>,
1007 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1151 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1008 de: impl Peripheral<P = impl DePin<T>> + 'd, 1152 de: Peri<'d, impl DePin<T>>,
1009 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 1153 tx_dma: Peri<'d, impl TxDma<T>>,
1010 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 1154 rx_dma: Peri<'d, impl RxDma<T>>,
1011 config: Config, 1155 config: Config,
1012 ) -> Result<Self, ConfigError> { 1156 ) -> Result<Self, ConfigError> {
1013 Self::new_inner( 1157 Self::new_inner(
@@ -1016,7 +1160,7 @@ impl<'d> Uart<'d, Async> {
1016 new_pin!(tx, config.tx_af()), 1160 new_pin!(tx, config.tx_af()),
1017 None, 1161 None,
1018 None, 1162 None,
1019 new_pin!(de, AfType::output(OutputType::PushPull, Speed::Medium)), 1163 new_pin!(de, config.de_config.af_type()),
1020 new_dma!(tx_dma), 1164 new_dma!(tx_dma),
1021 new_dma!(rx_dma), 1165 new_dma!(rx_dma),
1022 config, 1166 config,
@@ -1029,29 +1173,31 @@ impl<'d> Uart<'d, Async> {
1029 /// (when it is available for your chip). There is no functional difference between these methods, as both 1173 /// (when it is available for your chip). There is no functional difference between these methods, as both
1030 /// allow bidirectional communication. 1174 /// allow bidirectional communication.
1031 /// 1175 ///
1032 /// The pin is always released when no data is transmitted. Thus, it acts as a standard 1176 /// The TX pin is always released when no data is transmitted. Thus, it acts as a standard
1033 /// I/O in idle or in reception. 1177 /// I/O in idle or in reception. It means that the I/O must be configured so that TX is
1178 /// configured as alternate function open-drain with an external pull-up
1034 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 1179 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1035 /// on the line must be managed by software (for instance by using a centralized arbiter). 1180 /// on the line must be managed by software (for instance by using a centralized arbiter).
1036 #[doc(alias("HDSEL"))] 1181 #[doc(alias("HDSEL"))]
1037 pub fn new_half_duplex<T: Instance>( 1182 pub fn new_half_duplex<T: Instance>(
1038 peri: impl Peripheral<P = T> + 'd, 1183 peri: Peri<'d, T>,
1039 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1184 tx: Peri<'d, impl TxPin<T>>,
1040 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1185 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1041 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 1186 tx_dma: Peri<'d, impl TxDma<T>>,
1042 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 1187 rx_dma: Peri<'d, impl RxDma<T>>,
1043 mut config: Config, 1188 mut config: Config,
1189 readback: HalfDuplexReadback,
1044 ) -> Result<Self, ConfigError> { 1190 ) -> Result<Self, ConfigError> {
1045 #[cfg(not(any(usart_v1, usart_v2)))] 1191 #[cfg(not(any(usart_v1, usart_v2)))]
1046 { 1192 {
1047 config.swap_rx_tx = false; 1193 config.swap_rx_tx = false;
1048 } 1194 }
1049 config.half_duplex = true; 1195 config.duplex = Duplex::Half(readback);
1050 1196
1051 Self::new_inner( 1197 Self::new_inner(
1052 peri, 1198 peri,
1053 None, 1199 None,
1054 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 1200 new_pin!(tx, config.tx_af()),
1055 None, 1201 None,
1056 None, 1202 None,
1057 None, 1203 None,
@@ -1073,21 +1219,22 @@ impl<'d> Uart<'d, Async> {
1073 #[cfg(not(any(usart_v1, usart_v2)))] 1219 #[cfg(not(any(usart_v1, usart_v2)))]
1074 #[doc(alias("HDSEL"))] 1220 #[doc(alias("HDSEL"))]
1075 pub fn new_half_duplex_on_rx<T: Instance>( 1221 pub fn new_half_duplex_on_rx<T: Instance>(
1076 peri: impl Peripheral<P = T> + 'd, 1222 peri: Peri<'d, T>,
1077 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1223 rx: Peri<'d, impl RxPin<T>>,
1078 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1224 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1079 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 1225 tx_dma: Peri<'d, impl TxDma<T>>,
1080 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 1226 rx_dma: Peri<'d, impl RxDma<T>>,
1081 mut config: Config, 1227 mut config: Config,
1228 readback: HalfDuplexReadback,
1082 ) -> Result<Self, ConfigError> { 1229 ) -> Result<Self, ConfigError> {
1083 config.swap_rx_tx = true; 1230 config.swap_rx_tx = true;
1084 config.half_duplex = true; 1231 config.duplex = Duplex::Half(readback);
1085 1232
1086 Self::new_inner( 1233 Self::new_inner(
1087 peri, 1234 peri,
1088 None, 1235 None,
1089 None, 1236 None,
1090 new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), 1237 new_pin!(rx, config.rx_af()),
1091 None, 1238 None,
1092 None, 1239 None,
1093 new_dma!(tx_dma), 1240 new_dma!(tx_dma),
@@ -1101,6 +1248,11 @@ impl<'d> Uart<'d, Async> {
1101 self.tx.write(buffer).await 1248 self.tx.write(buffer).await
1102 } 1249 }
1103 1250
1251 /// Wait until transmission complete
1252 pub async fn flush(&mut self) -> Result<(), Error> {
1253 self.tx.flush().await
1254 }
1255
1104 /// Perform an asynchronous read into `buffer` 1256 /// Perform an asynchronous read into `buffer`
1105 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 1257 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
1106 self.rx.read(buffer).await 1258 self.rx.read(buffer).await
@@ -1115,9 +1267,9 @@ impl<'d> Uart<'d, Async> {
1115impl<'d> Uart<'d, Blocking> { 1267impl<'d> Uart<'d, Blocking> {
1116 /// Create a new blocking bidirectional UART. 1268 /// Create a new blocking bidirectional UART.
1117 pub fn new_blocking<T: Instance>( 1269 pub fn new_blocking<T: Instance>(
1118 peri: impl Peripheral<P = T> + 'd, 1270 peri: Peri<'d, T>,
1119 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1271 rx: Peri<'d, impl RxPin<T>>,
1120 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1272 tx: Peri<'d, impl TxPin<T>>,
1121 config: Config, 1273 config: Config,
1122 ) -> Result<Self, ConfigError> { 1274 ) -> Result<Self, ConfigError> {
1123 Self::new_inner( 1275 Self::new_inner(
@@ -1135,19 +1287,19 @@ impl<'d> Uart<'d, Blocking> {
1135 1287
1136 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 1288 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
1137 pub fn new_blocking_with_rtscts<T: Instance>( 1289 pub fn new_blocking_with_rtscts<T: Instance>(
1138 peri: impl Peripheral<P = T> + 'd, 1290 peri: Peri<'d, T>,
1139 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1291 rx: Peri<'d, impl RxPin<T>>,
1140 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1292 tx: Peri<'d, impl TxPin<T>>,
1141 rts: impl Peripheral<P = impl RtsPin<T>> + 'd, 1293 rts: Peri<'d, impl RtsPin<T>>,
1142 cts: impl Peripheral<P = impl CtsPin<T>> + 'd, 1294 cts: Peri<'d, impl CtsPin<T>>,
1143 config: Config, 1295 config: Config,
1144 ) -> Result<Self, ConfigError> { 1296 ) -> Result<Self, ConfigError> {
1145 Self::new_inner( 1297 Self::new_inner(
1146 peri, 1298 peri,
1147 new_pin!(rx, config.rx_af()), 1299 new_pin!(rx, config.rx_af()),
1148 new_pin!(tx, config.tx_af()), 1300 new_pin!(tx, config.tx_af()),
1149 new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), 1301 new_pin!(rts, config.rts_config.af_type()),
1150 new_pin!(cts, AfType::input(Pull::None)), 1302 new_pin!(cts, AfType::input(config.cts_pull)),
1151 None, 1303 None,
1152 None, 1304 None,
1153 None, 1305 None,
@@ -1158,10 +1310,10 @@ impl<'d> Uart<'d, Blocking> {
1158 #[cfg(not(any(usart_v1, usart_v2)))] 1310 #[cfg(not(any(usart_v1, usart_v2)))]
1159 /// Create a new bidirectional UART with a driver-enable pin 1311 /// Create a new bidirectional UART with a driver-enable pin
1160 pub fn new_blocking_with_de<T: Instance>( 1312 pub fn new_blocking_with_de<T: Instance>(
1161 peri: impl Peripheral<P = T> + 'd, 1313 peri: Peri<'d, T>,
1162 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1314 rx: Peri<'d, impl RxPin<T>>,
1163 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1315 tx: Peri<'d, impl TxPin<T>>,
1164 de: impl Peripheral<P = impl DePin<T>> + 'd, 1316 de: Peri<'d, impl DePin<T>>,
1165 config: Config, 1317 config: Config,
1166 ) -> Result<Self, ConfigError> { 1318 ) -> Result<Self, ConfigError> {
1167 Self::new_inner( 1319 Self::new_inner(
@@ -1170,7 +1322,7 @@ impl<'d> Uart<'d, Blocking> {
1170 new_pin!(tx, config.tx_af()), 1322 new_pin!(tx, config.tx_af()),
1171 None, 1323 None,
1172 None, 1324 None,
1173 new_pin!(de, AfType::output(OutputType::PushPull, Speed::Medium)), 1325 new_pin!(de, config.de_config.af_type()),
1174 None, 1326 None,
1175 None, 1327 None,
1176 config, 1328 config,
@@ -1189,20 +1341,21 @@ impl<'d> Uart<'d, Blocking> {
1189 /// on the line must be managed by software (for instance by using a centralized arbiter). 1341 /// on the line must be managed by software (for instance by using a centralized arbiter).
1190 #[doc(alias("HDSEL"))] 1342 #[doc(alias("HDSEL"))]
1191 pub fn new_blocking_half_duplex<T: Instance>( 1343 pub fn new_blocking_half_duplex<T: Instance>(
1192 peri: impl Peripheral<P = T> + 'd, 1344 peri: Peri<'d, T>,
1193 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1345 tx: Peri<'d, impl TxPin<T>>,
1194 mut config: Config, 1346 mut config: Config,
1347 readback: HalfDuplexReadback,
1195 ) -> Result<Self, ConfigError> { 1348 ) -> Result<Self, ConfigError> {
1196 #[cfg(not(any(usart_v1, usart_v2)))] 1349 #[cfg(not(any(usart_v1, usart_v2)))]
1197 { 1350 {
1198 config.swap_rx_tx = false; 1351 config.swap_rx_tx = false;
1199 } 1352 }
1200 config.half_duplex = true; 1353 config.duplex = Duplex::Half(readback);
1201 1354
1202 Self::new_inner( 1355 Self::new_inner(
1203 peri, 1356 peri,
1204 None, 1357 None,
1205 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 1358 new_pin!(tx, config.tx_af()),
1206 None, 1359 None,
1207 None, 1360 None,
1208 None, 1361 None,
@@ -1224,18 +1377,19 @@ impl<'d> Uart<'d, Blocking> {
1224 #[cfg(not(any(usart_v1, usart_v2)))] 1377 #[cfg(not(any(usart_v1, usart_v2)))]
1225 #[doc(alias("HDSEL"))] 1378 #[doc(alias("HDSEL"))]
1226 pub fn new_blocking_half_duplex_on_rx<T: Instance>( 1379 pub fn new_blocking_half_duplex_on_rx<T: Instance>(
1227 peri: impl Peripheral<P = T> + 'd, 1380 peri: Peri<'d, T>,
1228 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1381 rx: Peri<'d, impl RxPin<T>>,
1229 mut config: Config, 1382 mut config: Config,
1383 readback: HalfDuplexReadback,
1230 ) -> Result<Self, ConfigError> { 1384 ) -> Result<Self, ConfigError> {
1231 config.swap_rx_tx = true; 1385 config.swap_rx_tx = true;
1232 config.half_duplex = true; 1386 config.duplex = Duplex::Half(readback);
1233 1387
1234 Self::new_inner( 1388 Self::new_inner(
1235 peri, 1389 peri,
1236 None, 1390 None,
1237 None, 1391 None,
1238 new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), 1392 new_pin!(rx, config.rx_af()),
1239 None, 1393 None,
1240 None, 1394 None,
1241 None, 1395 None,
@@ -1247,12 +1401,12 @@ impl<'d> Uart<'d, Blocking> {
1247 1401
1248impl<'d, M: Mode> Uart<'d, M> { 1402impl<'d, M: Mode> Uart<'d, M> {
1249 fn new_inner<T: Instance>( 1403 fn new_inner<T: Instance>(
1250 _peri: impl Peripheral<P = T> + 'd, 1404 _peri: Peri<'d, T>,
1251 rx: Option<PeripheralRef<'d, AnyPin>>, 1405 rx: Option<Peri<'d, AnyPin>>,
1252 tx: Option<PeripheralRef<'d, AnyPin>>, 1406 tx: Option<Peri<'d, AnyPin>>,
1253 rts: Option<PeripheralRef<'d, AnyPin>>, 1407 rts: Option<Peri<'d, AnyPin>>,
1254 cts: Option<PeripheralRef<'d, AnyPin>>, 1408 cts: Option<Peri<'d, AnyPin>>,
1255 de: Option<PeripheralRef<'d, AnyPin>>, 1409 de: Option<Peri<'d, AnyPin>>,
1256 tx_dma: Option<ChannelAndRequest<'d>>, 1410 tx_dma: Option<ChannelAndRequest<'d>>,
1257 rx_dma: Option<ChannelAndRequest<'d>>, 1411 rx_dma: Option<ChannelAndRequest<'d>>,
1258 config: Config, 1412 config: Config,
@@ -1271,6 +1425,7 @@ impl<'d, M: Mode> Uart<'d, M> {
1271 cts, 1425 cts,
1272 de, 1426 de,
1273 tx_dma, 1427 tx_dma,
1428 duplex: config.duplex,
1274 }, 1429 },
1275 rx: UartRx { 1430 rx: UartRx {
1276 _phantom: PhantomData, 1431 _phantom: PhantomData,
@@ -1282,7 +1437,7 @@ impl<'d, M: Mode> Uart<'d, M> {
1282 rx_dma, 1437 rx_dma,
1283 detect_previous_overrun: config.detect_previous_overrun, 1438 detect_previous_overrun: config.detect_previous_overrun,
1284 #[cfg(any(usart_v1, usart_v2))] 1439 #[cfg(any(usart_v1, usart_v2))]
1285 buffered_sr: stm32_metapac::usart::regs::Sr(0), 1440 buffered_sr: regs::Sr(0),
1286 }, 1441 },
1287 }; 1442 };
1288 this.enable_and_configure(&config)?; 1443 this.enable_and_configure(&config)?;
@@ -1336,6 +1491,25 @@ impl<'d, M: Mode> Uart<'d, M> {
1336 pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) { 1491 pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
1337 (self.tx, self.rx) 1492 (self.tx, self.rx)
1338 } 1493 }
1494
1495 /// Split the Uart into a transmitter and receiver by mutable reference,
1496 /// which is particularly useful when having two tasks correlating to
1497 /// transmitting and receiving.
1498 pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) {
1499 (&mut self.tx, &mut self.rx)
1500 }
1501
1502 /// Send break character
1503 pub fn send_break(&self) {
1504 self.tx.send_break();
1505 }
1506
1507 /// Set baudrate
1508 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
1509 self.tx.set_baudrate(baudrate)?;
1510 self.rx.set_baudrate(baudrate)?;
1511 Ok(())
1512 }
1339} 1513}
1340 1514
1341fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { 1515fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
@@ -1351,20 +1525,33 @@ fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(),
1351 Ok(()) 1525 Ok(())
1352} 1526}
1353 1527
1354fn configure( 1528fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
1355 info: &Info, 1529 // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
1356 kernel_clock: Hertz, 1530 // To do this in 32-bit only we can't multiply `mul` and `pclk`
1357 config: &Config, 1531 let clock = pclk / presc;
1358 enable_rx: bool,
1359 enable_tx: bool,
1360) -> Result<(), ConfigError> {
1361 let r = info.regs;
1362 let kind = info.kind;
1363 1532
1364 if !enable_rx && !enable_tx { 1533 // The mul is applied as the last operation to prevent overflow
1365 return Err(ConfigError::RxOrTxNotEnabled); 1534 let brr = clock / baud * mul;
1366 } 1535
1536 // The BRR calculation will be a bit off because of integer rounding.
1537 // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
1538 let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
1539
1540 brr + rounding
1541}
1542
1543fn set_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
1544 info.interrupt.disable();
1367 1545
1546 set_usart_baudrate(info, kernel_clock, baudrate)?;
1547
1548 info.interrupt.unpend();
1549 unsafe { info.interrupt.enable() };
1550
1551 Ok(())
1552}
1553
1554fn find_and_set_brr(r: Regs, kind: Kind, kernel_clock: Hertz, baudrate: u32) -> Result<bool, ConfigError> {
1368 #[cfg(not(usart_v4))] 1555 #[cfg(not(usart_v4))]
1369 static DIVS: [(u16, ()); 1] = [(1, ())]; 1556 static DIVS: [(u16, ()); 1] = [(1, ())];
1370 1557
@@ -1396,31 +1583,14 @@ fn configure(
1396 } 1583 }
1397 }; 1584 };
1398 1585
1399 fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 { 1586 let mut found_brr = None;
1400 // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
1401 // To do this in 32-bit only we can't multiply `mul` and `pclk`
1402 let clock = pclk / presc;
1403
1404 // The mul is applied as the last operation to prevent overflow
1405 let brr = clock / baud * mul;
1406
1407 // The BRR calculation will be a bit off because of integer rounding.
1408 // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
1409 let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
1410
1411 brr + rounding
1412 }
1413
1414 // UART must be disabled during configuration.
1415 r.cr1().modify(|w| {
1416 w.set_ue(false);
1417 });
1418
1419 #[cfg(not(usart_v1))] 1587 #[cfg(not(usart_v1))]
1420 let mut over8 = false; 1588 let mut over8 = false;
1421 let mut found_brr = None; 1589 #[cfg(usart_v1)]
1590 let over8 = false;
1591
1422 for &(presc, _presc_val) in &DIVS { 1592 for &(presc, _presc_val) in &DIVS {
1423 let brr = calculate_brr(config.baudrate, kernel_clock.0, presc as u32, mul); 1593 let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul);
1424 trace!( 1594 trace!(
1425 "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", 1595 "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
1426 presc, 1596 presc,
@@ -1451,18 +1621,70 @@ fn configure(
1451 } 1621 }
1452 } 1622 }
1453 1623
1454 let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; 1624 match found_brr {
1625 Some(brr) => {
1626 #[cfg(not(usart_v1))]
1627 let oversampling = if over8 { "8 bit" } else { "16 bit" };
1628 #[cfg(usart_v1)]
1629 let oversampling = "default";
1630 trace!(
1631 "Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
1632 oversampling,
1633 baudrate,
1634 kernel_clock.0 / brr * mul
1635 );
1636 Ok(over8)
1637 }
1638 None => Err(ConfigError::BaudrateTooLow),
1639 }
1640}
1641
1642fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
1643 let r = info.regs;
1644 r.cr1().modify(|w| {
1645 // disable uart
1646 w.set_ue(false);
1647 });
1648
1649 #[cfg(not(usart_v1))]
1650 let over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?;
1651 #[cfg(usart_v1)]
1652 let _over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?;
1653
1654 r.cr1().modify(|w| {
1655 // enable uart
1656 w.set_ue(true);
1657
1658 #[cfg(not(usart_v1))]
1659 w.set_over8(vals::Over8::from_bits(over8 as _));
1660 });
1661
1662 Ok(())
1663}
1664
1665fn configure(
1666 info: &Info,
1667 kernel_clock: Hertz,
1668 config: &Config,
1669 enable_rx: bool,
1670 enable_tx: bool,
1671) -> Result<(), ConfigError> {
1672 let r = info.regs;
1673 let kind = info.kind;
1674
1675 if !enable_rx && !enable_tx {
1676 return Err(ConfigError::RxOrTxNotEnabled);
1677 }
1678
1679 // UART must be disabled during configuration.
1680 r.cr1().modify(|w| {
1681 w.set_ue(false);
1682 });
1455 1683
1456 #[cfg(not(usart_v1))] 1684 #[cfg(not(usart_v1))]
1457 let oversampling = if over8 { "8 bit" } else { "16 bit" }; 1685 let over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?;
1458 #[cfg(usart_v1)] 1686 #[cfg(usart_v1)]
1459 let oversampling = "default"; 1687 let _over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?;
1460 trace!(
1461 "Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
1462 oversampling,
1463 config.baudrate,
1464 kernel_clock.0 / brr * mul
1465 );
1466 1688
1467 r.cr2().write(|w| { 1689 r.cr2().write(|w| {
1468 w.set_stop(match config.stop_bits { 1690 w.set_stop(match config.stop_bits {
@@ -1483,14 +1705,14 @@ fn configure(
1483 r.cr3().modify(|w| { 1705 r.cr3().modify(|w| {
1484 #[cfg(not(usart_v1))] 1706 #[cfg(not(usart_v1))]
1485 w.set_onebit(config.assume_noise_free); 1707 w.set_onebit(config.assume_noise_free);
1486 w.set_hdsel(config.half_duplex); 1708 w.set_hdsel(config.duplex.is_half());
1487 }); 1709 });
1488 1710
1489 r.cr1().write(|w| { 1711 r.cr1().write(|w| {
1490 // enable uart 1712 // enable uart
1491 w.set_ue(true); 1713 w.set_ue(true);
1492 1714
1493 if config.half_duplex { 1715 if config.duplex.is_half() {
1494 // The te and re bits will be set by write, read and flush methods. 1716 // The te and re bits will be set by write, read and flush methods.
1495 // Receiver should be enabled by default for Half-Duplex. 1717 // Receiver should be enabled by default for Half-Duplex.
1496 w.set_te(false); 1718 w.set_te(false);
@@ -1502,31 +1724,66 @@ fn configure(
1502 w.set_re(enable_rx); 1724 w.set_re(enable_rx);
1503 } 1725 }
1504 1726
1505 // configure word size 1727 // configure word size and parity, since the parity bit is inserted into the MSB position,
1506 // if using odd or even parity it must be configured to 9bits 1728 // it increases the effective word size
1507 w.set_m0(if config.parity != Parity::ParityNone { 1729 match (config.parity, config.data_bits) {
1508 trace!("USART: m0: vals::M0::BIT9"); 1730 (Parity::ParityNone, DataBits::DataBits8) => {
1509 vals::M0::BIT9 1731 trace!("USART: m0: 8 data bits, no parity");
1510 } else { 1732 w.set_m0(vals::M0::BIT8);
1511 trace!("USART: m0: vals::M0::BIT8"); 1733 #[cfg(any(usart_v3, usart_v4))]
1512 vals::M0::BIT8 1734 w.set_m1(vals::M1::M0);
1513 }); 1735 w.set_pce(false);
1514 // configure parity
1515 w.set_pce(config.parity != Parity::ParityNone);
1516 w.set_ps(match config.parity {
1517 Parity::ParityOdd => {
1518 trace!("USART: set_ps: vals::Ps::ODD");
1519 vals::Ps::ODD
1520 } 1736 }
1521 Parity::ParityEven => { 1737 (Parity::ParityNone, DataBits::DataBits9) => {
1522 trace!("USART: set_ps: vals::Ps::EVEN"); 1738 trace!("USART: m0: 9 data bits, no parity");
1523 vals::Ps::EVEN 1739 w.set_m0(vals::M0::BIT9);
1740 #[cfg(any(usart_v3, usart_v4))]
1741 w.set_m1(vals::M1::M0);
1742 w.set_pce(false);
1743 }
1744 #[cfg(any(usart_v3, usart_v4))]
1745 (Parity::ParityNone, DataBits::DataBits7) => {
1746 trace!("USART: m0: 7 data bits, no parity");
1747 w.set_m0(vals::M0::BIT8);
1748 w.set_m1(vals::M1::BIT7);
1749 w.set_pce(false);
1750 }
1751 (Parity::ParityEven, DataBits::DataBits8) => {
1752 trace!("USART: m0: 8 data bits, even parity");
1753 w.set_m0(vals::M0::BIT9);
1754 #[cfg(any(usart_v3, usart_v4))]
1755 w.set_m1(vals::M1::M0);
1756 w.set_pce(true);
1757 w.set_ps(vals::Ps::EVEN);
1758 }
1759 (Parity::ParityEven, DataBits::DataBits7) => {
1760 trace!("USART: m0: 7 data bits, even parity");
1761 w.set_m0(vals::M0::BIT8);
1762 #[cfg(any(usart_v3, usart_v4))]
1763 w.set_m1(vals::M1::M0);
1764 w.set_pce(true);
1765 w.set_ps(vals::Ps::EVEN);
1766 }
1767 (Parity::ParityOdd, DataBits::DataBits8) => {
1768 trace!("USART: m0: 8 data bits, odd parity");
1769 w.set_m0(vals::M0::BIT9);
1770 #[cfg(any(usart_v3, usart_v4))]
1771 w.set_m1(vals::M1::M0);
1772 w.set_pce(true);
1773 w.set_ps(vals::Ps::ODD);
1774 }
1775 (Parity::ParityOdd, DataBits::DataBits7) => {
1776 trace!("USART: m0: 7 data bits, odd parity");
1777 w.set_m0(vals::M0::BIT8);
1778 #[cfg(any(usart_v3, usart_v4))]
1779 w.set_m1(vals::M1::M0);
1780 w.set_pce(true);
1781 w.set_ps(vals::Ps::ODD);
1524 } 1782 }
1525 _ => { 1783 _ => {
1526 trace!("USART: set_ps: vals::Ps::EVEN"); 1784 return Err(ConfigError::DataParityNotSupported);
1527 vals::Ps::EVEN
1528 } 1785 }
1529 }); 1786 }
1530 #[cfg(not(usart_v1))] 1787 #[cfg(not(usart_v1))]
1531 w.set_over8(vals::Over8::from_bits(over8 as _)); 1788 w.set_over8(vals::Over8::from_bits(over8 as _));
1532 #[cfg(usart_v4)] 1789 #[cfg(usart_v4)]
@@ -1534,7 +1791,9 @@ fn configure(
1534 trace!("USART: set_fifoen: true (usart_v4)"); 1791 trace!("USART: set_fifoen: true (usart_v4)");
1535 w.set_fifoen(true); 1792 w.set_fifoen(true);
1536 } 1793 }
1537 }); 1794
1795 Ok(())
1796 })?;
1538 1797
1539 Ok(()) 1798 Ok(())
1540} 1799}
@@ -1672,7 +1931,7 @@ impl embedded_io_async::Write for Uart<'_, Async> {
1672 } 1931 }
1673 1932
1674 async fn flush(&mut self) -> Result<(), Self::Error> { 1933 async fn flush(&mut self) -> Result<(), Self::Error> {
1675 self.blocking_flush() 1934 self.flush().await
1676 } 1935 }
1677} 1936}
1678 1937
@@ -1683,7 +1942,7 @@ impl embedded_io_async::Write for UartTx<'_, Async> {
1683 } 1942 }
1684 1943
1685 async fn flush(&mut self) -> Result<(), Self::Error> { 1944 async fn flush(&mut self) -> Result<(), Self::Error> {
1686 self.blocking_flush() 1945 self.flush().await
1687 } 1946 }
1688} 1947}
1689 1948
@@ -1749,6 +2008,7 @@ enum Kind {
1749 2008
1750struct State { 2009struct State {
1751 rx_waker: AtomicWaker, 2010 rx_waker: AtomicWaker,
2011 tx_waker: AtomicWaker,
1752 tx_rx_refcount: AtomicU8, 2012 tx_rx_refcount: AtomicU8,
1753} 2013}
1754 2014
@@ -1756,6 +2016,7 @@ impl State {
1756 const fn new() -> Self { 2016 const fn new() -> Self {
1757 Self { 2017 Self {
1758 rx_waker: AtomicWaker::new(), 2018 rx_waker: AtomicWaker::new(),
2019 tx_waker: AtomicWaker::new(),
1759 tx_rx_refcount: AtomicU8::new(0), 2020 tx_rx_refcount: AtomicU8::new(0),
1760 } 2021 }
1761 } 2022 }
@@ -1777,7 +2038,7 @@ pub(crate) trait SealedInstance: crate::rcc::RccPeripheral {
1777 2038
1778/// USART peripheral instance trait. 2039/// USART peripheral instance trait.
1779#[allow(private_bounds)] 2040#[allow(private_bounds)]
1780pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { 2041pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
1781 /// Interrupt for this peripheral. 2042 /// Interrupt for this peripheral.
1782 type Interrupt: interrupt::typelevel::Interrupt; 2043 type Interrupt: interrupt::typelevel::Interrupt;
1783} 2044}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 8cf75933a..1d4a44896 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -4,25 +4,85 @@ use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::PeripheralRef; 7use embedded_io_async::ReadReady;
8use futures_util::future::{select, Either}; 8use futures_util::future::{select, Either};
9 9
10use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; 10use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx};
11use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
12use crate::gpio::{AnyPin, SealedPin as _}; 12use crate::gpio::{AnyPin, SealedPin as _};
13use crate::mode::Async; 13use crate::mode::Async;
14use crate::time::Hertz; 14use crate::time::Hertz;
15use crate::usart::{Regs, Sr}; 15use crate::usart::Regs;
16use crate::Peri;
16 17
17/// Rx-only Ring-buffered UART Driver 18/// Rx-only Ring-buffered UART Driver
18/// 19///
19/// Created with [UartRx::into_ring_buffered] 20/// Created with [UartRx::into_ring_buffered]
21///
22/// ### Notes on 'waiting for bytes'
23///
24/// The `read(buf)` (but not `read()`) and `read_exact(buf)` functions
25/// may need to wait for bytes to arrive, if the ring buffer does not
26/// contain enough bytes to fill the buffer passed by the caller of
27/// the function, or is empty.
28///
29/// Waiting for bytes operates in one of two modes, depending on
30/// the behavior of the sender and the size of the buffer passed
31/// to the function:
32///
33/// - If the sender sends intermittently, the 'idle line'
34/// condition will be detected when the sender stops, and any
35/// bytes in the ring buffer will be returned. If there are no
36/// bytes in the buffer, the check will be repeated each time the
37/// 'idle line' condition is detected, so if the sender sends just
38/// a single byte, it will be returned once the 'idle line'
39/// condition is detected.
40///
41/// - If the sender sends continuously, the call will wait until
42/// the DMA controller indicates that it has written to either the
43/// middle byte or last byte of the ring buffer ('half transfer'
44/// or 'transfer complete', respectively). This does not indicate
45/// the buffer is half-full or full, though, because the DMA
46/// controller does not detect those conditions; it sends an
47/// interrupt when those specific buffer addresses have been
48/// written.
49///
50/// In both cases this will result in variable latency due to the
51/// buffering effect. For example, if the baudrate is 2400 bps, and
52/// the configuration is 8 data bits, no parity bit, and one stop bit,
53/// then a byte will be received every ~4.16ms. If the ring buffer is
54/// 32 bytes, then a 'wait for bytes' delay may have to wait for 16
55/// bytes in the worst case, resulting in a delay (latency) of
56/// ~62.46ms for the first byte in the ring buffer. If the sender
57/// sends only 6 bytes and then stops, but the buffer was empty when
58/// the read function was called, then those bytes may not be returned
59/// until ~24.96ms after the first byte was received (time for 5
60/// additional bytes plus the 'idle frame' which triggers the 'idle
61/// line' condition).
62///
63/// Applications subject to this latency must be careful if they
64/// also apply timeouts during reception, as it may appear (to
65/// them) that the sender has stopped sending when it did not. In
66/// the example above, a 50ms timeout (12 bytes at 2400bps) might
67/// seem to be reasonable to detect that the sender has stopped
68/// sending, but would be falsely triggered in the worst-case
69/// buffer delay scenario.
70///
71/// Note: This latency is caused by the limited capabilities of the
72/// STM32 DMA controller; since it cannot generate an interrupt when
73/// it stores a byte into an empty ring buffer, or in any other
74/// configurable conditions, it is not possible to take notice of the
75/// contents of the ring buffer more quickly without introducing
76/// polling. As a result the latency can be reduced by calling the
77/// read functions repeatedly with smaller buffers to receive the
78/// available bytes, as each call to a read function will explicitly
79/// check the ring buffer for available bytes.
20pub struct RingBufferedUartRx<'d> { 80pub struct RingBufferedUartRx<'d> {
21 info: &'static Info, 81 info: &'static Info,
22 state: &'static State, 82 state: &'static State,
23 kernel_clock: Hertz, 83 kernel_clock: Hertz,
24 rx: Option<PeripheralRef<'d, AnyPin>>, 84 rx: Option<Peri<'d, AnyPin>>,
25 rts: Option<PeripheralRef<'d, AnyPin>>, 85 rts: Option<Peri<'d, AnyPin>>,
26 ring_buf: ReadableRingBuffer<'d, u8>, 86 ring_buf: ReadableRingBuffer<'d, u8>,
27} 87}
28 88
@@ -71,33 +131,18 @@ impl<'d> UartRx<'d, Async> {
71} 131}
72 132
73impl<'d> RingBufferedUartRx<'d> { 133impl<'d> RingBufferedUartRx<'d> {
74 /// Clear the ring buffer and start receiving in the background
75 pub fn start(&mut self) -> Result<(), Error> {
76 // Clear the ring buffer so that it is ready to receive data
77 self.ring_buf.clear();
78
79 self.setup_uart();
80
81 Ok(())
82 }
83
84 fn stop(&mut self, err: Error) -> Result<usize, Error> {
85 self.teardown_uart();
86
87 Err(err)
88 }
89
90 /// Reconfigure the driver 134 /// Reconfigure the driver
91 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 135 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
92 reconfigure(self.info, self.kernel_clock, config) 136 reconfigure(self.info, self.kernel_clock, config)
93 } 137 }
94 138
95 /// Start uart background receive 139 /// Configure and start the DMA backed UART receiver
96 fn setup_uart(&mut self) { 140 ///
97 // fence before starting DMA. 141 /// Note: This is also done automatically by the read functions if
142 /// required.
143 pub fn start_uart(&mut self) {
144 // Clear the buffer so that it is ready to receive data
98 compiler_fence(Ordering::SeqCst); 145 compiler_fence(Ordering::SeqCst);
99
100 // start the dma controller
101 self.ring_buf.start(); 146 self.ring_buf.start();
102 147
103 let r = self.info.regs; 148 let r = self.info.regs;
@@ -118,9 +163,9 @@ impl<'d> RingBufferedUartRx<'d> {
118 }); 163 });
119 } 164 }
120 165
121 /// Stop uart background receive 166 /// Stop DMA backed UART receiver
122 fn teardown_uart(&mut self) { 167 fn stop_uart(&mut self) {
123 self.ring_buf.request_stop(); 168 self.ring_buf.request_pause();
124 169
125 let r = self.info.regs; 170 let r = self.info.regs;
126 // clear all interrupts and DMA Rx Request 171 // clear all interrupts and DMA Rx Request
@@ -142,23 +187,40 @@ impl<'d> RingBufferedUartRx<'d> {
142 compiler_fence(Ordering::SeqCst); 187 compiler_fence(Ordering::SeqCst);
143 } 188 }
144 189
145 /// Read bytes that are readily available in the ring buffer. 190 /// (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), and
146 /// If no bytes are currently available in the buffer the call waits until the some 191 /// check for errors in status register. Error flags are checked/cleared first.
147 /// bytes are available (at least one byte and at most half the buffer size) 192 fn start_dma_or_check_errors(&mut self) -> Result<(), Error> {
148 ///
149 /// Background receive is started if `start()` has not been previously called.
150 ///
151 /// Receive in the background is terminated if an error is returned.
152 /// It must then manually be started again by calling `start()` or by re-calling `read()`.
153 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
154 let r = self.info.regs; 193 let r = self.info.regs;
155 194
156 // Start background receive if it was not already started 195 check_idle_and_errors(r)?;
157 if !r.cr3().read().dmar() { 196 if !r.cr3().read().dmar() {
158 self.start()?; 197 self.start_uart();
159 } 198 }
199 Ok(())
200 }
201
202 /// Read bytes that are available in the ring buffer, or wait for
203 /// bytes to become available and return them.
204 ///
205 /// Background reception is started if necessary (if `start_uart()` had
206 /// not previously been called, or if an error was detected which
207 /// caused background reception to be stopped).
208 ///
209 /// Background reception is terminated when an error is returned.
210 /// It must be started again by calling `start_uart()` or by
211 /// calling a read function again.
212 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
213 self.start_dma_or_check_errors()?;
160 214
161 check_for_errors(clear_idle_flag(r))?; 215 // In half-duplex mode, we need to disable the Transmitter and enable the Receiver
216 // since they can't operate simultaneously on the shared line
217 let r = self.info.regs;
218 if r.cr3().read().hdsel() && r.cr1().read().te() {
219 r.cr1().modify(|reg| {
220 reg.set_re(true);
221 reg.set_te(false);
222 });
223 }
162 224
163 loop { 225 loop {
164 match self.ring_buf.read(buf) { 226 match self.ring_buf.read(buf) {
@@ -167,14 +229,16 @@ impl<'d> RingBufferedUartRx<'d> {
167 return Ok(len); 229 return Ok(len);
168 } 230 }
169 Err(_) => { 231 Err(_) => {
170 return self.stop(Error::Overrun); 232 self.stop_uart();
233 return Err(Error::Overrun);
171 } 234 }
172 } 235 }
173 236
174 match self.wait_for_data_or_idle().await { 237 match self.wait_for_data_or_idle().await {
175 Ok(_) => {} 238 Ok(_) => {}
176 Err(err) => { 239 Err(err) => {
177 return self.stop(err); 240 self.stop_uart();
241 return Err(err);
178 } 242 }
179 } 243 }
180 } 244 }
@@ -184,20 +248,6 @@ impl<'d> RingBufferedUartRx<'d> {
184 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { 248 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
185 compiler_fence(Ordering::SeqCst); 249 compiler_fence(Ordering::SeqCst);
186 250
187 let mut dma_init = false;
188 // Future which completes when there is dma is half full or full
189 let dma = poll_fn(|cx| {
190 self.ring_buf.set_waker(cx.waker());
191
192 let status = match dma_init {
193 false => Poll::Pending,
194 true => Poll::Ready(()),
195 };
196
197 dma_init = true;
198 status
199 });
200
201 // Future which completes when idle line is detected 251 // Future which completes when idle line is detected
202 let s = self.state; 252 let s = self.state;
203 let uart = poll_fn(|cx| { 253 let uart = poll_fn(|cx| {
@@ -205,13 +255,7 @@ impl<'d> RingBufferedUartRx<'d> {
205 255
206 compiler_fence(Ordering::SeqCst); 256 compiler_fence(Ordering::SeqCst);
207 257
208 // Critical section is needed so that IDLE isn't set after 258 if check_idle_and_errors(self.info.regs)? {
209 // our read but before we clear it.
210 let sr = critical_section::with(|_| clear_idle_flag(self.info.regs));
211
212 check_for_errors(sr)?;
213
214 if sr.idle() {
215 // Idle line is detected 259 // Idle line is detected
216 Poll::Ready(Ok(())) 260 Poll::Ready(Ok(()))
217 } else { 261 } else {
@@ -219,58 +263,131 @@ impl<'d> RingBufferedUartRx<'d> {
219 } 263 }
220 }); 264 });
221 265
222 match select(dma, uart).await { 266 let mut dma_init = false;
223 Either::Left(((), _)) => Ok(()), 267 // Future which completes when the DMA controller indicates it
224 Either::Right((result, _)) => result, 268 // has written to the ring buffer's middle byte, or last byte
269 let dma = poll_fn(|cx| {
270 self.ring_buf.set_waker(cx.waker());
271
272 let status = match dma_init {
273 false => Poll::Pending,
274 true => Poll::Ready(()),
275 };
276
277 dma_init = true;
278 status
279 });
280
281 match select(uart, dma).await {
282 Either::Left((result, _)) => result,
283 Either::Right(((), _)) => Ok(()),
225 } 284 }
226 } 285 }
286
287 /// Set baudrate
288 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
289 set_baudrate(self.info, self.kernel_clock, baudrate)
290 }
227} 291}
228 292
229impl Drop for RingBufferedUartRx<'_> { 293impl Drop for RingBufferedUartRx<'_> {
230 fn drop(&mut self) { 294 fn drop(&mut self) {
231 self.teardown_uart(); 295 self.stop_uart();
232 self.rx.as_ref().map(|x| x.set_as_disconnected()); 296 self.rx.as_ref().map(|x| x.set_as_disconnected());
233 self.rts.as_ref().map(|x| x.set_as_disconnected()); 297 self.rts.as_ref().map(|x| x.set_as_disconnected());
234 super::drop_tx_rx(self.info, self.state); 298 super::drop_tx_rx(self.info, self.state);
235 } 299 }
236} 300}
237 301
238/// Return an error result if the Sr register has errors 302/// Check and clear idle and error interrupts, return true if idle, Err(e) on error
239fn check_for_errors(s: Sr) -> Result<(), Error> { 303///
240 if s.pe() { 304/// All flags are read and cleared in a single step, respectively. When more than one flag is set
305/// at the same time, all flags will be cleared but only one flag will be reported. So the other
306/// flag(s) will gone missing unnoticed. The error flags are checked first, the idle flag last.
307///
308/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags
309/// are cleared by a single read to the RDR register.
310fn check_idle_and_errors(r: Regs) -> Result<bool, Error> {
311 // Critical section is required so that the flags aren't set after read and before clear
312 let sr = critical_section::with(|_| {
313 // SAFETY: read only and we only use Rx related flags
314 let sr = sr(r).read();
315
316 #[cfg(any(usart_v3, usart_v4))]
317 r.icr().write(|w| {
318 w.set_idle(true);
319 w.set_pe(true);
320 w.set_fe(true);
321 w.set_ne(true);
322 w.set_ore(true);
323 });
324 #[cfg(not(any(usart_v3, usart_v4)))]
325 unsafe {
326 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
327 rdr(r).read_volatile()
328 };
329 sr
330 });
331 if sr.pe() {
241 Err(Error::Parity) 332 Err(Error::Parity)
242 } else if s.fe() { 333 } else if sr.fe() {
243 Err(Error::Framing) 334 Err(Error::Framing)
244 } else if s.ne() { 335 } else if sr.ne() {
245 Err(Error::Noise) 336 Err(Error::Noise)
246 } else if s.ore() { 337 } else if sr.ore() {
247 Err(Error::Overrun) 338 Err(Error::Overrun)
248 } else { 339 } else {
249 Ok(()) 340 r.cr1().modify(|w| w.set_idleie(true));
341 Ok(sr.idle())
250 } 342 }
251} 343}
252 344
253/// Clear IDLE and return the Sr register 345impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> {
254fn clear_idle_flag(r: Regs) -> Sr { 346 type Error = Error;
255 // SAFETY: read only and we only use Rx related flags 347}
256
257 let sr = sr(r).read();
258 348
259 // This read also clears the error and idle interrupt flags on v1. 349impl embedded_io_async::Read for RingBufferedUartRx<'_> {
260 unsafe { rdr(r).read_volatile() }; 350 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
261 clear_interrupt_flags(r, sr); 351 self.read(buf).await
352 }
353}
262 354
263 r.cr1().modify(|w| w.set_idleie(true)); 355impl embedded_hal_nb::serial::Read for RingBufferedUartRx<'_> {
356 fn read(&mut self) -> nb::Result<u8, Self::Error> {
357 self.start_dma_or_check_errors()?;
264 358
265 sr 359 let mut buf = [0u8; 1];
360 match self.ring_buf.read(&mut buf) {
361 Ok((0, _)) => Err(nb::Error::WouldBlock),
362 Ok((len, _)) => {
363 assert!(len == 1);
364 Ok(buf[0])
365 }
366 Err(_) => {
367 self.stop_uart();
368 Err(nb::Error::Other(Error::Overrun))
369 }
370 }
371 }
266} 372}
267 373
268impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> { 374impl embedded_hal_nb::serial::ErrorType for RingBufferedUartRx<'_> {
269 type Error = Error; 375 type Error = Error;
270} 376}
271 377
272impl embedded_io_async::Read for RingBufferedUartRx<'_> { 378impl ReadReady for RingBufferedUartRx<'_> {
273 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 379 fn read_ready(&mut self) -> Result<bool, Self::Error> {
274 self.read(buf).await 380 let len = self.ring_buf.len().map_err(|e| match e {
381 crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun,
382 crate::dma::ringbuffer::Error::DmaUnsynced => {
383 error!(
384 "Ringbuffer error: DmaUNsynced, driver implementation is
385 probably bugged please open an issue"
386 );
387 // we report this as overrun since its recoverable in the same way
388 Self::Error::Overrun
389 }
390 })?;
391 Ok(len > 0)
275 } 392 }
276} 393}
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index ce9fe0a9b..ae5963420 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -13,9 +13,19 @@ fn common_init<T: Instance>() {
13 // Check the USB clock is enabled and running at exactly 48 MHz. 13 // Check the USB clock is enabled and running at exactly 48 MHz.
14 // frequency() will panic if not enabled 14 // frequency() will panic if not enabled
15 let freq = T::frequency(); 15 let freq = T::frequency();
16
17 // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally
18 #[cfg(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs)))]
19 if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) {
20 panic!(
21 "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.",
22 freq.0
23 )
24 }
16 // Check frequency is within the 0.25% tolerance allowed by the spec. 25 // Check frequency is within the 0.25% tolerance allowed by the spec.
17 // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user 26 // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user
18 // has tight clock restrictions due to something else (like audio). 27 // has tight clock restrictions due to something else (like audio).
28 #[cfg(not(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs))))]
19 if freq.0.abs_diff(48_000_000) > 120_000 { 29 if freq.0.abs_diff(48_000_000) > 120_000 {
20 panic!( 30 panic!(
21 "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", 31 "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.",
@@ -48,6 +58,26 @@ fn common_init<T: Instance>() {
48 while !crate::pac::PWR.cr3().read().usb33rdy() {} 58 while !crate::pac::PWR.cr3().read().usb33rdy() {}
49 } 59 }
50 60
61 #[cfg(stm32h7rs)]
62 {
63 // If true, VDD33USB is generated by internal regulator from VDD50USB
64 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
65 // TODO: unhardcode
66 let internal_regulator = false;
67
68 // Enable USB power
69 critical_section::with(|_| {
70 crate::pac::PWR.csr2().modify(|w| {
71 w.set_usbregen(internal_regulator);
72 w.set_usb33den(true);
73 w.set_usbhsregen(true);
74 })
75 });
76
77 // Wait for USB power to stabilize
78 while !crate::pac::PWR.csr2().read().usb33rdy() {}
79 }
80
51 #[cfg(stm32u5)] 81 #[cfg(stm32u5)]
52 { 82 {
53 // Enable USB power 83 // Enable USB power
@@ -60,6 +90,16 @@ fn common_init<T: Instance>() {
60 90
61 // Wait for USB power to stabilize 91 // Wait for USB power to stabilize
62 while !crate::pac::PWR.svmsr().read().vddusbrdy() {} 92 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
93
94 // Now set up transceiver power if it's a OTG-HS
95 #[cfg(peri_usb_otg_hs)]
96 {
97 crate::pac::PWR.vosr().modify(|w| {
98 w.set_usbpwren(true);
99 w.set_usbboosten(true);
100 });
101 while !crate::pac::PWR.vosr().read().usbboostrdy() {}
102 }
63 } 103 }
64 104
65 T::Interrupt::unpend(); 105 T::Interrupt::unpend();
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 8ee8dcc36..590d1a427 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -1,6 +1,6 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy_hal_internal::{into_ref, Peripheral}; 3use embassy_hal_internal::PeripheralType;
4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; 4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported};
5use embassy_usb_synopsys_otg::otg_v1::vals::Dspd; 5use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
6use embassy_usb_synopsys_otg::otg_v1::Otg; 6use embassy_usb_synopsys_otg::otg_v1::Otg;
@@ -11,9 +11,9 @@ use embassy_usb_synopsys_otg::{
11}; 11};
12 12
13use crate::gpio::{AfType, OutputType, Speed}; 13use crate::gpio::{AfType, OutputType, Speed};
14use crate::interrupt;
15use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
16use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, Peri};
17 17
18const MAX_EP_COUNT: usize = 9; 18const MAX_EP_COUNT: usize = 9;
19 19
@@ -24,20 +24,15 @@ pub struct InterruptHandler<T: Instance> {
24 24
25impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 25impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
26 unsafe fn on_interrupt() { 26 unsafe fn on_interrupt() {
27 trace!("irq");
28 let r = T::regs(); 27 let r = T::regs();
29 let state = T::state(); 28 let state = T::state();
30 29 on_interrupt_impl(r, state, T::ENDPOINT_COUNT);
31 let setup_late_cnak = quirk_setup_late_cnak(r);
32
33 on_interrupt_impl(r, state, T::ENDPOINT_COUNT, setup_late_cnak);
34 } 30 }
35} 31}
36 32
37macro_rules! config_ulpi_pins { 33macro_rules! config_ulpi_pins {
38 ($($pin:ident),*) => { 34 ($($pin:ident),*) => {
39 into_ref!($($pin),*); 35 critical_section::with(|_| {
40 critical_section::with(|_| {
41 $( 36 $(
42 $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 37 $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
43 )* 38 )*
@@ -66,15 +61,13 @@ impl<'d, T: Instance> Driver<'d, T> {
66 /// Must be large enough to fit all OUT endpoint max packet sizes. 61 /// Must be large enough to fit all OUT endpoint max packet sizes.
67 /// Endpoint allocation will fail if it is too small. 62 /// Endpoint allocation will fail if it is too small.
68 pub fn new_fs( 63 pub fn new_fs(
69 _peri: impl Peripheral<P = T> + 'd, 64 _peri: Peri<'d, T>,
70 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 65 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
71 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 66 dp: Peri<'d, impl DpPin<T>>,
72 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 67 dm: Peri<'d, impl DmPin<T>>,
73 ep_out_buffer: &'d mut [u8], 68 ep_out_buffer: &'d mut [u8],
74 config: Config, 69 config: Config,
75 ) -> Self { 70 ) -> Self {
76 into_ref!(dp, dm);
77
78 dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 71 dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
79 dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); 72 dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
80 73
@@ -87,7 +80,90 @@ impl<'d, T: Instance> Driver<'d, T> {
87 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, 80 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
88 endpoint_count: T::ENDPOINT_COUNT, 81 endpoint_count: T::ENDPOINT_COUNT,
89 phy_type: PhyType::InternalFullSpeed, 82 phy_type: PhyType::InternalFullSpeed,
90 quirk_setup_late_cnak: quirk_setup_late_cnak(regs), 83 calculate_trdt_fn: calculate_trdt::<T>,
84 };
85
86 Self {
87 inner: OtgDriver::new(ep_out_buffer, instance, config),
88 phantom: PhantomData,
89 }
90 }
91
92 /// Initializes USB OTG peripheral with internal High-Speed PHY.
93 ///
94 /// # Arguments
95 ///
96 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
97 /// Must be large enough to fit all OUT endpoint max packet sizes.
98 /// Endpoint allocation will fail if it is too small.
99 pub fn new_hs(
100 _peri: Peri<'d, T>,
101 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
102 _dp: Peri<'d, impl DpPin<T>>,
103 _dm: Peri<'d, impl DmPin<T>>,
104 ep_out_buffer: &'d mut [u8],
105 config: Config,
106 ) -> Self {
107 // For STM32U5 High speed pins need to be left in analog mode
108 #[cfg(not(all(stm32u5, peri_usb_otg_hs)))]
109 {
110 _dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
111 _dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
112 }
113
114 let instance = OtgInstance {
115 regs: T::regs(),
116 state: T::state(),
117 fifo_depth_words: T::FIFO_DEPTH_WORDS,
118 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
119 endpoint_count: T::ENDPOINT_COUNT,
120 phy_type: PhyType::InternalHighSpeed,
121 calculate_trdt_fn: calculate_trdt::<T>,
122 };
123
124 Self {
125 inner: OtgDriver::new(ep_out_buffer, instance, config),
126 phantom: PhantomData,
127 }
128 }
129
130 /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode).
131 ///
132 /// # Arguments
133 ///
134 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
135 /// Must be large enough to fit all OUT endpoint max packet sizes.
136 /// Endpoint allocation will fail if it is too small.
137 pub fn new_fs_ulpi(
138 _peri: Peri<'d, T>,
139 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
140 ulpi_clk: Peri<'d, impl UlpiClkPin<T>>,
141 ulpi_dir: Peri<'d, impl UlpiDirPin<T>>,
142 ulpi_nxt: Peri<'d, impl UlpiNxtPin<T>>,
143 ulpi_stp: Peri<'d, impl UlpiStpPin<T>>,
144 ulpi_d0: Peri<'d, impl UlpiD0Pin<T>>,
145 ulpi_d1: Peri<'d, impl UlpiD1Pin<T>>,
146 ulpi_d2: Peri<'d, impl UlpiD2Pin<T>>,
147 ulpi_d3: Peri<'d, impl UlpiD3Pin<T>>,
148 ulpi_d4: Peri<'d, impl UlpiD4Pin<T>>,
149 ulpi_d5: Peri<'d, impl UlpiD5Pin<T>>,
150 ulpi_d6: Peri<'d, impl UlpiD6Pin<T>>,
151 ulpi_d7: Peri<'d, impl UlpiD7Pin<T>>,
152 ep_out_buffer: &'d mut [u8],
153 config: Config,
154 ) -> Self {
155 config_ulpi_pins!(
156 ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6,
157 ulpi_d7
158 );
159
160 let instance = OtgInstance {
161 regs: T::regs(),
162 state: T::state(),
163 fifo_depth_words: T::FIFO_DEPTH_WORDS,
164 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
165 endpoint_count: T::ENDPOINT_COUNT,
166 phy_type: PhyType::ExternalFullSpeed,
91 calculate_trdt_fn: calculate_trdt::<T>, 167 calculate_trdt_fn: calculate_trdt::<T>,
92 }; 168 };
93 169
@@ -105,20 +181,20 @@ impl<'d, T: Instance> Driver<'d, T> {
105 /// Must be large enough to fit all OUT endpoint max packet sizes. 181 /// Must be large enough to fit all OUT endpoint max packet sizes.
106 /// Endpoint allocation will fail if it is too small. 182 /// Endpoint allocation will fail if it is too small.
107 pub fn new_hs_ulpi( 183 pub fn new_hs_ulpi(
108 _peri: impl Peripheral<P = T> + 'd, 184 _peri: Peri<'d, T>,
109 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 185 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
110 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd, 186 ulpi_clk: Peri<'d, impl UlpiClkPin<T>>,
111 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd, 187 ulpi_dir: Peri<'d, impl UlpiDirPin<T>>,
112 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd, 188 ulpi_nxt: Peri<'d, impl UlpiNxtPin<T>>,
113 ulpi_stp: impl Peripheral<P = impl UlpiStpPin<T>> + 'd, 189 ulpi_stp: Peri<'d, impl UlpiStpPin<T>>,
114 ulpi_d0: impl Peripheral<P = impl UlpiD0Pin<T>> + 'd, 190 ulpi_d0: Peri<'d, impl UlpiD0Pin<T>>,
115 ulpi_d1: impl Peripheral<P = impl UlpiD1Pin<T>> + 'd, 191 ulpi_d1: Peri<'d, impl UlpiD1Pin<T>>,
116 ulpi_d2: impl Peripheral<P = impl UlpiD2Pin<T>> + 'd, 192 ulpi_d2: Peri<'d, impl UlpiD2Pin<T>>,
117 ulpi_d3: impl Peripheral<P = impl UlpiD3Pin<T>> + 'd, 193 ulpi_d3: Peri<'d, impl UlpiD3Pin<T>>,
118 ulpi_d4: impl Peripheral<P = impl UlpiD4Pin<T>> + 'd, 194 ulpi_d4: Peri<'d, impl UlpiD4Pin<T>>,
119 ulpi_d5: impl Peripheral<P = impl UlpiD5Pin<T>> + 'd, 195 ulpi_d5: Peri<'d, impl UlpiD5Pin<T>>,
120 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd, 196 ulpi_d6: Peri<'d, impl UlpiD6Pin<T>>,
121 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd, 197 ulpi_d7: Peri<'d, impl UlpiD7Pin<T>>,
122 ep_out_buffer: &'d mut [u8], 198 ep_out_buffer: &'d mut [u8],
123 config: Config, 199 config: Config,
124 ) -> Self { 200 ) -> Self {
@@ -129,8 +205,6 @@ impl<'d, T: Instance> Driver<'d, T> {
129 ulpi_d7 205 ulpi_d7
130 ); 206 );
131 207
132 let regs = T::regs();
133
134 let instance = OtgInstance { 208 let instance = OtgInstance {
135 regs: T::regs(), 209 regs: T::regs(),
136 state: T::state(), 210 state: T::state(),
@@ -138,7 +212,6 @@ impl<'d, T: Instance> Driver<'d, T> {
138 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, 212 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
139 endpoint_count: T::ENDPOINT_COUNT, 213 endpoint_count: T::ENDPOINT_COUNT,
140 phy_type: PhyType::ExternalHighSpeed, 214 phy_type: PhyType::ExternalHighSpeed,
141 quirk_setup_late_cnak: quirk_setup_late_cnak(regs),
142 calculate_trdt_fn: calculate_trdt::<T>, 215 calculate_trdt_fn: calculate_trdt::<T>,
143 }; 216 };
144 217
@@ -223,6 +296,33 @@ impl<'d, T: Instance> Bus<'d, T> {
223 } 296 }
224 }); 297 });
225 298
299 #[cfg(stm32h7rs)]
300 critical_section::with(|_| {
301 let rcc = crate::pac::RCC;
302 rcc.ahb1enr().modify(|w| {
303 w.set_usbphycen(true);
304 w.set_usb_otg_hsen(true);
305 });
306 rcc.ahb1lpenr().modify(|w| {
307 w.set_usbphyclpen(true);
308 w.set_usb_otg_hslpen(true);
309 });
310 });
311
312 #[cfg(all(stm32u5, peri_usb_otg_hs))]
313 {
314 crate::pac::SYSCFG.otghsphycr().modify(|w| {
315 w.set_en(true);
316 });
317
318 critical_section::with(|_| {
319 crate::pac::RCC.ahb2enr1().modify(|w| {
320 w.set_usb_otg_hsen(true);
321 w.set_usb_otg_hs_phyen(true);
322 });
323 });
324 }
325
226 let r = T::regs(); 326 let r = T::regs();
227 let core_id = r.cid().read().0; 327 let core_id = r.cid().read().0;
228 trace!("Core id {:08x}", core_id); 328 trace!("Core id {:08x}", core_id);
@@ -235,8 +335,9 @@ impl<'d, T: Instance> Bus<'d, T> {
235 335
236 // Configuring Vbus sense and SOF output 336 // Configuring Vbus sense and SOF output
237 match core_id { 337 match core_id {
238 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(), 338 0x0000_1200 | 0x0000_1100 | 0x0000_1000 => self.inner.config_v1(),
239 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(), 339 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
340 0x0000_5000 => self.inner.config_v5(),
240 _ => unimplemented!("Unknown USB core id {:X}", core_id), 341 _ => unimplemented!("Unknown USB core id {:X}", core_id),
241 } 342 }
242 } 343 }
@@ -306,7 +407,7 @@ trait SealedInstance {
306 407
307/// USB instance trait. 408/// USB instance trait.
308#[allow(private_bounds)] 409#[allow(private_bounds)]
309pub trait Instance: SealedInstance + RccPeripheral + 'static { 410pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {
310 /// Interrupt for this USB instance. 411 /// Interrupt for this USB instance.
311 type Interrupt: interrupt::typelevel::Interrupt; 412 type Interrupt: interrupt::typelevel::Interrupt;
312} 413}
@@ -448,11 +549,11 @@ foreach_interrupt!(
448); 549);
449 550
450fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 { 551fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 {
451 let ahb_freq = T::frequency().0; 552 let ahb_freq = T::bus_frequency().0;
452 match speed { 553 match speed {
453 Dspd::HIGH_SPEED => { 554 Dspd::HIGH_SPEED => {
454 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) 555 // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446)
455 if ahb_freq >= 30_000_000 { 556 if ahb_freq >= 30_000_000 || cfg!(stm32h7rs) {
456 0x9 557 0x9
457 } else { 558 } else {
458 panic!("AHB frequency is too low") 559 panic!("AHB frequency is too low")
@@ -477,7 +578,3 @@ fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 {
477 _ => unimplemented!(), 578 _ => unimplemented!(),
478 } 579 }
479} 580}
480
481fn quirk_setup_late_cnak(r: Otg) -> bool {
482 r.cid().read().0 & 0xf000 == 0x1000
483}
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 9384c8688..3e8e74a1f 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -5,7 +5,7 @@ use core::marker::PhantomData;
5use core::sync::atomic::{AtomicBool, Ordering}; 5use core::sync::atomic::{AtomicBool, Ordering};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_hal_internal::into_ref; 8use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use embassy_usb_driver as driver; 10use embassy_usb_driver as driver;
11use embassy_usb_driver::{ 11use embassy_usb_driver::{
@@ -16,7 +16,7 @@ use crate::pac::usb::regs;
16use crate::pac::usb::vals::{EpType, Stat}; 16use crate::pac::usb::vals::{EpType, Stat};
17use crate::pac::USBRAM; 17use crate::pac::USBRAM;
18use crate::rcc::RccPeripheral; 18use crate::rcc::RccPeripheral;
19use crate::{interrupt, Peripheral}; 19use crate::{interrupt, Peri};
20 20
21/// Interrupt handler. 21/// Interrupt handler.
22pub struct InterruptHandler<T: Instance> { 22pub struct InterruptHandler<T: Instance> {
@@ -80,8 +80,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
80 80
81 if istr.ctr() { 81 if istr.ctr() {
82 let index = istr.ep_id() as usize; 82 let index = istr.ep_id() as usize;
83
83 let mut epr = regs.epr(index).read(); 84 let mut epr = regs.epr(index).read();
84 if epr.ctr_rx() { 85 if epr.ctr_rx() {
86 RX_COMPLETE[index].store(true, Ordering::Relaxed);
85 if index == 0 && epr.setup() { 87 if index == 0 && epr.setup() {
86 EP0_SETUP.store(true, Ordering::Relaxed); 88 EP0_SETUP.store(true, Ordering::Relaxed);
87 } 89 }
@@ -89,6 +91,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
89 EP_OUT_WAKERS[index].wake(); 91 EP_OUT_WAKERS[index].wake();
90 } 92 }
91 if epr.ctr_tx() { 93 if epr.ctr_tx() {
94 TX_PENDING[index].store(false, Ordering::Relaxed);
92 //trace!("EP {} TX", index); 95 //trace!("EP {} TX", index);
93 EP_IN_WAKERS[index].wake(); 96 EP_IN_WAKERS[index].wake();
94 } 97 }
@@ -117,11 +120,13 @@ const USBRAM_ALIGN: usize = 2;
117#[cfg(any(usbram_32_2048, usbram_32_1024))] 120#[cfg(any(usbram_32_2048, usbram_32_1024))]
118const USBRAM_ALIGN: usize = 4; 121const USBRAM_ALIGN: usize = 4;
119 122
120const NEW_AW: AtomicWaker = AtomicWaker::new(); 123static BUS_WAKER: AtomicWaker = AtomicWaker::new();
121static BUS_WAKER: AtomicWaker = NEW_AW;
122static EP0_SETUP: AtomicBool = AtomicBool::new(false); 124static EP0_SETUP: AtomicBool = AtomicBool::new(false);
123static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; 125
124static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; 126static TX_PENDING: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT];
127static RX_COMPLETE: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT];
128static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT];
129static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT];
125static IRQ_RESET: AtomicBool = AtomicBool::new(false); 130static IRQ_RESET: AtomicBool = AtomicBool::new(false);
126static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false); 131static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false);
127static IRQ_RESUME: AtomicBool = AtomicBool::new(false); 132static IRQ_RESUME: AtomicBool = AtomicBool::new(false);
@@ -163,20 +168,37 @@ fn calc_out_len(len: u16) -> (u16, u16) {
163mod btable { 168mod btable {
164 use super::*; 169 use super::*;
165 170
166 pub(super) fn write_in<T: Instance>(index: usize, addr: u16) { 171 pub(super) fn write_in_tx<T: Instance>(index: usize, addr: u16) {
167 USBRAM.mem(index * 4 + 0).write_value(addr); 172 USBRAM.mem(index * 4 + 0).write_value(addr);
168 } 173 }
169 174
170 pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { 175 pub(super) fn write_in_rx<T: Instance>(index: usize, addr: u16) {
176 USBRAM.mem(index * 4 + 2).write_value(addr);
177 }
178
179 pub(super) fn write_in_len_rx<T: Instance>(index: usize, _addr: u16, len: u16) {
180 USBRAM.mem(index * 4 + 3).write_value(len);
181 }
182
183 pub(super) fn write_in_len_tx<T: Instance>(index: usize, _addr: u16, len: u16) {
171 USBRAM.mem(index * 4 + 1).write_value(len); 184 USBRAM.mem(index * 4 + 1).write_value(len);
172 } 185 }
173 186
174 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 187 pub(super) fn write_out_rx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
175 USBRAM.mem(index * 4 + 2).write_value(addr); 188 USBRAM.mem(index * 4 + 2).write_value(addr);
176 USBRAM.mem(index * 4 + 3).write_value(max_len_bits); 189 USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
177 } 190 }
178 191
179 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { 192 pub(super) fn write_out_tx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
193 USBRAM.mem(index * 4 + 0).write_value(addr);
194 USBRAM.mem(index * 4 + 1).write_value(max_len_bits);
195 }
196
197 pub(super) fn read_out_len_tx<T: Instance>(index: usize) -> u16 {
198 USBRAM.mem(index * 4 + 1).read()
199 }
200
201 pub(super) fn read_out_len_rx<T: Instance>(index: usize) -> u16 {
180 USBRAM.mem(index * 4 + 3).read() 202 USBRAM.mem(index * 4 + 3).read()
181 } 203 }
182} 204}
@@ -184,19 +206,35 @@ mod btable {
184mod btable { 206mod btable {
185 use super::*; 207 use super::*;
186 208
187 pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {} 209 pub(super) fn write_in_len_tx<T: Instance>(index: usize, addr: u16, len: u16) {
188 210 assert_eq!(addr & 0b11, 0);
189 pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
190 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); 211 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
191 } 212 }
192 213
193 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 214 pub(super) fn write_in_len_rx<T: Instance>(index: usize, addr: u16, len: u16) {
215 assert_eq!(addr & 0b11, 0);
216 USBRAM
217 .mem(index * 2 + 1)
218 .write_value((addr as u32) | ((len as u32) << 16));
219 }
220
221 pub(super) fn write_out_tx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
222 USBRAM
223 .mem(index * 2)
224 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
225 }
226
227 pub(super) fn write_out_rx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
194 USBRAM 228 USBRAM
195 .mem(index * 2 + 1) 229 .mem(index * 2 + 1)
196 .write_value((addr as u32) | ((max_len_bits as u32) << 16)); 230 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
197 } 231 }
198 232
199 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { 233 pub(super) fn read_out_len_tx<T: Instance>(index: usize) -> u16 {
234 (USBRAM.mem(index * 2).read() >> 16) as u16
235 }
236
237 pub(super) fn read_out_len_rx<T: Instance>(index: usize) -> u16 {
200 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 238 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16
201 } 239 }
202} 240}
@@ -249,15 +287,30 @@ pub struct Driver<'d, T: Instance> {
249} 287}
250 288
251impl<'d, T: Instance> Driver<'d, T> { 289impl<'d, T: Instance> Driver<'d, T> {
290 /// Create a new USB driver with start-of-frame (SOF) output.
291 #[cfg(not(stm32l1))]
292 pub fn new_with_sof(
293 _usb: Peri<'d, T>,
294 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
295 dp: Peri<'d, impl DpPin<T>>,
296 dm: Peri<'d, impl DmPin<T>>,
297 sof: Peri<'d, impl SofPin<T>>,
298 ) -> Self {
299 {
300 use crate::gpio::{AfType, OutputType, Speed};
301 sof.set_as_af(sof.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
302 }
303
304 Self::new(_usb, _irq, dp, dm)
305 }
306
252 /// Create a new USB driver. 307 /// Create a new USB driver.
253 pub fn new( 308 pub fn new(
254 _usb: impl Peripheral<P = T> + 'd, 309 _usb: Peri<'d, T>,
255 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 310 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
256 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 311 dp: Peri<'d, impl DpPin<T>>,
257 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 312 dm: Peri<'d, impl DmPin<T>>,
258 ) -> Self { 313 ) -> Self {
259 into_ref!(dp, dm);
260
261 super::common_init::<T>(); 314 super::common_init::<T>();
262 315
263 let regs = T::regs(); 316 let regs = T::regs();
@@ -267,10 +320,8 @@ impl<'d, T: Instance> Driver<'d, T> {
267 w.set_fres(true); 320 w.set_fres(true);
268 }); 321 });
269 322
270 #[cfg(feature = "time")] 323 // wait t_STARTUP = 1us
271 embassy_time::block_for(embassy_time::Duration::from_millis(100)); 324 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000_000);
272 #[cfg(not(feature = "time"))]
273 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 10);
274 325
275 #[cfg(not(usb_v4))] 326 #[cfg(not(usb_v4))]
276 regs.btable().write(|w| w.set_btable(0)); 327 regs.btable().write(|w| w.set_btable(0));
@@ -327,6 +378,14 @@ impl<'d, T: Instance> Driver<'d, T> {
327 return false; // reserved for control pipe 378 return false; // reserved for control pipe
328 } 379 }
329 let used = ep.used_out || ep.used_in; 380 let used = ep.used_out || ep.used_in;
381 if used && (ep.ep_type == EndpointType::Isochronous) {
382 // Isochronous endpoints are always double-buffered.
383 // Their corresponding endpoint/channel registers are forced to be unidirectional.
384 // Do not reuse this index.
385 // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation.
386 return false;
387 }
388
330 let used_dir = match D::dir() { 389 let used_dir = match D::dir() {
331 Direction::Out => ep.used_out, 390 Direction::Out => ep.used_out,
332 Direction::In => ep.used_in, 391 Direction::In => ep.used_in,
@@ -350,7 +409,11 @@ impl<'d, T: Instance> Driver<'d, T> {
350 let addr = self.alloc_ep_mem(len); 409 let addr = self.alloc_ep_mem(len);
351 410
352 trace!(" len_bits = {:04x}", len_bits); 411 trace!(" len_bits = {:04x}", len_bits);
353 btable::write_out::<T>(index, addr, len_bits); 412 btable::write_out_rx::<T>(index, addr, len_bits);
413
414 if ep_type == EndpointType::Isochronous {
415 btable::write_out_tx::<T>(index, addr, len_bits);
416 }
354 417
355 EndpointBuffer { 418 EndpointBuffer {
356 addr, 419 addr,
@@ -365,8 +428,24 @@ impl<'d, T: Instance> Driver<'d, T> {
365 let len = align_len_up(max_packet_size); 428 let len = align_len_up(max_packet_size);
366 let addr = self.alloc_ep_mem(len); 429 let addr = self.alloc_ep_mem(len);
367 430
368 // ep_in_len is written when actually TXing packets. 431 #[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
369 btable::write_in::<T>(index, addr); 432 {
433 // ep_in_len is written when actually transmitting packets.
434 btable::write_in_tx::<T>(index, addr);
435
436 if ep_type == EndpointType::Isochronous {
437 btable::write_in_rx::<T>(index, addr);
438 }
439 }
440
441 #[cfg(any(usbram_32_2048, usbram_32_1024))]
442 {
443 btable::write_in_len_tx::<T>(index, addr, 0);
444
445 if ep_type == EndpointType::Isochronous {
446 btable::write_in_len_rx::<T>(index, addr, 0);
447 }
448 }
370 449
371 EndpointBuffer { 450 EndpointBuffer {
372 addr, 451 addr,
@@ -587,24 +666,27 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
587 } 666 }
588 667
589 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { 668 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
590 trace!("set_enabled {:x} {}", ep_addr, enabled); 669 trace!("set_enabled {:?} {}", ep_addr, enabled);
591 // This can race, so do a retry loop. 670 // This can race, so do a retry loop.
592 let reg = T::regs().epr(ep_addr.index() as _); 671 let epr = T::regs().epr(ep_addr.index() as _);
593 trace!("EPR before: {:04x}", reg.read().0); 672 trace!("EPR before: {:04x}", epr.read().0);
594 match ep_addr.direction() { 673 match ep_addr.direction() {
595 Direction::In => { 674 Direction::In => {
596 loop { 675 loop {
597 let want_stat = match enabled { 676 let want_stat = match enabled {
598 false => Stat::DISABLED, 677 false => Stat::DISABLED,
599 true => Stat::NAK, 678 true => match epr.read().ep_type() {
679 EpType::ISO => Stat::VALID,
680 _ => Stat::NAK,
681 },
600 }; 682 };
601 let r = reg.read(); 683 let r = epr.read();
602 if r.stat_tx() == want_stat { 684 if r.stat_tx() == want_stat {
603 break; 685 break;
604 } 686 }
605 let mut w = invariant(r); 687 let mut w = invariant(r);
606 w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits())); 688 w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
607 reg.write_value(w); 689 epr.write_value(w);
608 } 690 }
609 EP_IN_WAKERS[ep_addr.index()].wake(); 691 EP_IN_WAKERS[ep_addr.index()].wake();
610 } 692 }
@@ -614,18 +696,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
614 false => Stat::DISABLED, 696 false => Stat::DISABLED,
615 true => Stat::VALID, 697 true => Stat::VALID,
616 }; 698 };
617 let r = reg.read(); 699 let r = epr.read();
618 if r.stat_rx() == want_stat { 700 if r.stat_rx() == want_stat {
619 break; 701 break;
620 } 702 }
621 let mut w = invariant(r); 703 let mut w = invariant(r);
622 w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits())); 704 w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
623 reg.write_value(w); 705 epr.write_value(w);
624 } 706 }
625 EP_OUT_WAKERS[ep_addr.index()].wake(); 707 EP_OUT_WAKERS[ep_addr.index()].wake();
626 } 708 }
627 } 709 }
628 trace!("EPR after: {:04x}", reg.read().0); 710 trace!("EPR after: {:04x}", epr.read().0);
629 } 711 }
630 712
631 async fn enable(&mut self) {} 713 async fn enable(&mut self) {}
@@ -656,6 +738,19 @@ impl Dir for Out {
656 } 738 }
657} 739}
658 740
741/// Selects the packet buffer.
742///
743/// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same
744/// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve
745/// two directions at the same time.
746#[derive(Clone, Copy, Debug)]
747enum PacketBuffer {
748 /// The RX buffer - must be used for single-buffered OUT endpoints
749 Rx,
750 /// The TX buffer - must be used for single-buffered IN endpoints
751 Tx,
752}
753
659/// USB endpoint. 754/// USB endpoint.
660pub struct Endpoint<'d, T: Instance, D> { 755pub struct Endpoint<'d, T: Instance, D> {
661 _phantom: PhantomData<(&'d mut T, D)>, 756 _phantom: PhantomData<(&'d mut T, D)>,
@@ -664,15 +759,46 @@ pub struct Endpoint<'d, T: Instance, D> {
664} 759}
665 760
666impl<'d, T: Instance, D> Endpoint<'d, T, D> { 761impl<'d, T: Instance, D> Endpoint<'d, T, D> {
667 fn write_data(&mut self, buf: &[u8]) { 762 /// Write to a double-buffered endpoint.
763 ///
764 /// For double-buffered endpoints, the data buffers overlap, but we still need to write to the right counter field.
765 /// The DTOG_TX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in
766 /// which the next transmit packet will be stored, so we need to write the counter of the OTHER buffer, which is
767 /// where the last transmitted packet was stored.
768 fn write_data_double_buffered(&mut self, buf: &[u8], packet_buffer: PacketBuffer) {
668 let index = self.info.addr.index(); 769 let index = self.info.addr.index();
669 self.buf.write(buf); 770 self.buf.write(buf);
670 btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _); 771
772 match packet_buffer {
773 PacketBuffer::Rx => btable::write_in_len_rx::<T>(index, self.buf.addr, buf.len() as _),
774 PacketBuffer::Tx => btable::write_in_len_tx::<T>(index, self.buf.addr, buf.len() as _),
775 }
671 } 776 }
672 777
673 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 778 /// Write to a single-buffered endpoint.
779 fn write_data(&mut self, buf: &[u8]) {
780 self.write_data_double_buffered(buf, PacketBuffer::Tx);
781 }
782
783 /// Read from a double-buffered endpoint.
784 ///
785 /// For double-buffered endpoints, the data buffers overlap, but we still need to read from the right counter field.
786 /// The DTOG_RX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in
787 /// which the next received packet will be stored, so we need to read the counter of the OTHER buffer, which is
788 /// where the last received packet was stored.
789 fn read_data_double_buffered(
790 &mut self,
791 buf: &mut [u8],
792 packet_buffer: PacketBuffer,
793 ) -> Result<usize, EndpointError> {
674 let index = self.info.addr.index(); 794 let index = self.info.addr.index();
675 let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF; 795
796 let rx_len = match packet_buffer {
797 PacketBuffer::Rx => btable::read_out_len_rx::<T>(index),
798 PacketBuffer::Tx => btable::read_out_len_tx::<T>(index),
799 } as usize
800 & 0x3FF;
801
676 trace!("READ DONE, rx_len = {}", rx_len); 802 trace!("READ DONE, rx_len = {}", rx_len);
677 if rx_len > buf.len() { 803 if rx_len > buf.len() {
678 return Err(EndpointError::BufferOverflow); 804 return Err(EndpointError::BufferOverflow);
@@ -680,6 +806,11 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
680 self.buf.read(&mut buf[..rx_len]); 806 self.buf.read(&mut buf[..rx_len]);
681 Ok(rx_len) 807 Ok(rx_len)
682 } 808 }
809
810 /// Read from a single-buffered endpoint.
811 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
812 self.read_data_double_buffered(buf, PacketBuffer::Rx)
813 }
683} 814}
684 815
685impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { 816impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
@@ -734,29 +865,65 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
734 EP_OUT_WAKERS[index].register(cx.waker()); 865 EP_OUT_WAKERS[index].register(cx.waker());
735 let regs = T::regs(); 866 let regs = T::regs();
736 let stat = regs.epr(index).read().stat_rx(); 867 let stat = regs.epr(index).read().stat_rx();
737 if matches!(stat, Stat::NAK | Stat::DISABLED) { 868 if self.info.ep_type == EndpointType::Isochronous {
738 Poll::Ready(stat) 869 // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet.
870 // Therefore, this instead waits until the `CTR` interrupt was triggered.
871 if matches!(stat, Stat::DISABLED) || RX_COMPLETE[index].load(Ordering::Relaxed) {
872 assert!(matches!(stat, Stat::VALID | Stat::DISABLED));
873 Poll::Ready(stat)
874 } else {
875 Poll::Pending
876 }
739 } else { 877 } else {
740 Poll::Pending 878 if matches!(stat, Stat::NAK | Stat::DISABLED) {
879 Poll::Ready(stat)
880 } else {
881 Poll::Pending
882 }
741 } 883 }
742 }) 884 })
743 .await; 885 .await;
744 886
887 // Errata for STM32H5, 2.20.1:
888 // During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
889 // have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
890 //
891 // Workaround:
892 // Software should ensure that a small delay is included before accessing the SRAM contents. This delay should be
893 // 800 ns in Full Speed mode and 6.4 μs in Low Speed mode.
894 #[cfg(stm32h5)]
895 embassy_time::block_for(embassy_time::Duration::from_nanos(800));
896
897 RX_COMPLETE[index].store(false, Ordering::Relaxed);
898
745 if stat == Stat::DISABLED { 899 if stat == Stat::DISABLED {
746 return Err(EndpointError::Disabled); 900 return Err(EndpointError::Disabled);
747 } 901 }
748 902
749 let rx_len = self.read_data(buf)?;
750
751 let regs = T::regs(); 903 let regs = T::regs();
752 regs.epr(index).write(|w| { 904
753 w.set_ep_type(convert_type(self.info.ep_type)); 905 let rx_len = if self.info.ep_type == EndpointType::Isochronous {
754 w.set_ea(self.info.addr.index() as _); 906 // Find the buffer, which is currently in use. Read from the OTHER buffer.
755 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); 907 let packet_buffer = if regs.epr(index).read().dtog_rx() {
756 w.set_stat_tx(Stat::from_bits(0)); 908 PacketBuffer::Tx
757 w.set_ctr_rx(true); // don't clear 909 } else {
758 w.set_ctr_tx(true); // don't clear 910 PacketBuffer::Rx
759 }); 911 };
912 self.read_data_double_buffered(buf, packet_buffer)?
913 } else {
914 let len = self.read_data(buf)?;
915
916 regs.epr(index).write(|w| {
917 w.set_ep_type(convert_type(self.info.ep_type));
918 w.set_ea(self.info.addr.index() as _);
919 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
920 w.set_stat_tx(Stat::from_bits(0));
921 w.set_ctr_rx(true); // don't clear
922 w.set_ctr_tx(true); // don't clear
923 });
924
925 len
926 };
760 trace!("READ OK, rx_len = {}", rx_len); 927 trace!("READ OK, rx_len = {}", rx_len);
761 928
762 Ok(rx_len) 929 Ok(rx_len)
@@ -768,18 +935,41 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
768 if buf.len() > self.info.max_packet_size as usize { 935 if buf.len() > self.info.max_packet_size as usize {
769 return Err(EndpointError::BufferOverflow); 936 return Err(EndpointError::BufferOverflow);
770 } 937 }
938 trace!("WRITE WAITING, buf.len() = {}", buf.len());
771 939
940 let regs = T::regs();
772 let index = self.info.addr.index(); 941 let index = self.info.addr.index();
773 942
774 trace!("WRITE WAITING"); 943 if self.info.ep_type == EndpointType::Isochronous {
944 // Find the buffer, which is currently in use. Write to the OTHER buffer.
945 let packet_buffer = if regs.epr(index).read().dtog_tx() {
946 PacketBuffer::Rx
947 } else {
948 PacketBuffer::Tx
949 };
950
951 self.write_data_double_buffered(buf, packet_buffer);
952 }
953
775 let stat = poll_fn(|cx| { 954 let stat = poll_fn(|cx| {
776 EP_IN_WAKERS[index].register(cx.waker()); 955 EP_IN_WAKERS[index].register(cx.waker());
777 let regs = T::regs(); 956 let regs = T::regs();
778 let stat = regs.epr(index).read().stat_tx(); 957 let stat = regs.epr(index).read().stat_tx();
779 if matches!(stat, Stat::NAK | Stat::DISABLED) { 958 if self.info.ep_type == EndpointType::Isochronous {
780 Poll::Ready(stat) 959 // The isochronous endpoint does not change its `STAT_TX` field to `NAK` after sending a packet.
960 // Therefore, this instead waits until the `CTR` interrupt was triggered.
961 if matches!(stat, Stat::DISABLED) || !TX_PENDING[index].load(Ordering::Relaxed) {
962 assert!(matches!(stat, Stat::VALID | Stat::DISABLED));
963 Poll::Ready(stat)
964 } else {
965 Poll::Pending
966 }
781 } else { 967 } else {
782 Poll::Pending 968 if matches!(stat, Stat::NAK | Stat::DISABLED) {
969 Poll::Ready(stat)
970 } else {
971 Poll::Pending
972 }
783 } 973 }
784 }) 974 })
785 .await; 975 .await;
@@ -788,18 +978,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
788 return Err(EndpointError::Disabled); 978 return Err(EndpointError::Disabled);
789 } 979 }
790 980
791 self.write_data(buf); 981 if self.info.ep_type != EndpointType::Isochronous {
792 982 self.write_data(buf);
793 let regs = T::regs();
794 regs.epr(index).write(|w| {
795 w.set_ep_type(convert_type(self.info.ep_type));
796 w.set_ea(self.info.addr.index() as _);
797 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
798 w.set_stat_rx(Stat::from_bits(0));
799 w.set_ctr_rx(true); // don't clear
800 w.set_ctr_tx(true); // don't clear
801 });
802 983
984 regs.epr(index).write(|w| {
985 w.set_ep_type(convert_type(self.info.ep_type));
986 w.set_ea(self.info.addr.index() as _);
987 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
988 w.set_stat_rx(Stat::from_bits(0));
989 w.set_ctr_rx(true); // don't clear
990 w.set_ctr_tx(true); // don't clear
991 });
992 }
993 TX_PENDING[index].store(true, Ordering::Relaxed);
803 trace!("WRITE OK"); 994 trace!("WRITE OK");
804 995
805 Ok(()) 996 Ok(())
@@ -1044,7 +1235,7 @@ trait SealedInstance {
1044 1235
1045/// USB instance trait. 1236/// USB instance trait.
1046#[allow(private_bounds)] 1237#[allow(private_bounds)]
1047pub trait Instance: SealedInstance + RccPeripheral + 'static { 1238pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {
1048 /// Interrupt for this USB instance. 1239 /// Interrupt for this USB instance.
1049 type Interrupt: interrupt::typelevel::Interrupt; 1240 type Interrupt: interrupt::typelevel::Interrupt;
1050} 1241}
@@ -1052,6 +1243,7 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static {
1052// Internal PHY pins 1243// Internal PHY pins
1053pin_trait!(DpPin, Instance); 1244pin_trait!(DpPin, Instance);
1054pin_trait!(DmPin, Instance); 1245pin_trait!(DmPin, Instance);
1246pin_trait!(SofPin, Instance);
1055 1247
1056foreach_interrupt!( 1248foreach_interrupt!(
1057 ($inst:ident, usb, $block:ident, LP, $irq:ident) => { 1249 ($inst:ident, usb, $block:ident, LP, $irq:ident) => {
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index ab21c4b6b..fb5c3d930 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -1,10 +1,11 @@
1//! Watchdog Timer (IWDG, WWDG) 1//! Watchdog Timer (IWDG, WWDG)
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3 3
4use embassy_hal_internal::{into_ref, Peripheral}; 4use embassy_hal_internal::PeripheralType;
5use stm32_metapac::iwdg::vals::{Key, Pr}; 5use stm32_metapac::iwdg::vals::{Key, Pr};
6 6
7use crate::rcc::LSI_FREQ; 7use crate::rcc::LSI_FREQ;
8use crate::Peri;
8 9
9/// Independent watchdog (IWDG) driver. 10/// Independent watchdog (IWDG) driver.
10pub struct IndependentWatchdog<'d, T: Instance> { 11pub struct IndependentWatchdog<'d, T: Instance> {
@@ -29,9 +30,7 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
29 /// 30 ///
30 /// [Self] has to be started with [Self::unleash()]. 31 /// [Self] has to be started with [Self::unleash()].
31 /// Once timer expires, MCU will be reset. To prevent this, timer must be reloaded by repeatedly calling [Self::pet()] within timeout interval. 32 /// Once timer expires, MCU will be reset. To prevent this, timer must be reloaded by repeatedly calling [Self::pet()] within timeout interval.
32 pub fn new(_instance: impl Peripheral<P = T> + 'd, timeout_us: u32) -> Self { 33 pub fn new(_instance: Peri<'d, T>, timeout_us: u32) -> Self {
33 into_ref!(_instance);
34
35 // Find lowest prescaler value, which makes watchdog period longer or equal to timeout. 34 // Find lowest prescaler value, which makes watchdog period longer or equal to timeout.
36 // This iterates from 4 (2^2) to 256 (2^8). 35 // This iterates from 4 (2^2) to 256 (2^8).
37 let psc_power = unwrap!((2..=8).find(|psc_power| { 36 let psc_power = unwrap!((2..=8).find(|psc_power| {
@@ -86,7 +85,7 @@ trait SealedInstance {
86 85
87/// IWDG instance trait. 86/// IWDG instance trait.
88#[allow(private_bounds)] 87#[allow(private_bounds)]
89pub trait Instance: SealedInstance {} 88pub trait Instance: SealedInstance + PeripheralType {}
90 89
91foreach_peripheral!( 90foreach_peripheral!(
92 (iwdg, $inst:ident) => { 91 (iwdg, $inst:ident) => {
diff --git a/embassy-stm32/src/xspi/enums.rs b/embassy-stm32/src/xspi/enums.rs
new file mode 100644
index 000000000..c96641180
--- /dev/null
+++ b/embassy-stm32/src/xspi/enums.rs
@@ -0,0 +1,364 @@
1//! Enums used in Xspi configuration.
2#[derive(Copy, Clone)]
3pub(crate) enum XspiMode {
4 IndirectWrite,
5 IndirectRead,
6 #[expect(dead_code)]
7 AutoPolling,
8 #[expect(dead_code)]
9 MemoryMapped,
10}
11
12impl Into<u8> for XspiMode {
13 fn into(self) -> u8 {
14 match self {
15 XspiMode::IndirectWrite => 0b00,
16 XspiMode::IndirectRead => 0b01,
17 XspiMode::AutoPolling => 0b10,
18 XspiMode::MemoryMapped => 0b11,
19 }
20 }
21}
22
23/// Xspi lane width
24#[derive(Copy, Clone)]
25pub enum XspiWidth {
26 /// None
27 NONE,
28 /// Single lane
29 SING,
30 /// Dual lanes
31 DUAL,
32 /// Quad lanes
33 QUAD,
34 /// Eight lanes
35 OCTO,
36}
37
38impl Into<u8> for XspiWidth {
39 fn into(self) -> u8 {
40 match self {
41 XspiWidth::NONE => 0b00,
42 XspiWidth::SING => 0b01,
43 XspiWidth::DUAL => 0b10,
44 XspiWidth::QUAD => 0b11,
45 XspiWidth::OCTO => 0b100,
46 }
47 }
48}
49
50/// Wrap Size
51#[allow(missing_docs)]
52#[derive(Copy, Clone)]
53pub enum WrapSize {
54 None,
55 _16Bytes,
56 _32Bytes,
57 _64Bytes,
58 _128Bytes,
59}
60
61impl Into<u8> for WrapSize {
62 fn into(self) -> u8 {
63 match self {
64 WrapSize::None => 0x00,
65 WrapSize::_16Bytes => 0x02,
66 WrapSize::_32Bytes => 0x03,
67 WrapSize::_64Bytes => 0x04,
68 WrapSize::_128Bytes => 0x05,
69 }
70 }
71}
72
73/// Memory Type
74#[allow(missing_docs)]
75#[derive(Copy, Clone)]
76pub enum MemoryType {
77 Micron,
78 Macronix,
79 Standard,
80 MacronixRam,
81 HyperBusMemory,
82 HyperBusRegister,
83}
84
85impl Into<u8> for MemoryType {
86 fn into(self) -> u8 {
87 match self {
88 MemoryType::Micron => 0x00,
89 MemoryType::Macronix => 0x01,
90 MemoryType::Standard => 0x02,
91 MemoryType::MacronixRam => 0x03,
92 MemoryType::HyperBusMemory => 0x04,
93 MemoryType::HyperBusRegister => 0x04,
94 }
95 }
96}
97
98/// Xspi memory size.
99#[allow(missing_docs)]
100#[derive(Copy, Clone)]
101pub enum MemorySize {
102 _1KiB,
103 _2KiB,
104 _4KiB,
105 _8KiB,
106 _16KiB,
107 _32KiB,
108 _64KiB,
109 _128KiB,
110 _256KiB,
111 _512KiB,
112 _1MiB,
113 _2MiB,
114 _4MiB,
115 _8MiB,
116 _16MiB,
117 _32MiB,
118 _64MiB,
119 _128MiB,
120 _256MiB,
121 _512MiB,
122 _1GiB,
123 _2GiB,
124 _4GiB,
125 Other(u8),
126}
127
128impl Into<u8> for MemorySize {
129 fn into(self) -> u8 {
130 match self {
131 MemorySize::_1KiB => 9,
132 MemorySize::_2KiB => 10,
133 MemorySize::_4KiB => 11,
134 MemorySize::_8KiB => 12,
135 MemorySize::_16KiB => 13,
136 MemorySize::_32KiB => 14,
137 MemorySize::_64KiB => 15,
138 MemorySize::_128KiB => 16,
139 MemorySize::_256KiB => 17,
140 MemorySize::_512KiB => 18,
141 MemorySize::_1MiB => 19,
142 MemorySize::_2MiB => 20,
143 MemorySize::_4MiB => 21,
144 MemorySize::_8MiB => 22,
145 MemorySize::_16MiB => 23,
146 MemorySize::_32MiB => 24,
147 MemorySize::_64MiB => 25,
148 MemorySize::_128MiB => 26,
149 MemorySize::_256MiB => 27,
150 MemorySize::_512MiB => 28,
151 MemorySize::_1GiB => 29,
152 MemorySize::_2GiB => 30,
153 MemorySize::_4GiB => 31,
154 MemorySize::Other(val) => val,
155 }
156 }
157}
158
159/// Xspi Address size
160#[derive(Copy, Clone)]
161pub enum AddressSize {
162 /// 8-bit address
163 _8bit,
164 /// 16-bit address
165 _16bit,
166 /// 24-bit address
167 _24bit,
168 /// 32-bit address
169 _32bit,
170}
171
172impl Into<u8> for AddressSize {
173 fn into(self) -> u8 {
174 match self {
175 AddressSize::_8bit => 0b00,
176 AddressSize::_16bit => 0b01,
177 AddressSize::_24bit => 0b10,
178 AddressSize::_32bit => 0b11,
179 }
180 }
181}
182
183/// Time the Chip Select line stays high.
184#[allow(missing_docs)]
185#[derive(Copy, Clone)]
186pub enum ChipSelectHighTime {
187 _1Cycle,
188 _2Cycle,
189 _3Cycle,
190 _4Cycle,
191 _5Cycle,
192 _6Cycle,
193 _7Cycle,
194 _8Cycle,
195}
196
197impl Into<u8> for ChipSelectHighTime {
198 fn into(self) -> u8 {
199 match self {
200 ChipSelectHighTime::_1Cycle => 0,
201 ChipSelectHighTime::_2Cycle => 1,
202 ChipSelectHighTime::_3Cycle => 2,
203 ChipSelectHighTime::_4Cycle => 3,
204 ChipSelectHighTime::_5Cycle => 4,
205 ChipSelectHighTime::_6Cycle => 5,
206 ChipSelectHighTime::_7Cycle => 6,
207 ChipSelectHighTime::_8Cycle => 7,
208 }
209 }
210}
211
212/// FIFO threshold.
213#[allow(missing_docs)]
214#[derive(Copy, Clone)]
215pub enum FIFOThresholdLevel {
216 _1Bytes,
217 _2Bytes,
218 _3Bytes,
219 _4Bytes,
220 _5Bytes,
221 _6Bytes,
222 _7Bytes,
223 _8Bytes,
224 _9Bytes,
225 _10Bytes,
226 _11Bytes,
227 _12Bytes,
228 _13Bytes,
229 _14Bytes,
230 _15Bytes,
231 _16Bytes,
232 _17Bytes,
233 _18Bytes,
234 _19Bytes,
235 _20Bytes,
236 _21Bytes,
237 _22Bytes,
238 _23Bytes,
239 _24Bytes,
240 _25Bytes,
241 _26Bytes,
242 _27Bytes,
243 _28Bytes,
244 _29Bytes,
245 _30Bytes,
246 _31Bytes,
247 _32Bytes,
248}
249
250impl Into<u8> for FIFOThresholdLevel {
251 fn into(self) -> u8 {
252 match self {
253 FIFOThresholdLevel::_1Bytes => 0,
254 FIFOThresholdLevel::_2Bytes => 1,
255 FIFOThresholdLevel::_3Bytes => 2,
256 FIFOThresholdLevel::_4Bytes => 3,
257 FIFOThresholdLevel::_5Bytes => 4,
258 FIFOThresholdLevel::_6Bytes => 5,
259 FIFOThresholdLevel::_7Bytes => 6,
260 FIFOThresholdLevel::_8Bytes => 7,
261 FIFOThresholdLevel::_9Bytes => 8,
262 FIFOThresholdLevel::_10Bytes => 9,
263 FIFOThresholdLevel::_11Bytes => 10,
264 FIFOThresholdLevel::_12Bytes => 11,
265 FIFOThresholdLevel::_13Bytes => 12,
266 FIFOThresholdLevel::_14Bytes => 13,
267 FIFOThresholdLevel::_15Bytes => 14,
268 FIFOThresholdLevel::_16Bytes => 15,
269 FIFOThresholdLevel::_17Bytes => 16,
270 FIFOThresholdLevel::_18Bytes => 17,
271 FIFOThresholdLevel::_19Bytes => 18,
272 FIFOThresholdLevel::_20Bytes => 19,
273 FIFOThresholdLevel::_21Bytes => 20,
274 FIFOThresholdLevel::_22Bytes => 21,
275 FIFOThresholdLevel::_23Bytes => 22,
276 FIFOThresholdLevel::_24Bytes => 23,
277 FIFOThresholdLevel::_25Bytes => 24,
278 FIFOThresholdLevel::_26Bytes => 25,
279 FIFOThresholdLevel::_27Bytes => 26,
280 FIFOThresholdLevel::_28Bytes => 27,
281 FIFOThresholdLevel::_29Bytes => 28,
282 FIFOThresholdLevel::_30Bytes => 29,
283 FIFOThresholdLevel::_31Bytes => 30,
284 FIFOThresholdLevel::_32Bytes => 31,
285 }
286 }
287}
288
289/// Dummy cycle count
290#[allow(missing_docs)]
291#[derive(Copy, Clone)]
292pub enum DummyCycles {
293 _0,
294 _1,
295 _2,
296 _3,
297 _4,
298 _5,
299 _6,
300 _7,
301 _8,
302 _9,
303 _10,
304 _11,
305 _12,
306 _13,
307 _14,
308 _15,
309 _16,
310 _17,
311 _18,
312 _19,
313 _20,
314 _21,
315 _22,
316 _23,
317 _24,
318 _25,
319 _26,
320 _27,
321 _28,
322 _29,
323 _30,
324 _31,
325}
326
327impl Into<u8> for DummyCycles {
328 fn into(self) -> u8 {
329 match self {
330 DummyCycles::_0 => 0,
331 DummyCycles::_1 => 1,
332 DummyCycles::_2 => 2,
333 DummyCycles::_3 => 3,
334 DummyCycles::_4 => 4,
335 DummyCycles::_5 => 5,
336 DummyCycles::_6 => 6,
337 DummyCycles::_7 => 7,
338 DummyCycles::_8 => 8,
339 DummyCycles::_9 => 9,
340 DummyCycles::_10 => 10,
341 DummyCycles::_11 => 11,
342 DummyCycles::_12 => 12,
343 DummyCycles::_13 => 13,
344 DummyCycles::_14 => 14,
345 DummyCycles::_15 => 15,
346 DummyCycles::_16 => 16,
347 DummyCycles::_17 => 17,
348 DummyCycles::_18 => 18,
349 DummyCycles::_19 => 19,
350 DummyCycles::_20 => 20,
351 DummyCycles::_21 => 21,
352 DummyCycles::_22 => 22,
353 DummyCycles::_23 => 23,
354 DummyCycles::_24 => 24,
355 DummyCycles::_25 => 25,
356 DummyCycles::_26 => 26,
357 DummyCycles::_27 => 27,
358 DummyCycles::_28 => 28,
359 DummyCycles::_29 => 29,
360 DummyCycles::_30 => 30,
361 DummyCycles::_31 => 31,
362 }
363 }
364}
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
new file mode 100644
index 000000000..44c10b961
--- /dev/null
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -0,0 +1,1425 @@
1//! XSPI Serial Peripheral Interface
2//!
3
4#![macro_use]
5
6pub mod enums;
7
8use core::marker::PhantomData;
9
10use embassy_embedded_hal::{GetConfig, SetConfig};
11use embassy_hal_internal::PeripheralType;
12pub use enums::*;
13
14use crate::dma::{word, ChannelAndRequest};
15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
16use crate::mode::{Async, Blocking, Mode as PeriMode};
17use crate::pac::xspi::vals::*;
18use crate::pac::xspi::Xspi as Regs;
19#[cfg(xspim_v1)]
20use crate::pac::xspim::Xspim;
21use crate::rcc::{self, RccPeripheral};
22use crate::{peripherals, Peri};
23
24/// XPSI driver config.
25#[derive(Clone, Copy)]
26pub struct Config {
27 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
28 /// or space is available in the FIFO
29 pub fifo_threshold: FIFOThresholdLevel,
30 /// Indicates the type of external device connected
31 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
32 /// Defines the size of the external device connected to the XSPI corresponding
33 /// to the number of address bits required to access the device
34 pub device_size: MemorySize,
35 /// Sets the minimum number of clock cycles that the chip select signal must be held high
36 /// between commands
37 pub chip_select_high_time: ChipSelectHighTime,
38 /// Enables the free running clock
39 pub free_running_clock: bool,
40 /// Sets the clock level when the device is not selected
41 pub clock_mode: bool,
42 /// Indicates the wrap size corresponding to the external device configuration
43 pub wrap_size: WrapSize,
44 /// Specified the prescaler factor used for generating the external clock based
45 /// on the AHB clock. 0 = Fkernel, 1 = Fkernel/2, 2 = Fkernel/3 etc.
46 pub clock_prescaler: u8,
47 /// Allows the delay of 1/2 cycle the data sampling to account for external
48 /// signal delays
49 pub sample_shifting: bool,
50 /// Allows hold to 1/4 cycle the data
51 pub delay_hold_quarter_cycle: bool,
52 /// Enables the transaction boundary feature and defines the boundary to release
53 /// the chip select
54 pub chip_select_boundary: u8,
55 /// Enables communication regulation feature. Chip select is released when the other
56 /// XSpi requests access to the bus
57 pub max_transfer: u8,
58 /// Enables the refresh feature, chip select is released every refresh + 1 clock cycles
59 pub refresh: u32,
60}
61
62impl Default for Config {
63 fn default() -> Self {
64 Self {
65 fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity
66 memory_type: MemoryType::Micron,
67 device_size: MemorySize::Other(0),
68 chip_select_high_time: ChipSelectHighTime::_5Cycle,
69 free_running_clock: false,
70 clock_mode: false,
71 wrap_size: WrapSize::None,
72 clock_prescaler: 0,
73 sample_shifting: false,
74 delay_hold_quarter_cycle: false,
75 chip_select_boundary: 0, // Acceptable range 0 to 31
76 max_transfer: 0,
77 refresh: 0,
78 }
79 }
80}
81
82/// XSPI transfer configuration.
83pub struct TransferConfig {
84 /// Instruction width (IMODE)
85 pub iwidth: XspiWidth,
86 /// Instruction Id
87 pub instruction: Option<u32>,
88 /// Number of Instruction Bytes
89 pub isize: AddressSize,
90 /// Instruction Double Transfer rate enable
91 pub idtr: bool,
92
93 /// Address width (ADMODE)
94 pub adwidth: XspiWidth,
95 /// Device memory address
96 pub address: Option<u32>,
97 /// Number of Address Bytes
98 pub adsize: AddressSize,
99 /// Address Double Transfer rate enable
100 pub addtr: bool,
101
102 /// Alternate bytes width (ABMODE)
103 pub abwidth: XspiWidth,
104 /// Alternate Bytes
105 pub alternate_bytes: Option<u32>,
106 /// Number of Alternate Bytes
107 pub absize: AddressSize,
108 /// Alternate Bytes Double Transfer rate enable
109 pub abdtr: bool,
110
111 /// Data width (DMODE)
112 pub dwidth: XspiWidth,
113 /// Data buffer
114 pub ddtr: bool,
115
116 /// Number of dummy cycles (DCYC)
117 pub dummy: DummyCycles,
118}
119
120impl Default for TransferConfig {
121 fn default() -> Self {
122 Self {
123 iwidth: XspiWidth::NONE,
124 instruction: None,
125 isize: AddressSize::_8bit,
126 idtr: false,
127
128 adwidth: XspiWidth::NONE,
129 address: None,
130 adsize: AddressSize::_8bit,
131 addtr: false,
132
133 abwidth: XspiWidth::NONE,
134 alternate_bytes: None,
135 absize: AddressSize::_8bit,
136 abdtr: false,
137
138 dwidth: XspiWidth::NONE,
139 ddtr: false,
140
141 dummy: DummyCycles::_0,
142 }
143 }
144}
145
146/// Error used for Xspi implementation
147#[derive(Debug)]
148#[cfg_attr(feature = "defmt", derive(defmt::Format))]
149pub enum XspiError {
150 /// Peripheral configuration is invalid
151 InvalidConfiguration,
152 /// Operation configuration is invalid
153 InvalidCommand,
154 /// Size zero buffer passed to instruction
155 EmptyBuffer,
156}
157
158/// XSPI driver.
159pub struct Xspi<'d, T: Instance, M: PeriMode> {
160 _peri: Peri<'d, T>,
161 clk: Option<Peri<'d, AnyPin>>,
162 d0: Option<Peri<'d, AnyPin>>,
163 d1: Option<Peri<'d, AnyPin>>,
164 d2: Option<Peri<'d, AnyPin>>,
165 d3: Option<Peri<'d, AnyPin>>,
166 d4: Option<Peri<'d, AnyPin>>,
167 d5: Option<Peri<'d, AnyPin>>,
168 d6: Option<Peri<'d, AnyPin>>,
169 d7: Option<Peri<'d, AnyPin>>,
170 d8: Option<Peri<'d, AnyPin>>,
171 d9: Option<Peri<'d, AnyPin>>,
172 d10: Option<Peri<'d, AnyPin>>,
173 d11: Option<Peri<'d, AnyPin>>,
174 d12: Option<Peri<'d, AnyPin>>,
175 d13: Option<Peri<'d, AnyPin>>,
176 d14: Option<Peri<'d, AnyPin>>,
177 d15: Option<Peri<'d, AnyPin>>,
178 ncs: Option<Peri<'d, AnyPin>>,
179 // TODO: allow switching between multiple chips
180 ncs_alt: Option<Peri<'d, AnyPin>>,
181 // false if ncs == NCS1, true if ncs == NCS2
182 // (ncs_alt will be the opposite to ncs).
183 _cssel_swap: bool,
184 dqs0: Option<Peri<'d, AnyPin>>,
185 dqs1: Option<Peri<'d, AnyPin>>,
186 dma: Option<ChannelAndRequest<'d>>,
187 _phantom: PhantomData<M>,
188 config: Config,
189 width: XspiWidth,
190}
191
192impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
193 /// Enter memory mode.
194 /// The Input `read_config` is used to configure the read operation in memory mode
195 pub fn enable_memory_mapped_mode(
196 &mut self,
197 read_config: TransferConfig,
198 write_config: TransferConfig,
199 ) -> Result<(), XspiError> {
200 // Use configure command to set read config
201 self.configure_command(&read_config, None)?;
202
203 let reg = T::REGS;
204 while reg.sr().read().busy() {}
205
206 reg.ccr().modify(|r| {
207 r.set_dqse(false);
208 });
209
210 // Set wrting configurations, there are separate registers for write configurations in memory mapped mode
211 reg.wccr().modify(|w| {
212 w.set_imode(WccrImode::from_bits(write_config.iwidth.into()));
213 w.set_idtr(write_config.idtr);
214 w.set_isize(WccrIsize::from_bits(write_config.isize.into()));
215
216 w.set_admode(WccrAdmode::from_bits(write_config.adwidth.into()));
217 w.set_addtr(write_config.addtr);
218 w.set_adsize(WccrAdsize::from_bits(write_config.adsize.into()));
219
220 w.set_dmode(WccrDmode::from_bits(write_config.dwidth.into()));
221 w.set_ddtr(write_config.ddtr);
222
223 w.set_abmode(WccrAbmode::from_bits(write_config.abwidth.into()));
224 w.set_dqse(true);
225 });
226
227 reg.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into()));
228
229 // Enable memory mapped mode
230 reg.cr().modify(|r| {
231 r.set_fmode(Fmode::B_0X3);
232 r.set_tcen(false);
233 });
234 Ok(())
235 }
236
237 /// Quit from memory mapped mode
238 pub fn disable_memory_mapped_mode(&mut self) {
239 let reg = T::REGS;
240
241 reg.cr().modify(|r| {
242 r.set_fmode(Fmode::B_0X0);
243 r.set_abort(true);
244 r.set_dmaen(false);
245 r.set_en(false);
246 });
247
248 // Clear transfer complete flag
249 reg.fcr().write(|w| w.set_ctcf(true));
250
251 // Re-enable ospi
252 reg.cr().modify(|r| {
253 r.set_en(true);
254 });
255 }
256
257 fn new_inner(
258 peri: Peri<'d, T>,
259 d0: Option<Peri<'d, AnyPin>>,
260 d1: Option<Peri<'d, AnyPin>>,
261 d2: Option<Peri<'d, AnyPin>>,
262 d3: Option<Peri<'d, AnyPin>>,
263 d4: Option<Peri<'d, AnyPin>>,
264 d5: Option<Peri<'d, AnyPin>>,
265 d6: Option<Peri<'d, AnyPin>>,
266 d7: Option<Peri<'d, AnyPin>>,
267 d8: Option<Peri<'d, AnyPin>>,
268 d9: Option<Peri<'d, AnyPin>>,
269 d10: Option<Peri<'d, AnyPin>>,
270 d11: Option<Peri<'d, AnyPin>>,
271 d12: Option<Peri<'d, AnyPin>>,
272 d13: Option<Peri<'d, AnyPin>>,
273 d14: Option<Peri<'d, AnyPin>>,
274 d15: Option<Peri<'d, AnyPin>>,
275 clk: Option<Peri<'d, AnyPin>>,
276 ncs_cssel: u8,
277 ncs: Option<Peri<'d, AnyPin>>,
278 ncs_alt: Option<Peri<'d, AnyPin>>,
279 dqs0: Option<Peri<'d, AnyPin>>,
280 dqs1: Option<Peri<'d, AnyPin>>,
281 dma: Option<ChannelAndRequest<'d>>,
282 config: Config,
283 width: XspiWidth,
284 dual_quad: bool,
285 ) -> Self {
286 // Enable the interface
287 match T::SPI_IDX {
288 1 => crate::pac::PWR.csr2().modify(|r| r.set_en_xspim1(true)),
289 2 => crate::pac::PWR.csr2().modify(|r| r.set_en_xspim2(true)),
290 _ => unreachable!(),
291 };
292
293 #[cfg(xspim_v1)]
294 {
295 // RCC for xspim should be enabled before writing register
296 crate::pac::RCC.ahb5enr().modify(|w| w.set_iomngren(true));
297
298 // Disable XSPI peripheral first
299 T::REGS.cr().modify(|w| {
300 w.set_en(false);
301 });
302
303 // XSPI IO Manager has been enabled before
304 T::SPIM_REGS.cr().modify(|w| {
305 w.set_muxen(false);
306 w.set_req2ack_time(0xff);
307 });
308 }
309
310 // System configuration
311 rcc::enable_and_reset::<T>();
312 while T::REGS.sr().read().busy() {}
313
314 // Device configuration
315 T::REGS.dcr1().modify(|w| {
316 w.set_devsize(config.device_size.into());
317 w.set_mtyp(Mtyp::from_bits(config.memory_type.into()));
318 w.set_csht(Csht::from_bits(config.chip_select_high_time.into()));
319 w.set_frck(false);
320 w.set_ckmode(Ckmode::from_bits(config.clock_mode.into()));
321 });
322
323 T::REGS.dcr2().modify(|w| {
324 w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into()));
325 });
326
327 T::REGS.dcr3().modify(|w| {
328 w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into()));
329 #[cfg(xspi_v1)]
330 {
331 w.set_maxtran(Maxtran::from_bits(config.max_transfer.into()));
332 }
333 });
334
335 T::REGS.dcr4().modify(|w| {
336 w.set_refresh(Refresh::from_bits(config.refresh.into()));
337 });
338
339 T::REGS.cr().modify(|w| {
340 w.set_fthres(Fthres::from_bits(config.fifo_threshold.into()));
341 });
342
343 // Wait for busy flag to clear
344 while T::REGS.sr().read().busy() {}
345
346 T::REGS.dcr2().modify(|w| {
347 w.set_prescaler(config.clock_prescaler);
348 });
349
350 // Wait for busy flag to clear after changing prescaler, during calibration
351 while T::REGS.sr().read().busy() {}
352
353 T::REGS.cr().modify(|w| {
354 w.set_dmm(dual_quad);
355
356 assert!(ncs_alt.is_none(), "ncs_alt TODO");
357 let cssel = if ncs_cssel == 0 { Cssel::B_0X0 } else { Cssel::B_0X1 };
358 w.set_cssel(cssel);
359 });
360
361 T::REGS.tcr().modify(|w| {
362 w.set_sshift(config.sample_shifting);
363 w.set_dhqc(config.delay_hold_quarter_cycle);
364 });
365
366 // Enable peripheral
367 T::REGS.cr().modify(|w| {
368 w.set_en(true);
369 });
370
371 // Free running clock needs to be set after peripheral enable
372 if config.free_running_clock {
373 T::REGS.dcr1().modify(|w| {
374 w.set_frck(config.free_running_clock);
375 });
376 }
377
378 Self {
379 _peri: peri,
380 clk,
381 d0,
382 d1,
383 d2,
384 d3,
385 d4,
386 d5,
387 d6,
388 d7,
389 d8,
390 d9,
391 d10,
392 d11,
393 d12,
394 d13,
395 d14,
396 d15,
397 ncs,
398 ncs_alt,
399 _cssel_swap: ncs_cssel == 1,
400 dqs0,
401 dqs1,
402 dma,
403 _phantom: PhantomData,
404 config,
405 width,
406 }
407 }
408
409 // Function to configure the peripheral for the requested command
410 fn configure_command(&mut self, command: &TransferConfig, data_len: Option<usize>) -> Result<(), XspiError> {
411 // Check that transaction doesn't use more than hardware initialized pins
412 if <enums::XspiWidth as Into<u8>>::into(command.iwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
413 || <enums::XspiWidth as Into<u8>>::into(command.adwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
414 || <enums::XspiWidth as Into<u8>>::into(command.abwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
415 || <enums::XspiWidth as Into<u8>>::into(command.dwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
416 {
417 return Err(XspiError::InvalidCommand);
418 }
419
420 T::REGS.cr().modify(|w| {
421 w.set_fmode(0.into());
422 });
423
424 // Configure alternate bytes
425 if let Some(ab) = command.alternate_bytes {
426 T::REGS.abr().write(|v| v.set_alternate(ab));
427 T::REGS.ccr().modify(|w| {
428 w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
429 w.set_abdtr(command.abdtr);
430 w.set_absize(CcrAbsize::from_bits(command.absize.into()));
431 })
432 }
433
434 // Configure dummy cycles
435 T::REGS.tcr().modify(|w| {
436 w.set_dcyc(command.dummy.into());
437 });
438
439 // Configure data
440 if let Some(data_length) = data_len {
441 T::REGS.dlr().write(|v| {
442 v.set_dl((data_length - 1) as u32);
443 })
444 } else {
445 T::REGS.dlr().write(|v| {
446 v.set_dl((0) as u32);
447 })
448 }
449
450 // Configure instruction/address/data modes
451 T::REGS.ccr().modify(|w| {
452 w.set_imode(CcrImode::from_bits(command.iwidth.into()));
453 w.set_idtr(command.idtr);
454 w.set_isize(CcrIsize::from_bits(command.isize.into()));
455
456 w.set_admode(CcrAdmode::from_bits(command.adwidth.into()));
457 w.set_addtr(command.addtr);
458 w.set_adsize(CcrAdsize::from_bits(command.adsize.into()));
459
460 w.set_dmode(CcrDmode::from_bits(command.dwidth.into()));
461 w.set_ddtr(command.ddtr);
462 });
463
464 // Set information required to initiate transaction
465 if let Some(instruction) = command.instruction {
466 if let Some(address) = command.address {
467 T::REGS.ir().write(|v| {
468 v.set_instruction(instruction);
469 });
470
471 T::REGS.ar().write(|v| {
472 v.set_address(address);
473 });
474 } else {
475 // Double check requirements for delay hold and sample shifting
476 // if let None = command.data_len {
477 // if self.config.delay_hold_quarter_cycle && command.idtr {
478 // T::REGS.ccr().modify(|w| {
479 // w.set_ddtr(true);
480 // });
481 // }
482 // }
483
484 // warn!("instruction: {:#x}", instruction);
485 T::REGS.ir().write(|v| {
486 v.set_instruction(instruction);
487 });
488 }
489 } else {
490 if let Some(address) = command.address {
491 T::REGS.ar().write(|v| {
492 v.set_address(address);
493 });
494 } else {
495 // The only single phase transaction supported is instruction only
496 return Err(XspiError::InvalidCommand);
497 }
498 }
499
500 Ok(())
501 }
502
503 /// Function used to control or configure the target device without data transfer
504 pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), XspiError> {
505 // Wait for peripheral to be free
506 while T::REGS.sr().read().busy() {}
507
508 // Need additional validation that command configuration doesn't have data set
509 self.configure_command(command, None)?;
510
511 // Transaction initiated by setting final configuration, i.e the instruction register
512 while !T::REGS.sr().read().tcf() {}
513 T::REGS.fcr().write(|w| {
514 w.set_ctcf(true);
515 });
516
517 Ok(())
518 }
519
520 /// Blocking read with byte by byte data transfer
521 pub fn blocking_read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> {
522 if buf.is_empty() {
523 return Err(XspiError::EmptyBuffer);
524 }
525
526 // Wait for peripheral to be free
527 while T::REGS.sr().read().busy() {}
528
529 // Ensure DMA is not enabled for this transaction
530 T::REGS.cr().modify(|w| {
531 w.set_dmaen(false);
532 });
533
534 // self.configure_command(&transaction, Some(buf.len()))?;
535 self.configure_command(&transaction, Some(buf.len())).unwrap();
536
537 let current_address = T::REGS.ar().read().address();
538 let current_instruction = T::REGS.ir().read().instruction();
539
540 // For a indirect read transaction, the transaction begins when the instruction/address is set
541 T::REGS
542 .cr()
543 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
544 if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 {
545 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
546 } else {
547 T::REGS.ar().write(|v| v.set_address(current_address));
548 }
549
550 for idx in 0..buf.len() {
551 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
552 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() };
553 }
554
555 while !T::REGS.sr().read().tcf() {}
556 T::REGS.fcr().write(|v| v.set_ctcf(true));
557
558 Ok(())
559 }
560
561 /// Blocking write with byte by byte data transfer
562 pub fn blocking_write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> {
563 if buf.is_empty() {
564 return Err(XspiError::EmptyBuffer);
565 }
566
567 // Wait for peripheral to be free
568 while T::REGS.sr().read().busy() {}
569
570 T::REGS.cr().modify(|w| {
571 w.set_dmaen(false);
572 });
573
574 self.configure_command(&transaction, Some(buf.len()))?;
575
576 T::REGS
577 .cr()
578 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
579
580 for idx in 0..buf.len() {
581 while !T::REGS.sr().read().ftf() {}
582 unsafe { (T::REGS.dr().as_ptr() as *mut W).write_volatile(buf[idx]) };
583 }
584
585 while !T::REGS.sr().read().tcf() {}
586 T::REGS.fcr().write(|v| v.set_ctcf(true));
587
588 Ok(())
589 }
590
591 /// Set new bus configuration
592 pub fn set_config(&mut self, config: &Config) {
593 // Wait for busy flag to clear
594 while T::REGS.sr().read().busy() {}
595
596 // Disable DMA channel while configuring the peripheral
597 T::REGS.cr().modify(|w| {
598 w.set_dmaen(false);
599 });
600
601 // Device configuration
602 T::REGS.dcr1().modify(|w| {
603 w.set_devsize(config.device_size.into());
604 w.set_mtyp(Mtyp::from_bits(config.memory_type.into()));
605 w.set_csht(Csht::from_bits(config.chip_select_high_time.into()));
606 w.set_frck(false);
607 w.set_ckmode(match config.clock_mode {
608 true => Ckmode::B_0X1,
609 false => Ckmode::B_0X0,
610 });
611 });
612
613 T::REGS.dcr2().modify(|w| {
614 w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into()));
615 });
616
617 T::REGS.dcr3().modify(|w| {
618 w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into()));
619 #[cfg(xspi_v1)]
620 {
621 w.set_maxtran(Maxtran::from_bits(config.max_transfer.into()));
622 }
623 });
624
625 T::REGS.dcr4().modify(|w| {
626 w.set_refresh(Refresh::from_bits(config.refresh.into()));
627 });
628
629 T::REGS.cr().modify(|w| {
630 w.set_fthres(Fthres::from_bits(config.fifo_threshold.into()));
631 });
632
633 // Wait for busy flag to clear
634 while T::REGS.sr().read().busy() {}
635
636 T::REGS.dcr2().modify(|w| {
637 w.set_prescaler(config.clock_prescaler);
638 });
639
640 T::REGS.tcr().modify(|w| {
641 w.set_sshift(config.sample_shifting);
642 w.set_dhqc(config.delay_hold_quarter_cycle);
643 });
644
645 // Enable peripheral
646 T::REGS.cr().modify(|w| {
647 w.set_en(true);
648 });
649
650 // Free running clock needs to be set after peripheral enable
651 if config.free_running_clock {
652 T::REGS.dcr1().modify(|w| {
653 w.set_frck(config.free_running_clock);
654 });
655 }
656
657 self.config = *config;
658 }
659
660 /// Get current configuration
661 pub fn get_config(&self) -> Config {
662 self.config
663 }
664}
665
666impl<'d, T: Instance> Xspi<'d, T, Blocking> {
667 /// Create new blocking XSPI driver for a single spi external chip
668 pub fn new_blocking_singlespi(
669 peri: Peri<'d, T>,
670 clk: Peri<'d, impl CLKPin<T>>,
671 d0: Peri<'d, impl D0Pin<T>>,
672 d1: Peri<'d, impl D1Pin<T>>,
673 ncs: Peri<'d, impl NCSEither<T>>,
674 config: Config,
675 ) -> Self {
676 Self::new_inner(
677 peri,
678 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
679 new_pin!(d1, AfType::input(Pull::None)),
680 None,
681 None,
682 None,
683 None,
684 None,
685 None,
686 None,
687 None,
688 None,
689 None,
690 None,
691 None,
692 None,
693 None,
694 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
695 ncs.sel(),
696 new_pin!(
697 ncs,
698 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
699 ),
700 None,
701 None,
702 None,
703 None,
704 config,
705 XspiWidth::SING,
706 false,
707 )
708 }
709
710 /// Create new blocking XSPI driver for a dualspi external chip
711 pub fn new_blocking_dualspi(
712 peri: Peri<'d, T>,
713 clk: Peri<'d, impl CLKPin<T>>,
714 d0: Peri<'d, impl D0Pin<T>>,
715 d1: Peri<'d, impl D1Pin<T>>,
716 ncs: Peri<'d, impl NCSEither<T>>,
717 config: Config,
718 ) -> Self {
719 Self::new_inner(
720 peri,
721 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
722 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
723 None,
724 None,
725 None,
726 None,
727 None,
728 None,
729 None,
730 None,
731 None,
732 None,
733 None,
734 None,
735 None,
736 None,
737 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
738 ncs.sel(),
739 new_pin!(
740 ncs,
741 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
742 ),
743 None,
744 None,
745 None,
746 None,
747 config,
748 XspiWidth::DUAL,
749 false,
750 )
751 }
752
753 /// Create new blocking XSPI driver for a quadspi external chip
754 pub fn new_blocking_quadspi(
755 peri: Peri<'d, T>,
756 clk: Peri<'d, impl CLKPin<T>>,
757 d0: Peri<'d, impl D0Pin<T>>,
758 d1: Peri<'d, impl D1Pin<T>>,
759 d2: Peri<'d, impl D2Pin<T>>,
760 d3: Peri<'d, impl D3Pin<T>>,
761 ncs: Peri<'d, impl NCSEither<T>>,
762 config: Config,
763 ) -> Self {
764 Self::new_inner(
765 peri,
766 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
767 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
768 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
769 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
770 None,
771 None,
772 None,
773 None,
774 None,
775 None,
776 None,
777 None,
778 None,
779 None,
780 None,
781 None,
782 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
783 ncs.sel(),
784 new_pin!(
785 ncs,
786 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
787 ),
788 None,
789 None,
790 None,
791 None,
792 config,
793 XspiWidth::QUAD,
794 false,
795 )
796 }
797
798 /// Create new blocking XSPI driver for two quadspi external chips
799 pub fn new_blocking_dualquadspi(
800 peri: Peri<'d, T>,
801 clk: Peri<'d, impl CLKPin<T>>,
802 d0: Peri<'d, impl D0Pin<T>>,
803 d1: Peri<'d, impl D1Pin<T>>,
804 d2: Peri<'d, impl D2Pin<T>>,
805 d3: Peri<'d, impl D3Pin<T>>,
806 d4: Peri<'d, impl D4Pin<T>>,
807 d5: Peri<'d, impl D5Pin<T>>,
808 d6: Peri<'d, impl D6Pin<T>>,
809 d7: Peri<'d, impl D7Pin<T>>,
810 ncs: Peri<'d, impl NCSEither<T>>,
811 config: Config,
812 ) -> Self {
813 Self::new_inner(
814 peri,
815 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
816 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
817 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
818 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
819 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
820 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
821 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
822 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
823 None,
824 None,
825 None,
826 None,
827 None,
828 None,
829 None,
830 None,
831 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
832 ncs.sel(),
833 new_pin!(
834 ncs,
835 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
836 ),
837 None,
838 None,
839 None,
840 None,
841 config,
842 XspiWidth::QUAD,
843 true,
844 )
845 }
846
847 /// Create new blocking XSPI driver for xspi external chips
848 pub fn new_blocking_xspi(
849 peri: Peri<'d, T>,
850 clk: Peri<'d, impl CLKPin<T>>,
851 d0: Peri<'d, impl D0Pin<T>>,
852 d1: Peri<'d, impl D1Pin<T>>,
853 d2: Peri<'d, impl D2Pin<T>>,
854 d3: Peri<'d, impl D3Pin<T>>,
855 d4: Peri<'d, impl D4Pin<T>>,
856 d5: Peri<'d, impl D5Pin<T>>,
857 d6: Peri<'d, impl D6Pin<T>>,
858 d7: Peri<'d, impl D7Pin<T>>,
859 ncs: Peri<'d, impl NCSEither<T>>,
860 config: Config,
861 ) -> Self {
862 Self::new_inner(
863 peri,
864 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
865 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
866 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
867 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
868 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
869 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
870 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
871 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
872 None,
873 None,
874 None,
875 None,
876 None,
877 None,
878 None,
879 None,
880 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
881 ncs.sel(),
882 new_pin!(
883 ncs,
884 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
885 ),
886 None,
887 None,
888 None,
889 None,
890 config,
891 XspiWidth::OCTO,
892 false,
893 )
894 }
895}
896
897impl<'d, T: Instance> Xspi<'d, T, Async> {
898 /// Create new blocking XSPI driver for a single spi external chip
899 pub fn new_singlespi(
900 peri: Peri<'d, T>,
901 clk: Peri<'d, impl CLKPin<T>>,
902 d0: Peri<'d, impl D0Pin<T>>,
903 d1: Peri<'d, impl D1Pin<T>>,
904 ncs: Peri<'d, impl NCSEither<T>>,
905 dma: Peri<'d, impl XDma<T>>,
906 config: Config,
907 ) -> Self {
908 Self::new_inner(
909 peri,
910 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
911 new_pin!(d1, AfType::input(Pull::None)),
912 None,
913 None,
914 None,
915 None,
916 None,
917 None,
918 None,
919 None,
920 None,
921 None,
922 None,
923 None,
924 None,
925 None,
926 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
927 ncs.sel(),
928 new_pin!(
929 ncs,
930 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
931 ),
932 None,
933 None,
934 None,
935 new_dma!(dma),
936 config,
937 XspiWidth::SING,
938 false,
939 )
940 }
941
942 /// Create new blocking XSPI driver for a dualspi external chip
943 pub fn new_dualspi(
944 peri: Peri<'d, T>,
945 clk: Peri<'d, impl CLKPin<T>>,
946 d0: Peri<'d, impl D0Pin<T>>,
947 d1: Peri<'d, impl D1Pin<T>>,
948 ncs: Peri<'d, impl NCSEither<T>>,
949 dma: Peri<'d, impl XDma<T>>,
950 config: Config,
951 ) -> Self {
952 Self::new_inner(
953 peri,
954 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
955 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
956 None,
957 None,
958 None,
959 None,
960 None,
961 None,
962 None,
963 None,
964 None,
965 None,
966 None,
967 None,
968 None,
969 None,
970 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
971 ncs.sel(),
972 new_pin!(
973 ncs,
974 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
975 ),
976 None,
977 None,
978 None,
979 new_dma!(dma),
980 config,
981 XspiWidth::DUAL,
982 false,
983 )
984 }
985
986 /// Create new blocking XSPI driver for a quadspi external chip
987 pub fn new_quadspi(
988 peri: Peri<'d, T>,
989 clk: Peri<'d, impl CLKPin<T>>,
990 d0: Peri<'d, impl D0Pin<T>>,
991 d1: Peri<'d, impl D1Pin<T>>,
992 d2: Peri<'d, impl D2Pin<T>>,
993 d3: Peri<'d, impl D3Pin<T>>,
994 ncs: Peri<'d, impl NCSEither<T>>,
995 dma: Peri<'d, impl XDma<T>>,
996 config: Config,
997 ) -> Self {
998 Self::new_inner(
999 peri,
1000 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1001 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1002 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1003 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1004 None,
1005 None,
1006 None,
1007 None,
1008 None,
1009 None,
1010 None,
1011 None,
1012 None,
1013 None,
1014 None,
1015 None,
1016 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1017 ncs.sel(),
1018 new_pin!(
1019 ncs,
1020 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
1021 ),
1022 None,
1023 None,
1024 None,
1025 new_dma!(dma),
1026 config,
1027 XspiWidth::QUAD,
1028 false,
1029 )
1030 }
1031
1032 /// Create new blocking XSPI driver for two quadspi external chips
1033 pub fn new_dualquadspi(
1034 peri: Peri<'d, T>,
1035 clk: Peri<'d, impl CLKPin<T>>,
1036 d0: Peri<'d, impl D0Pin<T>>,
1037 d1: Peri<'d, impl D1Pin<T>>,
1038 d2: Peri<'d, impl D2Pin<T>>,
1039 d3: Peri<'d, impl D3Pin<T>>,
1040 d4: Peri<'d, impl D4Pin<T>>,
1041 d5: Peri<'d, impl D5Pin<T>>,
1042 d6: Peri<'d, impl D6Pin<T>>,
1043 d7: Peri<'d, impl D7Pin<T>>,
1044 ncs: Peri<'d, impl NCSEither<T>>,
1045 dma: Peri<'d, impl XDma<T>>,
1046 config: Config,
1047 ) -> Self {
1048 Self::new_inner(
1049 peri,
1050 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1051 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1052 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1053 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1054 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1055 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1056 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1057 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1058 None,
1059 None,
1060 None,
1061 None,
1062 None,
1063 None,
1064 None,
1065 None,
1066 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1067 ncs.sel(),
1068 new_pin!(
1069 ncs,
1070 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
1071 ),
1072 None,
1073 None,
1074 None,
1075 new_dma!(dma),
1076 config,
1077 XspiWidth::QUAD,
1078 true,
1079 )
1080 }
1081
1082 /// Create new blocking XSPI driver for xspi external chips
1083 pub fn new_xspi(
1084 peri: Peri<'d, T>,
1085 clk: Peri<'d, impl CLKPin<T>>,
1086 d0: Peri<'d, impl D0Pin<T>>,
1087 d1: Peri<'d, impl D1Pin<T>>,
1088 d2: Peri<'d, impl D2Pin<T>>,
1089 d3: Peri<'d, impl D3Pin<T>>,
1090 d4: Peri<'d, impl D4Pin<T>>,
1091 d5: Peri<'d, impl D5Pin<T>>,
1092 d6: Peri<'d, impl D6Pin<T>>,
1093 d7: Peri<'d, impl D7Pin<T>>,
1094 ncs: Peri<'d, impl NCSEither<T>>,
1095 dma: Peri<'d, impl XDma<T>>,
1096 config: Config,
1097 ) -> Self {
1098 Self::new_inner(
1099 peri,
1100 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1101 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1102 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1103 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1104 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1105 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1106 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1107 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1108 None,
1109 None,
1110 None,
1111 None,
1112 None,
1113 None,
1114 None,
1115 None,
1116 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1117 ncs.sel(),
1118 new_pin!(
1119 ncs,
1120 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
1121 ),
1122 None,
1123 None,
1124 None,
1125 new_dma!(dma),
1126 config,
1127 XspiWidth::OCTO,
1128 false,
1129 )
1130 }
1131
1132 /// Blocking read with DMA transfer
1133 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> {
1134 if buf.is_empty() {
1135 return Err(XspiError::EmptyBuffer);
1136 }
1137
1138 // Wait for peripheral to be free
1139 while T::REGS.sr().read().busy() {}
1140
1141 self.configure_command(&transaction, Some(buf.len()))?;
1142
1143 let current_address = T::REGS.ar().read().address();
1144 let current_instruction = T::REGS.ir().read().instruction();
1145
1146 // For a indirect read transaction, the transaction begins when the instruction/address is set
1147 T::REGS
1148 .cr()
1149 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
1150 if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 {
1151 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
1152 } else {
1153 T::REGS.ar().write(|v| v.set_address(current_address));
1154 }
1155
1156 let transfer = unsafe {
1157 self.dma
1158 .as_mut()
1159 .unwrap()
1160 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
1161 };
1162
1163 T::REGS.cr().modify(|w| w.set_dmaen(true));
1164
1165 transfer.blocking_wait();
1166
1167 finish_dma(T::REGS);
1168
1169 Ok(())
1170 }
1171
1172 /// Blocking write with DMA transfer
1173 pub fn blocking_write_dma<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> {
1174 if buf.is_empty() {
1175 return Err(XspiError::EmptyBuffer);
1176 }
1177
1178 // Wait for peripheral to be free
1179 while T::REGS.sr().read().busy() {}
1180
1181 self.configure_command(&transaction, Some(buf.len()))?;
1182 T::REGS
1183 .cr()
1184 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
1185
1186 let transfer = unsafe {
1187 self.dma
1188 .as_mut()
1189 .unwrap()
1190 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
1191 };
1192
1193 T::REGS.cr().modify(|w| w.set_dmaen(true));
1194
1195 transfer.blocking_wait();
1196
1197 finish_dma(T::REGS);
1198
1199 Ok(())
1200 }
1201
1202 /// Asynchronous read from external device
1203 pub async fn read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> {
1204 if buf.is_empty() {
1205 return Err(XspiError::EmptyBuffer);
1206 }
1207
1208 // Wait for peripheral to be free
1209 while T::REGS.sr().read().busy() {}
1210
1211 self.configure_command(&transaction, Some(buf.len()))?;
1212
1213 let current_address = T::REGS.ar().read().address();
1214 let current_instruction = T::REGS.ir().read().instruction();
1215
1216 // For a indirect read transaction, the transaction begins when the instruction/address is set
1217 T::REGS
1218 .cr()
1219 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
1220 if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 {
1221 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
1222 } else {
1223 T::REGS.ar().write(|v| v.set_address(current_address));
1224 }
1225
1226 let transfer = unsafe {
1227 self.dma
1228 .as_mut()
1229 .unwrap()
1230 .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
1231 };
1232
1233 T::REGS.cr().modify(|w| w.set_dmaen(true));
1234
1235 transfer.await;
1236
1237 finish_dma(T::REGS);
1238
1239 Ok(())
1240 }
1241
1242 /// Asynchronous write to external device
1243 pub async fn write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> {
1244 if buf.is_empty() {
1245 return Err(XspiError::EmptyBuffer);
1246 }
1247
1248 // Wait for peripheral to be free
1249 while T::REGS.sr().read().busy() {}
1250
1251 self.configure_command(&transaction, Some(buf.len()))?;
1252 T::REGS
1253 .cr()
1254 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
1255
1256 let transfer = unsafe {
1257 self.dma
1258 .as_mut()
1259 .unwrap()
1260 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
1261 };
1262
1263 T::REGS.cr().modify(|w| w.set_dmaen(true));
1264
1265 transfer.await;
1266
1267 finish_dma(T::REGS);
1268
1269 Ok(())
1270 }
1271}
1272
1273impl<'d, T: Instance, M: PeriMode> Drop for Xspi<'d, T, M> {
1274 fn drop(&mut self) {
1275 self.clk.as_ref().map(|x| x.set_as_disconnected());
1276 self.d0.as_ref().map(|x| x.set_as_disconnected());
1277 self.d1.as_ref().map(|x| x.set_as_disconnected());
1278 self.d2.as_ref().map(|x| x.set_as_disconnected());
1279 self.d3.as_ref().map(|x| x.set_as_disconnected());
1280 self.d4.as_ref().map(|x| x.set_as_disconnected());
1281 self.d5.as_ref().map(|x| x.set_as_disconnected());
1282 self.d6.as_ref().map(|x| x.set_as_disconnected());
1283 self.d7.as_ref().map(|x| x.set_as_disconnected());
1284 self.d8.as_ref().map(|x| x.set_as_disconnected());
1285 self.d9.as_ref().map(|x| x.set_as_disconnected());
1286 self.d10.as_ref().map(|x| x.set_as_disconnected());
1287 self.d11.as_ref().map(|x| x.set_as_disconnected());
1288 self.d12.as_ref().map(|x| x.set_as_disconnected());
1289 self.d13.as_ref().map(|x| x.set_as_disconnected());
1290 self.d14.as_ref().map(|x| x.set_as_disconnected());
1291 self.d15.as_ref().map(|x| x.set_as_disconnected());
1292 self.ncs.as_ref().map(|x| x.set_as_disconnected());
1293 self.ncs_alt.as_ref().map(|x| x.set_as_disconnected());
1294 self.dqs0.as_ref().map(|x| x.set_as_disconnected());
1295 self.dqs1.as_ref().map(|x| x.set_as_disconnected());
1296
1297 rcc::disable::<T>();
1298 }
1299}
1300
1301fn finish_dma(regs: Regs) {
1302 while !regs.sr().read().tcf() {}
1303 regs.fcr().write(|v| v.set_ctcf(true));
1304
1305 regs.cr().modify(|w| {
1306 w.set_dmaen(false);
1307 });
1308}
1309
1310/// XSPI I/O manager instance trait.
1311#[cfg(xspim_v1)]
1312pub(crate) trait SealedXspimInstance {
1313 const SPIM_REGS: Xspim;
1314 const SPI_IDX: u8;
1315}
1316
1317/// XSPI instance trait.
1318pub(crate) trait SealedInstance {
1319 const REGS: Regs;
1320}
1321
1322/// XSPI instance trait.
1323#[cfg(xspim_v1)]
1324#[allow(private_bounds)]
1325pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + SealedXspimInstance {}
1326
1327/// XSPI instance trait.
1328#[cfg(not(xspim_v1))]
1329#[allow(private_bounds)]
1330pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {}
1331
1332pin_trait!(D0Pin, Instance);
1333pin_trait!(D1Pin, Instance);
1334pin_trait!(D2Pin, Instance);
1335pin_trait!(D3Pin, Instance);
1336pin_trait!(D4Pin, Instance);
1337pin_trait!(D5Pin, Instance);
1338pin_trait!(D6Pin, Instance);
1339pin_trait!(D7Pin, Instance);
1340pin_trait!(D8Pin, Instance);
1341pin_trait!(D9Pin, Instance);
1342pin_trait!(D10Pin, Instance);
1343pin_trait!(D11Pin, Instance);
1344pin_trait!(D12Pin, Instance);
1345pin_trait!(D13Pin, Instance);
1346pin_trait!(D14Pin, Instance);
1347pin_trait!(D15Pin, Instance);
1348pin_trait!(DQS0Pin, Instance);
1349pin_trait!(DQS1Pin, Instance);
1350pin_trait!(NCSPin, Instance);
1351pin_trait!(CLKPin, Instance);
1352pin_trait!(NCLKPin, Instance);
1353dma_trait!(XDma, Instance);
1354
1355/// Trait for either NCS1 or NCS2 pins
1356pub trait NCSEither<T: Instance>: NCSPin<T> {
1357 /// Get the CSSEL for this NCS pin
1358 fn sel(&self) -> u8;
1359}
1360
1361// Hard-coded the xspi index, for SPIM
1362#[cfg(xspim_v1)]
1363impl SealedXspimInstance for peripherals::XSPI1 {
1364 const SPIM_REGS: Xspim = crate::pac::XSPIM;
1365 const SPI_IDX: u8 = 1;
1366}
1367
1368// Some cubedb files are missing XSPI2, for example STM32H7R3Z8
1369#[cfg(all(xspim_v1, peri_xspi2))]
1370impl SealedXspimInstance for peripherals::XSPI2 {
1371 const SPIM_REGS: Xspim = crate::pac::XSPIM;
1372 const SPI_IDX: u8 = 2;
1373}
1374
1375#[cfg(xspim_v1)]
1376foreach_peripheral!(
1377 (xspi, $inst:ident) => {
1378 impl SealedInstance for peripherals::$inst {
1379 const REGS: Regs = crate::pac::$inst;
1380 }
1381
1382 impl Instance for peripherals::$inst {}
1383 };
1384);
1385
1386#[cfg(not(xspim_v1))]
1387foreach_peripheral!(
1388 (xspi, $inst:ident) => {
1389 impl SealedInstance for peripherals::$inst {
1390 const REGS: Regs = crate::pac::$inst;
1391 }
1392
1393 impl Instance for peripherals::$inst {}
1394 };
1395);
1396
1397impl<'d, T: Instance, M: PeriMode> SetConfig for Xspi<'d, T, M> {
1398 type Config = Config;
1399 type ConfigError = ();
1400 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
1401 self.set_config(config);
1402 Ok(())
1403 }
1404}
1405
1406impl<'d, T: Instance, M: PeriMode> GetConfig for Xspi<'d, T, M> {
1407 type Config = Config;
1408 fn get_config(&self) -> Self::Config {
1409 self.get_config()
1410 }
1411}
1412
1413/// Word sizes usable for XSPI.
1414#[allow(private_bounds)]
1415pub trait Word: word::Word {}
1416
1417macro_rules! impl_word {
1418 ($T:ty) => {
1419 impl Word for $T {}
1420 };
1421}
1422
1423impl_word!(u8);
1424impl_word!(u16);
1425impl_word!(u32);