aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rwxr-xr-xci.sh5
-rw-r--r--docs/modules/ROOT/pages/best_practices.adoc6
-rw-r--r--docs/modules/ROOT/pages/faq.adoc12
-rw-r--r--docs/modules/ROOT/pages/new_project.adoc25
-rw-r--r--docs/modules/ROOT/pages/project_structure.adoc9
-rw-r--r--embassy-boot/src/boot_loader.rs53
-rw-r--r--embassy-boot/src/firmware_updater/asynch.rs13
-rw-r--r--embassy-boot/src/firmware_updater/blocking.rs43
-rw-r--r--embassy-boot/src/firmware_updater/mod.rs2
-rw-r--r--embassy-executor/src/raw/mod.rs12
-rw-r--r--embassy-nrf/src/spim.rs14
-rw-r--r--embassy-nrf/src/spis.rs8
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/adc/mod.rs23
-rw-r--r--embassy-stm32/src/adc/resolution.rs8
-rw-r--r--embassy-stm32/src/adc/sample_time.rs2
-rw-r--r--embassy-stm32/src/adc/v1.rs23
-rw-r--r--embassy-stm32/src/dma/bdma.rs7
-rw-r--r--embassy-stm32/src/dma/dma.rs7
-rw-r--r--embassy-stm32/src/dma/ringbuffer.rs12
-rw-r--r--embassy-stm32/src/rcc/h.rs1
-rw-r--r--embassy-stm32/src/rcc/u5.rs1
-rw-r--r--embassy-stm32/src/time_driver.rs8
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs17
-rw-r--r--embassy-stm32/src/timer/mod.rs618
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs7
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs2
-rw-r--r--examples/boot/application/rp/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f3/memory.x4
-rw-r--r--examples/boot/application/stm32f3/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l0/memory.x4
-rw-r--r--examples/boot/application/stm32l0/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l1/memory.x4
-rw-r--r--examples/boot/application/stm32l1/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l4/memory.x4
-rw-r--r--examples/boot/application/stm32l4/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32wb-dfu/README.md24
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs2
-rw-r--r--examples/boot/application/stm32wl/memory.x4
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs2
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs2
-rw-r--r--examples/boot/bootloader/rp/src/main.rs2
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/Cargo.toml57
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/README.md44
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/build.rs27
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/memory.x18
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/src/main.rs53
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/README.md2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs4
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs14
-rw-r--r--examples/stm32l0/src/bin/adc.rs40
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs14
-rwxr-xr-xtests/stm32/teleprobe.sh12
58 files changed, 948 insertions, 351 deletions
diff --git a/README.md b/README.md
index 24347a43f..b6f667f75 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
2 2
3Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. 3Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries.
4 4
5## <a href="https://embassy.dev/dev/index.html">Documentation</a> - <a href="https://docs.embassy.dev/">API reference</a> - <a href="https://embassy.dev/">Website</a> - <a href="https://matrix.to/#/#embassy-rs:matrix.org">Chat</a> 5## <a href="https://embassy.dev/book/dev/index.html">Documentation</a> - <a href="https://docs.embassy.dev/">API reference</a> - <a href="https://embassy.dev/">Website</a> - <a href="https://matrix.to/#/#embassy-rs:matrix.org">Chat</a>
6## Rust + async ❤️ embedded 6## Rust + async ❤️ embedded
7 7
8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. 8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system.
diff --git a/ci.sh b/ci.sh
index df9e09848..58a288441 100755
--- a/ci.sh
+++ b/ci.sh
@@ -23,6 +23,8 @@ cargo batch \
23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ 23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \ 24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \ 25 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \
26 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \
27 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers,rtos-trace \
26 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \ 28 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
27 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \ 29 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \ 30 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \
@@ -194,7 +196,8 @@ cargo batch \
194 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 196 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
195 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ 197 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
196 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 198 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
197 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf \ 199 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32wb55rg \
200 --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32h747xi-cm7 \
198 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ 201 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
199 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ 202 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
200 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ 203 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
diff --git a/docs/modules/ROOT/pages/best_practices.adoc b/docs/modules/ROOT/pages/best_practices.adoc
index 1e02f9ba9..bfcedec06 100644
--- a/docs/modules/ROOT/pages/best_practices.adoc
+++ b/docs/modules/ROOT/pages/best_practices.adoc
@@ -3,8 +3,10 @@
3Over time, a couple of best practices have emerged. The following list should serve as a guideline for developers writing embedded software in _Rust_, especially in the context of the _Embassy_ framework. 3Over time, a couple of best practices have emerged. The following list should serve as a guideline for developers writing embedded software in _Rust_, especially in the context of the _Embassy_ framework.
4 4
5== Passing Buffers by Reference 5== Passing Buffers by Reference
6It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't want to spend ressources on an allocator and end up placing buffers on the stack. 6It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`],
7This, however, can easily blow up your stack if you are not careful. 7to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't
8want to spend resources on an allocator and end up placing buffers on the stack. This, however, can easily blow up
9your stack if you are not careful.
8 10
9Consider the following example: 11Consider the following example:
10[,rust] 12[,rust]
diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc
index 05ff7c598..7fb81e2ca 100644
--- a/docs/modules/ROOT/pages/faq.adoc
+++ b/docs/modules/ROOT/pages/faq.adoc
@@ -29,11 +29,10 @@ If you see an error like this:
29 29
30You are likely missing some features of the `embassy-executor` crate. 30You are likely missing some features of the `embassy-executor` crate.
31 31
32For Cortex-M targets, consider making sure that ALL of the following features are active in your `Cargo.toml` for the `embassy-executor` crate: 32For Cortex-M targets, check whether ALL of the following features are enabled in your `Cargo.toml` for the `embassy-executor` crate:
33 33
34* `arch-cortex-m` 34* `arch-cortex-m`
35* `executor-thread` 35* `executor-thread`
36* `nightly`
37 36
38For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. 37For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate].
39 38
@@ -125,15 +124,18 @@ You have multiple versions of the same crate in your dependency tree. This means
125embassy crates are coming from crates.io, and some from git, each of them pulling in a different set 124embassy crates are coming from crates.io, and some from git, each of them pulling in a different set
126of dependencies. 125of dependencies.
127 126
128To resolve this issue, make sure to only use a single source for all your embassy crates! To do this, 127To resolve this issue, make sure to only use a single source for all your embassy crates!
129you should patch your dependencies to use git sources using `[patch.crates.io]` and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. 128To do this, you should patch your dependencies to use git sources using `[patch.crates.io]`
129and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`.
130 130
131Example: 131Example:
132 132
133[source,toml] 133[source,toml]
134---- 134----
135[patch.crates-io] 135[patch.crates-io]
136embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } 136embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" }
137embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" }
138# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" }
137---- 139----
138 140
139Note that the git revision should match any other embassy patches or git dependencies that you are using! 141Note that the git revision should match any other embassy patches or git dependencies that you are using!
diff --git a/docs/modules/ROOT/pages/new_project.adoc b/docs/modules/ROOT/pages/new_project.adoc
index ce139ed8d..320966bb6 100644
--- a/docs/modules/ROOT/pages/new_project.adoc
+++ b/docs/modules/ROOT/pages/new_project.adoc
@@ -1,6 +1,17 @@
1= Starting a new Embassy project 1= Starting a new Embassy project
2 2
3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. The easiest way to do this is to adapt an example for a similar chip to the one you’re targeting. 3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project.
4
5There are some tools for generating Embassy projects: (WIP)
6
7==== CLI
8- link:https://github.com/adinack/cargo-embassy[cargo-embassy] (STM32 and NRF)
9
10==== cargo-generate
11- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP)
12- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP)
13
14But if you want to start from scratch:
4 15
5As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes. 16As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes.
6 17
@@ -166,13 +177,13 @@ should result in a blinking LED (if there’s one attached to the pin in `src/ma
166 Erasing sectors ✔ [00:00:00] [#########################################################] 18.00 KiB/18.00 KiB @ 54.09 KiB/s (eta 0s ) 177 Erasing sectors ✔ [00:00:00] [#########################################################] 18.00 KiB/18.00 KiB @ 54.09 KiB/s (eta 0s )
167 Programming pages ✔ [00:00:00] [#########################################################] 17.00 KiB/17.00 KiB @ 35.91 KiB/s (eta 0s ) Finished in 0.817s 178 Programming pages ✔ [00:00:00] [#########################################################] 17.00 KiB/17.00 KiB @ 35.91 KiB/s (eta 0s ) Finished in 0.817s
1680.000000 TRACE BDCR configured: 00008200 1790.000000 TRACE BDCR configured: 00008200
169└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117 180└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117
1700.000000 DEBUG rcc: Clocks { sys: Hertz(16000000), pclk1: Hertz(16000000), pclk1_tim: Hertz(16000000), pclk2: Hertz(16000000), pclk2_tim: Hertz(16000000), hclk1: Hertz(16000000), hclk2: Hertz(16000000), pll1_p: None, adc: None, adc34: None, rtc: Some(Hertz(32000)) } 1810.000000 DEBUG rcc: Clocks { sys: Hertz(16000000), pclk1: Hertz(16000000), pclk1_tim: Hertz(16000000), pclk2: Hertz(16000000), pclk2_tim: Hertz(16000000), hclk1: Hertz(16000000), hclk2: Hertz(16000000), pll1_p: None, adc: None, adc34: None, rtc: Some(Hertz(32000)) }
171└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130 182└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130
1720.000000 INFO Hello World! 1830.000000 INFO Hello World!
173└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14 184└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14
1740.000091 INFO high 1850.000091 INFO high
175└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19 186└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19
1760.300201 INFO low 1870.300201 INFO low
177└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23 188└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23
178---- \ No newline at end of file 189----
diff --git a/docs/modules/ROOT/pages/project_structure.adoc b/docs/modules/ROOT/pages/project_structure.adoc
index 61ffd05a6..2adfcc1df 100644
--- a/docs/modules/ROOT/pages/project_structure.adoc
+++ b/docs/modules/ROOT/pages/project_structure.adoc
@@ -38,13 +38,18 @@ DEFMT_LOG = "trace" # <- can change to info, warn, or error
38 38
39== build.rs 39== build.rs
40 40
41This is the build script for your project. It links defmt (what is defmt?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. 41This is the build script for your project. It links defmt (what is link:https://defmt.ferrous-systems.com[defmt]?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example].
42 42
43== Cargo.toml 43== Cargo.toml
44 44
45This is your manifest file, where you can configure all of the embassy components to use the features you need. 45This is your manifest file, where you can configure all of the embassy components to use the features you need.
46 46
47TODO: someone should exhaustively describe every feature for every component! 47==== Features
48===== Time
49- tick-hz-x: Configures the tick rate of `embassy-time`. Higher tick rate means higher precision, and higher CPU wakes.
50- defmt-timestamp-uptime: defmt log entries will display the uptime in seconds.
51
52...more to come
48 53
49== memory.x 54== memory.x
50 55
diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs
index e568001bc..ca1a1b10c 100644
--- a/embassy-boot/src/boot_loader.rs
+++ b/embassy-boot/src/boot_loader.rs
@@ -49,16 +49,51 @@ pub struct BootLoaderConfig<ACTIVE, DFU, STATE> {
49 pub state: STATE, 49 pub state: STATE,
50} 50}
51 51
52impl<'a, FLASH: NorFlash> 52impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>
53 BootLoaderConfig< 53 BootLoaderConfig<
54 BlockingPartition<'a, NoopRawMutex, FLASH>, 54 BlockingPartition<'a, NoopRawMutex, ACTIVE>,
55 BlockingPartition<'a, NoopRawMutex, FLASH>, 55 BlockingPartition<'a, NoopRawMutex, DFU>,
56 BlockingPartition<'a, NoopRawMutex, FLASH>, 56 BlockingPartition<'a, NoopRawMutex, STATE>,
57 > 57 >
58{ 58{
59 /// Create a bootloader config from the flash and address symbols defined in the linkerfile 59 /// Constructs a `BootLoaderConfig` instance from flash memory and address symbols defined in the linker file.
60 ///
61 /// This method initializes `BlockingPartition` instances for the active, DFU (Device Firmware Update),
62 /// and state partitions, leveraging start and end addresses specified by the linker. These partitions
63 /// are critical for managing firmware updates, application state, and boot operations within the bootloader.
64 ///
65 /// # Parameters
66 /// - `active_flash`: A reference to a mutex-protected `RefCell` for the active partition's flash interface.
67 /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface.
68 /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface.
69 ///
70 /// # Safety
71 /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses
72 /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined
73 /// in the memory.x file to prevent undefined behavior.
74 ///
75 /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory
76 /// interfaces provided are compatible with these regions.
77 ///
78 /// # Returns
79 /// A `BootLoaderConfig` instance with `BlockingPartition` instances for the active, DFU, and state partitions.
80 ///
81 /// # Example
82 /// ```ignore
83 /// // Assume `active_flash`, `dfu_flash`, and `state_flash` all share the same flash memory interface.
84 /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
85 /// let flash = Mutex::new(RefCell::new(layout.bank1_region));
86 ///
87 /// let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
88 /// // `config` can now be used to create a `BootLoader` instance for managing boot operations.
89 /// ```
90 /// Working examples can be found in the bootloader examples folder.
60 // #[cfg(target_os = "none")] 91 // #[cfg(target_os = "none")]
61 pub fn from_linkerfile_blocking(flash: &'a Mutex<NoopRawMutex, RefCell<FLASH>>) -> Self { 92 pub fn from_linkerfile_blocking(
93 active_flash: &'a Mutex<NoopRawMutex, RefCell<ACTIVE>>,
94 dfu_flash: &'a Mutex<NoopRawMutex, RefCell<DFU>>,
95 state_flash: &'a Mutex<NoopRawMutex, RefCell<STATE>>,
96 ) -> Self {
62 extern "C" { 97 extern "C" {
63 static __bootloader_state_start: u32; 98 static __bootloader_state_start: u32;
64 static __bootloader_state_end: u32; 99 static __bootloader_state_end: u32;
@@ -73,21 +108,21 @@ impl<'a, FLASH: NorFlash>
73 let end = &__bootloader_active_end as *const u32 as u32; 108 let end = &__bootloader_active_end as *const u32 as u32;
74 trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end); 109 trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end);
75 110
76 BlockingPartition::new(flash, start, end - start) 111 BlockingPartition::new(active_flash, start, end - start)
77 }; 112 };
78 let dfu = unsafe { 113 let dfu = unsafe {
79 let start = &__bootloader_dfu_start as *const u32 as u32; 114 let start = &__bootloader_dfu_start as *const u32 as u32;
80 let end = &__bootloader_dfu_end as *const u32 as u32; 115 let end = &__bootloader_dfu_end as *const u32 as u32;
81 trace!("DFU: 0x{:x} - 0x{:x}", start, end); 116 trace!("DFU: 0x{:x} - 0x{:x}", start, end);
82 117
83 BlockingPartition::new(flash, start, end - start) 118 BlockingPartition::new(dfu_flash, start, end - start)
84 }; 119 };
85 let state = unsafe { 120 let state = unsafe {
86 let start = &__bootloader_state_start as *const u32 as u32; 121 let start = &__bootloader_state_start as *const u32 as u32;
87 let end = &__bootloader_state_end as *const u32 as u32; 122 let end = &__bootloader_state_end as *const u32 as u32;
88 trace!("STATE: 0x{:x} - 0x{:x}", start, end); 123 trace!("STATE: 0x{:x} - 0x{:x}", start, end);
89 124
90 BlockingPartition::new(flash, start, end - start) 125 BlockingPartition::new(state_flash, start, end - start)
91 }; 126 };
92 127
93 Self { active, dfu, state } 128 Self { active, dfu, state }
diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs
index 2e43e1cc1..668f16f16 100644
--- a/embassy-boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/src/firmware_updater/asynch.rs
@@ -16,11 +16,14 @@ pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> {
16} 16}
17 17
18#[cfg(target_os = "none")] 18#[cfg(target_os = "none")]
19impl<'a, FLASH: NorFlash> 19impl<'a, DFU: NorFlash, STATE: NorFlash>
20 FirmwareUpdaterConfig<Partition<'a, NoopRawMutex, FLASH>, Partition<'a, NoopRawMutex, FLASH>> 20 FirmwareUpdaterConfig<Partition<'a, NoopRawMutex, DFU>, Partition<'a, NoopRawMutex, STATE>>
21{ 21{
22 /// Create a firmware updater config from the flash and address symbols defined in the linkerfile 22 /// Create a firmware updater config from the flash and address symbols defined in the linkerfile
23 pub fn from_linkerfile(flash: &'a embassy_sync::mutex::Mutex<NoopRawMutex, FLASH>) -> Self { 23 pub fn from_linkerfile(
24 dfu_flash: &'a embassy_sync::mutex::Mutex<NoopRawMutex, DFU>,
25 state_flash: &'a embassy_sync::mutex::Mutex<NoopRawMutex, STATE>,
26 ) -> Self {
24 extern "C" { 27 extern "C" {
25 static __bootloader_state_start: u32; 28 static __bootloader_state_start: u32;
26 static __bootloader_state_end: u32; 29 static __bootloader_state_end: u32;
@@ -33,14 +36,14 @@ impl<'a, FLASH: NorFlash>
33 let end = &__bootloader_dfu_end as *const u32 as u32; 36 let end = &__bootloader_dfu_end as *const u32 as u32;
34 trace!("DFU: 0x{:x} - 0x{:x}", start, end); 37 trace!("DFU: 0x{:x} - 0x{:x}", start, end);
35 38
36 Partition::new(flash, start, end - start) 39 Partition::new(dfu_flash, start, end - start)
37 }; 40 };
38 let state = unsafe { 41 let state = unsafe {
39 let start = &__bootloader_state_start as *const u32 as u32; 42 let start = &__bootloader_state_start as *const u32 as u32;
40 let end = &__bootloader_state_end as *const u32 as u32; 43 let end = &__bootloader_state_end as *const u32 as u32;
41 trace!("STATE: 0x{:x} - 0x{:x}", start, end); 44 trace!("STATE: 0x{:x} - 0x{:x}", start, end);
42 45
43 Partition::new(flash, start, end - start) 46 Partition::new(state_flash, start, end - start)
44 }; 47 };
45 48
46 Self { dfu, state } 49 Self { dfu, state }
diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs
index 514070639..3e83366af 100644
--- a/embassy-boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/src/firmware_updater/blocking.rs
@@ -16,12 +16,43 @@ pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> {
16} 16}
17 17
18#[cfg(target_os = "none")] 18#[cfg(target_os = "none")]
19impl<'a, FLASH: NorFlash> 19impl<'a, DFU: NorFlash, STATE: NorFlash>
20 FirmwareUpdaterConfig<BlockingPartition<'a, NoopRawMutex, FLASH>, BlockingPartition<'a, NoopRawMutex, FLASH>> 20 FirmwareUpdaterConfig<BlockingPartition<'a, NoopRawMutex, DFU>, BlockingPartition<'a, NoopRawMutex, STATE>>
21{ 21{
22 /// Create a firmware updater config from the flash and address symbols defined in the linkerfile 22 /// Constructs a `FirmwareUpdaterConfig` instance from flash memory and address symbols defined in the linker file.
23 ///
24 /// This method initializes `BlockingPartition` instances for the DFU (Device Firmware Update), and state
25 /// partitions, leveraging start and end addresses specified by the linker. These partitions are critical
26 /// for managing firmware updates, application state, and boot operations within the bootloader.
27 ///
28 /// # Parameters
29 /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface.
30 /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface.
31 ///
32 /// # Safety
33 /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses
34 /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined
35 /// in the memory.x file to prevent undefined behavior.
36 ///
37 /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory
38 /// interfaces provided are compatible with these regions.
39 ///
40 /// # Returns
41 /// A `FirmwareUpdaterConfig` instance with `BlockingPartition` instances for the DFU, and state partitions.
42 ///
43 /// # Example
44 /// ```ignore
45 /// // Assume `dfu_flash`, and `state_flash` share the same flash memory interface.
46 /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
47 /// let flash = Mutex::new(RefCell::new(layout.bank1_region));
48 ///
49 /// let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
50 /// // `config` can now be used to create a `FirmwareUpdater` instance for managing boot operations.
51 /// ```
52 /// Working examples can be found in the bootloader examples folder.
23 pub fn from_linkerfile_blocking( 53 pub fn from_linkerfile_blocking(
24 flash: &'a embassy_sync::blocking_mutex::Mutex<NoopRawMutex, core::cell::RefCell<FLASH>>, 54 dfu_flash: &'a embassy_sync::blocking_mutex::Mutex<NoopRawMutex, core::cell::RefCell<DFU>>,
55 state_flash: &'a embassy_sync::blocking_mutex::Mutex<NoopRawMutex, core::cell::RefCell<STATE>>,
25 ) -> Self { 56 ) -> Self {
26 extern "C" { 57 extern "C" {
27 static __bootloader_state_start: u32; 58 static __bootloader_state_start: u32;
@@ -35,14 +66,14 @@ impl<'a, FLASH: NorFlash>
35 let end = &__bootloader_dfu_end as *const u32 as u32; 66 let end = &__bootloader_dfu_end as *const u32 as u32;
36 trace!("DFU: 0x{:x} - 0x{:x}", start, end); 67 trace!("DFU: 0x{:x} - 0x{:x}", start, end);
37 68
38 BlockingPartition::new(flash, start, end - start) 69 BlockingPartition::new(dfu_flash, start, end - start)
39 }; 70 };
40 let state = unsafe { 71 let state = unsafe {
41 let start = &__bootloader_state_start as *const u32 as u32; 72 let start = &__bootloader_state_start as *const u32 as u32;
42 let end = &__bootloader_state_end as *const u32 as u32; 73 let end = &__bootloader_state_end as *const u32 as u32;
43 trace!("STATE: 0x{:x} - 0x{:x}", start, end); 74 trace!("STATE: 0x{:x} - 0x{:x}", start, end);
44 75
45 BlockingPartition::new(flash, start, end - start) 76 BlockingPartition::new(state_flash, start, end - start)
46 }; 77 };
47 78
48 Self { dfu, state } 79 Self { dfu, state }
diff --git a/embassy-boot/src/firmware_updater/mod.rs b/embassy-boot/src/firmware_updater/mod.rs
index 4814786bf..4c4f4f10b 100644
--- a/embassy-boot/src/firmware_updater/mod.rs
+++ b/embassy-boot/src/firmware_updater/mod.rs
@@ -8,7 +8,7 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
8/// Firmware updater flash configuration holding the two flashes used by the updater 8/// Firmware updater flash configuration holding the two flashes used by the updater
9/// 9///
10/// If only a single flash is actually used, then that flash should be partitioned into two partitions before use. 10/// If only a single flash is actually used, then that flash should be partitioned into two partitions before use.
11/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition 11/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile_blocking`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition
12/// the provided flash according to symbols defined in the linkerfile. 12/// the provided flash according to symbols defined in the linkerfile.
13pub struct FirmwareUpdaterConfig<DFU, STATE> { 13pub struct FirmwareUpdaterConfig<DFU, STATE> {
14 /// The dfu flash partition 14 /// The dfu flash partition
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 3f00be4a8..3d5e3ab9f 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -581,6 +581,15 @@ impl embassy_time_queue_driver::TimerQueue for TimerQueue {
581#[cfg(feature = "integrated-timers")] 581#[cfg(feature = "integrated-timers")]
582embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); 582embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue);
583 583
584#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))]
585const fn gcd(a: u64, b: u64) -> u64 {
586 if b == 0 {
587 a
588 } else {
589 gcd(b, a % b)
590 }
591}
592
584#[cfg(feature = "rtos-trace")] 593#[cfg(feature = "rtos-trace")]
585impl rtos_trace::RtosTraceOSCallbacks for Executor { 594impl rtos_trace::RtosTraceOSCallbacks for Executor {
586 fn task_list() { 595 fn task_list() {
@@ -588,7 +597,8 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor {
588 } 597 }
589 #[cfg(feature = "integrated-timers")] 598 #[cfg(feature = "integrated-timers")]
590 fn time() -> u64 { 599 fn time() -> u64 {
591 Instant::now().as_micros() 600 const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000);
601 embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M)
592 } 602 }
593 #[cfg(not(feature = "integrated-timers"))] 603 #[cfg(not(feature = "integrated-timers"))]
594 fn time() -> u64 { 604 fn time() -> u64 {
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 6b6f79188..8937159df 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -13,7 +13,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
13pub use pac::spim0::config::ORDER_A as BitOrder; 13pub use pac::spim0::config::ORDER_A as BitOrder;
14pub use pac::spim0::frequency::FREQUENCY_A as Frequency; 14pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
15 15
16use crate::chip::FORCE_COPY_BUFFER_SIZE; 16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
17use crate::gpio::sealed::Pin as _; 17use crate::gpio::sealed::Pin as _;
18use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; 18use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
19use crate::interrupt::typelevel::Interrupt; 19use crate::interrupt::typelevel::Interrupt;
@@ -25,9 +25,9 @@ use crate::{interrupt, pac, Peripheral};
25#[cfg_attr(feature = "defmt", derive(defmt::Format))] 25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[non_exhaustive] 26#[non_exhaustive]
27pub enum Error { 27pub enum Error {
28 /// TX buffer was too long. 28 /// Supplied TX buffer overflows EasyDMA transmit buffer
29 TxBufferTooLong, 29 TxBufferTooLong,
30 /// RX buffer was too long. 30 /// Supplied RX buffer overflows EasyDMA receive buffer
31 RxBufferTooLong, 31 RxBufferTooLong,
32 /// EasyDMA can only read from data memory, read only buffers in flash will fail. 32 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
33 BufferNotInRAM, 33 BufferNotInRAM,
@@ -220,11 +220,19 @@ impl<'d, T: Instance> Spim<'d, T> {
220 220
221 // Set up the DMA write. 221 // Set up the DMA write.
222 let (ptr, tx_len) = slice_ptr_parts(tx); 222 let (ptr, tx_len) = slice_ptr_parts(tx);
223 if tx_len > EASY_DMA_SIZE {
224 return Err(Error::TxBufferTooLong);
225 }
226
223 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 227 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
224 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); 228 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) });
225 229
226 // Set up the DMA read. 230 // Set up the DMA read.
227 let (ptr, rx_len) = slice_ptr_parts_mut(rx); 231 let (ptr, rx_len) = slice_ptr_parts_mut(rx);
232 if rx_len > EASY_DMA_SIZE {
233 return Err(Error::RxBufferTooLong);
234 }
235
228 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 236 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
229 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); 237 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
230 238
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 60f4c9865..772ca40cc 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -11,7 +11,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
11pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 11pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
12pub use pac::spis0::config::ORDER_A as BitOrder; 12pub use pac::spis0::config::ORDER_A as BitOrder;
13 13
14use crate::chip::FORCE_COPY_BUFFER_SIZE; 14use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
15use crate::gpio::sealed::Pin as _; 15use crate::gpio::sealed::Pin as _;
16use crate::gpio::{self, AnyPin, Pin as GpioPin}; 16use crate::gpio::{self, AnyPin, Pin as GpioPin};
17use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
@@ -227,11 +227,17 @@ impl<'d, T: Instance> Spis<'d, T> {
227 227
228 // Set up the DMA write. 228 // Set up the DMA write.
229 let (ptr, len) = slice_ptr_parts(tx); 229 let (ptr, len) = slice_ptr_parts(tx);
230 if len > EASY_DMA_SIZE {
231 return Err(Error::TxBufferTooLong);
232 }
230 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 233 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
231 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 234 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
232 235
233 // Set up the DMA read. 236 // Set up the DMA read.
234 let (ptr, len) = slice_ptr_parts_mut(rx); 237 let (ptr, len) = slice_ptr_parts_mut(rx);
238 if len > EASY_DMA_SIZE {
239 return Err(Error::RxBufferTooLong);
240 }
235 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 241 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
236 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 242 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
237 243
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 8f0fc1c59..3f5f12f06 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -68,7 +68,7 @@ rand_core = "0.6.3"
68sdio-host = "0.5.0" 68sdio-host = "0.5.0"
69critical-section = "1.1" 69critical-section = "1.1"
70#stm32-metapac = { version = "15" } 70#stm32-metapac = { version = "15" }
71stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24" } 71stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76" }
72vcell = "0.1.3" 72vcell = "0.1.3"
73bxcan = "0.7.0" 73bxcan = "0.7.0"
74nb = "1.0.0" 74nb = "1.0.0"
@@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] }
89proc-macro2 = "1.0.36" 89proc-macro2 = "1.0.36"
90quote = "1.0.15" 90quote = "1.0.15"
91#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 91#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
92stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24", default-features = false, features = ["metadata"]} 92stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76", default-features = false, features = ["metadata"]}
93 93
94 94
95[features] 95[features]
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index d21c3053f..51b4b5fcc 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -8,6 +8,7 @@
8#[cfg_attr(adc_f3, path = "f3.rs")] 8#[cfg_attr(adc_f3, path = "f3.rs")]
9#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] 9#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
10#[cfg_attr(adc_v1, path = "v1.rs")] 10#[cfg_attr(adc_v1, path = "v1.rs")]
11#[cfg_attr(adc_l0, path = "v1.rs")]
11#[cfg_attr(adc_v2, path = "v2.rs")] 12#[cfg_attr(adc_v2, path = "v2.rs")]
12#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] 13#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
13#[cfg_attr(adc_v4, path = "v4.rs")] 14#[cfg_attr(adc_v4, path = "v4.rs")]
@@ -36,15 +37,15 @@ pub struct Adc<'d, T: Instance> {
36} 37}
37 38
38pub(crate) mod sealed { 39pub(crate) mod sealed {
39 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 40 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
40 use embassy_sync::waitqueue::AtomicWaker; 41 use embassy_sync::waitqueue::AtomicWaker;
41 42
42 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 43 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
43 pub struct State { 44 pub struct State {
44 pub waker: AtomicWaker, 45 pub waker: AtomicWaker,
45 } 46 }
46 47
47 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 48 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
48 impl State { 49 impl State {
49 pub const fn new() -> Self { 50 pub const fn new() -> Self {
50 Self { 51 Self {
@@ -59,14 +60,14 @@ pub(crate) mod sealed {
59 60
60 pub trait Instance: InterruptableInstance { 61 pub trait Instance: InterruptableInstance {
61 fn regs() -> crate::pac::adc::Adc; 62 fn regs() -> crate::pac::adc::Adc;
62 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 63 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
63 fn common_regs() -> crate::pac::adccommon::AdcCommon; 64 fn common_regs() -> crate::pac::adccommon::AdcCommon;
64 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 65 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
65 fn state() -> &'static State; 66 fn state() -> &'static State;
66 } 67 }
67 68
68 pub trait AdcPin<T: Instance> { 69 pub trait AdcPin<T: Instance> {
69 #[cfg(any(adc_v1, adc_v2))] 70 #[cfg(any(adc_v1, adc_l0, adc_v2))]
70 fn set_as_analog(&mut self) {} 71 fn set_as_analog(&mut self) {}
71 72
72 fn channel(&self) -> u8; 73 fn channel(&self) -> u8;
@@ -78,10 +79,10 @@ pub(crate) mod sealed {
78} 79}
79 80
80/// ADC instance. 81/// ADC instance.
81#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] 82#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
82pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 83pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
83/// ADC instance. 84/// ADC instance.
84#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] 85#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
85pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 86pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
86 87
87/// ADC pin. 88/// ADC pin.
@@ -96,12 +97,12 @@ foreach_adc!(
96 crate::pac::$inst 97 crate::pac::$inst
97 } 98 }
98 99
99 #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 100 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
100 fn common_regs() -> crate::pac::adccommon::AdcCommon { 101 fn common_regs() -> crate::pac::adccommon::AdcCommon {
101 return crate::pac::$common_inst 102 return crate::pac::$common_inst
102 } 103 }
103 104
104 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] 105 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
105 fn state() -> &'static sealed::State { 106 fn state() -> &'static sealed::State {
106 static STATE: sealed::State = sealed::State::new(); 107 static STATE: sealed::State = sealed::State::new();
107 &STATE 108 &STATE
@@ -125,7 +126,7 @@ macro_rules! impl_adc_pin {
125 impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} 126 impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
126 127
127 impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { 128 impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
128 #[cfg(any(adc_v1, adc_v2))] 129 #[cfg(any(adc_v1, adc_l0, adc_v2))]
129 fn set_as_analog(&mut self) { 130 fn set_as_analog(&mut self) {
130 <Self as crate::gpio::sealed::Pin>::set_as_analog(self); 131 <Self as crate::gpio::sealed::Pin>::set_as_analog(self);
131 } 132 }
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
index 9513e1df7..0e6c45c65 100644
--- a/embassy-stm32/src/adc/resolution.rs
+++ b/embassy-stm32/src/adc/resolution.rs
@@ -1,6 +1,6 @@
1/// ADC resolution 1/// ADC resolution
2#[allow(missing_docs)] 2#[allow(missing_docs)]
3#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] 3#[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
4#[derive(Clone, Copy, Debug, Eq, PartialEq)] 4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub enum Resolution { 6pub enum Resolution {
@@ -25,7 +25,7 @@ pub enum Resolution {
25 25
26impl Default for Resolution { 26impl Default for Resolution {
27 fn default() -> Self { 27 fn default() -> Self {
28 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] 28 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
29 { 29 {
30 Self::TwelveBit 30 Self::TwelveBit
31 } 31 }
@@ -46,7 +46,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
46 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, 46 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
47 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, 47 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
48 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, 48 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
49 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] 49 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
50 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, 50 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
51 } 51 }
52 } 52 }
@@ -65,7 +65,7 @@ impl Resolution {
65 Resolution::TwelveBit => (1 << 12) - 1, 65 Resolution::TwelveBit => (1 << 12) - 1,
66 Resolution::TenBit => (1 << 10) - 1, 66 Resolution::TenBit => (1 << 10) - 1,
67 Resolution::EightBit => (1 << 8) - 1, 67 Resolution::EightBit => (1 << 8) - 1,
68 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] 68 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
69 Resolution::SixBit => (1 << 6) - 1, 69 Resolution::SixBit => (1 << 6) - 1,
70 } 70 }
71 } 71 }
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index 5a06f1a5a..f4b22b462 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -83,7 +83,7 @@ impl_sample_time!(
83 ) 83 )
84); 84);
85 85
86#[cfg(adc_g0)] 86#[cfg(any(adc_l0, adc_g0))]
87impl_sample_time!( 87impl_sample_time!(
88 "1.5", 88 "1.5",
89 Cycles1_5, 89 Cycles1_5,
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 852b027df..37115dfab 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -4,6 +4,8 @@ use core::task::Poll;
4 4
5use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
6use embedded_hal_02::blocking::delay::DelayUs; 6use embedded_hal_02::blocking::delay::DelayUs;
7#[cfg(adc_l0)]
8use stm32_metapac::adc::vals::Ckmode;
7 9
8use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; 10use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
9use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
@@ -30,8 +32,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
30 } 32 }
31} 33}
32 34
35#[cfg(not(adc_l0))]
33pub struct Vbat; 36pub struct Vbat;
37
38#[cfg(not(adc_l0))]
34impl AdcPin<ADC> for Vbat {} 39impl AdcPin<ADC> for Vbat {}
40
41#[cfg(not(adc_l0))]
35impl super::sealed::AdcPin<ADC> for Vbat { 42impl super::sealed::AdcPin<ADC> for Vbat {
36 fn channel(&self) -> u8 { 43 fn channel(&self) -> u8 {
37 18 44 18
@@ -69,9 +76,18 @@ impl<'d, T: Instance> Adc<'d, T> {
69 // tstab = 14 * 1/fadc 76 // tstab = 14 * 1/fadc
70 delay.delay_us(1); 77 delay.delay_us(1);
71 78
79 // set default PCKL/2 on L0s because HSI is disabled in the default clock config
80 #[cfg(adc_l0)]
81 T::regs().cfgr2().modify(|reg| reg.set_ckmode(Ckmode::PCLK_DIV2));
82
72 // A.7.1 ADC calibration code example 83 // A.7.1 ADC calibration code example
73 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); 84 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
74 T::regs().cr().modify(|reg| reg.set_adcal(true)); 85 T::regs().cr().modify(|reg| reg.set_adcal(true));
86
87 #[cfg(adc_l0)]
88 while !T::regs().isr().read().eocal() {}
89
90 #[cfg(not(adc_l0))]
75 while T::regs().cr().read().adcal() {} 91 while T::regs().cr().read().adcal() {}
76 92
77 // A.7.2 ADC enable sequence code example 93 // A.7.2 ADC enable sequence code example
@@ -97,6 +113,7 @@ impl<'d, T: Instance> Adc<'d, T> {
97 } 113 }
98 } 114 }
99 115
116 #[cfg(not(adc_l0))]
100 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { 117 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
101 // SMP must be ≥ 56 ADC clock cycles when using HSI14. 118 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
102 // 119 //
@@ -133,6 +150,12 @@ impl<'d, T: Instance> Adc<'d, T> {
133 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 150 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
134 } 151 }
135 152
153 #[cfg(adc_l0)]
154 pub fn set_ckmode(&mut self, ckmode: Ckmode) {
155 // set ADC clock mode
156 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
157 }
158
136 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { 159 pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
137 let channel = pin.channel(); 160 let channel = pin.channel();
138 pin.set_as_analog(); 161 pin.set_as_analog();
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index a2b83716d..077cfdcd9 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -664,6 +664,13 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
664 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 664 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
665 } 665 }
666 666
667 /// Write elements directly to the raw buffer.
668 /// This can be used to fill the buffer before starting the DMA transfer.
669 #[allow(dead_code)]
670 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
671 self.ringbuf.write_immediate(buf)
672 }
673
667 /// Write elements to the ring buffer 674 /// Write elements to the ring buffer
668 /// Return a tuple of the length written and the length remaining in the buffer 675 /// Return a tuple of the length written and the length remaining in the buffer
669 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { 676 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 16d02f273..ef9bb3d78 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -934,6 +934,13 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
934 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 934 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
935 } 935 }
936 936
937 /// Write elements directly to the raw buffer.
938 /// This can be used to fill the buffer before starting the DMA transfer.
939 #[allow(dead_code)]
940 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
941 self.ringbuf.write_immediate(buf)
942 }
943
937 /// Write elements from the ring buffer 944 /// Write elements from the ring buffer
938 /// Return a tuple of the length written and the length remaining in the buffer 945 /// Return a tuple of the length written and the length remaining in the buffer
939 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { 946 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs
index c9f7a3026..23f1d67d5 100644
--- a/embassy-stm32/src/dma/ringbuffer.rs
+++ b/embassy-stm32/src/dma/ringbuffer.rs
@@ -37,6 +37,7 @@ pub struct ReadableDmaRingBuffer<'a, W: Word> {
37} 37}
38 38
39#[derive(Debug, PartialEq)] 39#[derive(Debug, PartialEq)]
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub struct OverrunError; 41pub struct OverrunError;
41 42
42pub trait DmaCtrl { 43pub trait DmaCtrl {
@@ -263,6 +264,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
263 self.cap() - dma.get_remaining_transfers() 264 self.cap() - dma.get_remaining_transfers()
264 } 265 }
265 266
267 /// Write elements directly to the buffer. This must be done before the DMA is started
268 /// or after the buffer has been cleared using `clear()`.
269 pub fn write_immediate(&mut self, buffer: &[W]) -> Result<(usize, usize), OverrunError> {
270 if self.end != 0 {
271 return Err(OverrunError);
272 }
273 let written = self.copy_from(buffer, 0..self.cap());
274 self.end = written % self.cap();
275 Ok((written, self.cap() - written))
276 }
277
266 /// Write an exact number of elements to the ringbuffer. 278 /// Write an exact number of elements to the ringbuffer.
267 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> { 279 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> {
268 let mut written_data = 0; 280 let mut written_data = 0;
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 352e10816..474c44115 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -658,6 +658,7 @@ pub(crate) unsafe fn init(config: Config) {
658 #[cfg(stm32h5)] 658 #[cfg(stm32h5)]
659 audioclk: None, 659 audioclk: None,
660 per: None, 660 per: None,
661 i2s_ckin: None,
661 ); 662 );
662} 663}
663 664
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 9cec6c96c..20cc3112a 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -477,6 +477,7 @@ pub(crate) unsafe fn init(config: Config) {
477 pll3_p: None, 477 pll3_p: None,
478 pll3_q: None, 478 pll3_q: None,
479 pll3_r: None, 479 pll3_r: None,
480 iclk: None,
480 ); 481 );
481} 482}
482 483
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 320b29ddb..29ff4a736 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -14,7 +14,7 @@ use crate::pac::timer::vals;
14use crate::rcc::sealed::RccPeripheral; 14use crate::rcc::sealed::RccPeripheral;
15#[cfg(feature = "low-power")] 15#[cfg(feature = "low-power")]
16use crate::rtc::Rtc; 16use crate::rtc::Rtc;
17use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; 17use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance};
18use crate::{interrupt, peripherals}; 18use crate::{interrupt, peripherals};
19 19
20// NOTE regarding ALARM_COUNT: 20// NOTE regarding ALARM_COUNT:
@@ -234,8 +234,8 @@ impl RtcDriver {
234 w.set_ccie(0, true); 234 w.set_ccie(0, true);
235 }); 235 });
236 236
237 <T as BasicInstance>::Interrupt::unpend(); 237 <T as CoreInstance>::Interrupt::unpend();
238 unsafe { <T as BasicInstance>::Interrupt::enable() }; 238 unsafe { <T as CoreInstance>::Interrupt::enable() };
239 239
240 r.cr1().modify(|w| w.set_cen(true)); 240 r.cr1().modify(|w| w.set_cen(true));
241 } 241 }
@@ -251,7 +251,7 @@ impl RtcDriver {
251 // Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT. 251 // Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT.
252 // Other approaches such as writing all zeros, or RMWing won't work, they can 252 // Other approaches such as writing all zeros, or RMWing won't work, they can
253 // miss interrupts. 253 // miss interrupts.
254 r.sr().write_value(regs::SrGp(!sr.0)); 254 r.sr().write_value(regs::SrGp16(!sr.0));
255 255
256 // Overflow 256 // Overflow
257 if sr.uif() { 257 if sr.uif() {
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index eddce0404..72f1ec864 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -23,7 +23,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
23 23
24macro_rules! complementary_channel_impl { 24macro_rules! complementary_channel_impl {
25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
26 impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { 26 impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
27 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 27 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
28 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { 28 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
29 into_ref!(pin); 29 into_ref!(pin);
@@ -84,14 +84,13 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
84 84
85 this.inner.enable_outputs(); 85 this.inner.enable_outputs();
86 86
87 this.inner 87 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
88 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); 88 .iter()
89 this.inner 89 .for_each(|&channel| {
90 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); 90 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
91 this.inner 91 this.inner.set_output_compare_preload(channel, true);
92 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); 92 });
93 this.inner 93
94 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
95 this 94 this
96 } 95 }
97 96
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 210bf7153..9480d6972 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,5 +1,37 @@
1//! Timers, PWM, quadrature decoder. 1//! Timers, PWM, quadrature decoder.
2 2//!
3
4//! Timer inheritance
5//!
6
7// sealed:
8//
9// Core -------------------------> 1CH -------------------------> 1CH_CMP
10// | | ^ |
11// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV
12// | | | ^ | | ^ ^
13// | | +------|--|--------------|-----------+ |
14// | +--------------------+ +--------------|-----------|---------+
15// | | | |
16// | +--------------------------------------|-----------+
17// +----------------------------------------------------+
18
19//! ```text
20//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance
21//! |
22//! +--> CaptureCompare32bitInstance
23//! ```
24//!
25//! Mapping:
26//!
27//! | trait | timer |
28//! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- |
29//! | [BasicInstance] | Basic Timer |
30//! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer |
31//! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer |
32//! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer |
33
34#[cfg(not(stm32l0))]
3pub mod complementary_pwm; 35pub mod complementary_pwm;
4pub mod qei; 36pub mod qei;
5pub mod simple_pwm; 37pub mod simple_pwm;
@@ -19,32 +51,32 @@ pub mod low_level {
19pub(crate) mod sealed { 51pub(crate) mod sealed {
20 use super::*; 52 use super::*;
21 53
22 /// Basic 16-bit timer instance. 54 /// Virtual Core 16-bit timer instance.
23 pub trait Basic16bitInstance: RccPeripheral { 55 pub trait CoreInstance: RccPeripheral {
24 /// Interrupt for this timer. 56 /// Interrupt for this timer.
25 type Interrupt: interrupt::typelevel::Interrupt; 57 type Interrupt: interrupt::typelevel::Interrupt;
26 58
27 /// Get access to the basic 16bit timer registers. 59 /// Get access to the virutal core 16bit timer registers.
28 /// 60 ///
29 /// Note: This works even if the timer is more capable, because registers 61 /// Note: This works even if the timer is more capable, because registers
30 /// for the less capable timers are a subset. This allows writing a driver 62 /// for the less capable timers are a subset. This allows writing a driver
31 /// for a given set of capabilities, and having it transparently work with 63 /// for a given set of capabilities, and having it transparently work with
32 /// more capable timers. 64 /// more capable timers.
33 fn regs() -> crate::pac::timer::TimBasic; 65 fn regs_core() -> crate::pac::timer::TimCore;
34 66
35 /// Start the timer. 67 /// Start the timer.
36 fn start(&mut self) { 68 fn start(&mut self) {
37 Self::regs().cr1().modify(|r| r.set_cen(true)); 69 Self::regs_core().cr1().modify(|r| r.set_cen(true));
38 } 70 }
39 71
40 /// Stop the timer. 72 /// Stop the timer.
41 fn stop(&mut self) { 73 fn stop(&mut self) {
42 Self::regs().cr1().modify(|r| r.set_cen(false)); 74 Self::regs_core().cr1().modify(|r| r.set_cen(false));
43 } 75 }
44 76
45 /// Reset the counter value to 0 77 /// Reset the counter value to 0
46 fn reset(&mut self) { 78 fn reset(&mut self) {
47 Self::regs().cnt().write(|r| r.set_cnt(0)); 79 Self::regs_core().cnt().write(|r| r.set_cnt(0));
48 } 80 }
49 81
50 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. 82 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
@@ -64,7 +96,7 @@ pub(crate) mod sealed {
64 // the timer counts `0..=arr`, we want it to count `0..divide_by` 96 // the timer counts `0..=arr`, we want it to count `0..divide_by`
65 let arr = unwrap!(u16::try_from(divide_by - 1)); 97 let arr = unwrap!(u16::try_from(divide_by - 1));
66 98
67 let regs = Self::regs(); 99 let regs = Self::regs_core();
68 regs.psc().write(|r| r.set_psc(psc)); 100 regs.psc().write(|r| r.set_psc(psc));
69 regs.arr().write(|r| r.set_arr(arr)); 101 regs.arr().write(|r| r.set_arr(arr));
70 102
@@ -77,7 +109,7 @@ pub(crate) mod sealed {
77 /// 109 ///
78 /// Returns whether the update interrupt flag was set. 110 /// Returns whether the update interrupt flag was set.
79 fn clear_update_interrupt(&mut self) -> bool { 111 fn clear_update_interrupt(&mut self) -> bool {
80 let regs = Self::regs(); 112 let regs = Self::regs_core();
81 let sr = regs.sr().read(); 113 let sr = regs.sr().read();
82 if sr.uif() { 114 if sr.uif() {
83 regs.sr().modify(|r| { 115 regs.sr().modify(|r| {
@@ -91,29 +123,19 @@ pub(crate) mod sealed {
91 123
92 /// Enable/disable the update interrupt. 124 /// Enable/disable the update interrupt.
93 fn enable_update_interrupt(&mut self, enable: bool) { 125 fn enable_update_interrupt(&mut self, enable: bool) {
94 Self::regs().dier().modify(|r| r.set_uie(enable)); 126 Self::regs_core().dier().modify(|r| r.set_uie(enable));
95 }
96
97 /// Enable/disable the update dma.
98 fn enable_update_dma(&mut self, enable: bool) {
99 Self::regs().dier().modify(|r| r.set_ude(enable));
100 }
101
102 /// Get the update dma enable/disable state.
103 fn get_update_dma_state(&self) -> bool {
104 Self::regs().dier().read().ude()
105 } 127 }
106 128
107 /// Enable/disable autoreload preload. 129 /// Enable/disable autoreload preload.
108 fn set_autoreload_preload(&mut self, enable: bool) { 130 fn set_autoreload_preload(&mut self, enable: bool) {
109 Self::regs().cr1().modify(|r| r.set_arpe(enable)); 131 Self::regs_core().cr1().modify(|r| r.set_arpe(enable));
110 } 132 }
111 133
112 /// Get the timer frequency. 134 /// Get the timer frequency.
113 fn get_frequency(&self) -> Hertz { 135 fn get_frequency(&self) -> Hertz {
114 let timer_f = Self::frequency(); 136 let timer_f = Self::frequency();
115 137
116 let regs = Self::regs(); 138 let regs = Self::regs_core();
117 let arr = regs.arr().read().arr(); 139 let arr = regs.arr().read().arr();
118 let psc = regs.psc().read().psc(); 140 let psc = regs.psc().read().psc();
119 141
@@ -121,91 +143,101 @@ pub(crate) mod sealed {
121 } 143 }
122 } 144 }
123 145
124 /// Gneral-purpose 16-bit timer instance. 146 /// Virtual Basic without CR2 16-bit timer instance.
125 pub trait GeneralPurpose16bitInstance: Basic16bitInstance { 147 pub trait BasicNoCr2Instance: CoreInstance {
126 /// Get access to the general purpose 16bit timer registers. 148 /// Get access to the Baisc 16bit timer registers.
127 /// 149 ///
128 /// Note: This works even if the timer is more capable, because registers 150 /// Note: This works even if the timer is more capable, because registers
129 /// for the less capable timers are a subset. This allows writing a driver 151 /// for the less capable timers are a subset. This allows writing a driver
130 /// for a given set of capabilities, and having it transparently work with 152 /// for a given set of capabilities, and having it transparently work with
131 /// more capable timers. 153 /// more capable timers.
132 fn regs_gp16() -> crate::pac::timer::TimGp16; 154 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2;
133
134 /// Set counting mode.
135 fn set_counting_mode(&mut self, mode: CountingMode) {
136 let (cms, dir) = mode.into();
137
138 let timer_enabled = Self::regs().cr1().read().cen();
139 // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
140 // Changing direction is discouraged while the timer is running.
141 assert!(!timer_enabled);
142 155
143 Self::regs_gp16().cr1().modify(|r| r.set_dir(dir)); 156 /// Enable/disable the update dma.
144 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) 157 fn enable_update_dma(&mut self, enable: bool) {
158 Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
145 } 159 }
146 160
147 /// Get counting mode. 161 /// Get the update dma enable/disable state.
148 fn get_counting_mode(&self) -> CountingMode { 162 fn get_update_dma_state(&self) -> bool {
149 let cr1 = Self::regs_gp16().cr1().read(); 163 Self::regs_basic_no_cr2().dier().read().ude()
150 (cr1.cms(), cr1.dir()).into()
151 } 164 }
165 }
166
167 /// Basic 16-bit timer instance.
168 pub trait BasicInstance: BasicNoCr2Instance {
169 /// Get access to the Baisc 16bit timer registers.
170 ///
171 /// Note: This works even if the timer is more capable, because registers
172 /// for the less capable timers are a subset. This allows writing a driver
173 /// for a given set of capabilities, and having it transparently work with
174 /// more capable timers.
175 fn regs_basic() -> crate::pac::timer::TimBasic;
176 }
177
178 /// Gneral-purpose 1 channel 16-bit timer instance.
179 pub trait GeneralPurpose1ChannelInstance: CoreInstance {
180 /// Get access to the general purpose 1 channel 16bit timer registers.
181 ///
182 /// Note: This works even if the timer is more capable, because registers
183 /// for the less capable timers are a subset. This allows writing a driver
184 /// for a given set of capabilities, and having it transparently work with
185 /// more capable timers.
186 fn regs_1ch() -> crate::pac::timer::Tim1ch;
152 187
153 /// Set clock divider. 188 /// Set clock divider.
154 fn set_clock_division(&mut self, ckd: vals::Ckd) { 189 fn set_clock_division(&mut self, ckd: vals::Ckd) {
155 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); 190 Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
191 }
192
193 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
194 fn get_max_compare_value(&self) -> u16 {
195 Self::regs_1ch().arr().read().arr()
156 } 196 }
157 } 197 }
158 198
159 /// Gneral-purpose 32-bit timer instance. 199 /// Gneral-purpose 1 channel 16-bit timer instance.
160 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { 200 pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance {
161 /// Get access to the general purpose 32bit timer registers. 201 /// Get access to the general purpose 2 channel 16bit timer registers.
162 /// 202 ///
163 /// Note: This works even if the timer is more capable, because registers 203 /// Note: This works even if the timer is more capable, because registers
164 /// for the less capable timers are a subset. This allows writing a driver 204 /// for the less capable timers are a subset. This allows writing a driver
165 /// for a given set of capabilities, and having it transparently work with 205 /// for a given set of capabilities, and having it transparently work with
166 /// more capable timers. 206 /// more capable timers.
167 fn regs_gp32() -> crate::pac::timer::TimGp32; 207 fn regs_2ch() -> crate::pac::timer::Tim2ch;
168 208 }
169 /// Set timer frequency.
170 fn set_frequency(&mut self, frequency: Hertz) {
171 let f = frequency.0;
172 assert!(f > 0);
173 let timer_f = Self::frequency().0;
174 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
175 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
176 let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
177
178 let regs = Self::regs_gp32();
179 regs.psc().write(|r| r.set_psc(psc));
180 regs.arr().write(|r| r.set_arr(arr));
181 209
182 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); 210 /// Gneral-purpose 16-bit timer instance.
183 regs.egr().write(|r| r.set_ug(true)); 211 pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance {
184 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 212 /// Get access to the general purpose 16bit timer registers.
185 } 213 ///
214 /// Note: This works even if the timer is more capable, because registers
215 /// for the less capable timers are a subset. This allows writing a driver
216 /// for a given set of capabilities, and having it transparently work with
217 /// more capable timers.
218 fn regs_gp16() -> crate::pac::timer::TimGp16;
186 219
187 /// Get timer frequency. 220 /// Set counting mode.
188 fn get_frequency(&self) -> Hertz { 221 fn set_counting_mode(&mut self, mode: CountingMode) {
189 let timer_f = Self::frequency(); 222 let (cms, dir) = mode.into();
190 223
191 let regs = Self::regs_gp32(); 224 let timer_enabled = Self::regs_core().cr1().read().cen();
192 let arr = regs.arr().read().arr(); 225 // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
193 let psc = regs.psc().read().psc(); 226 // Changing direction is discouraged while the timer is running.
227 assert!(!timer_enabled);
194 228
195 timer_f / arr / (psc + 1) 229 Self::regs_gp16().cr1().modify(|r| r.set_dir(dir));
230 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
196 } 231 }
197 }
198 232
199 /// Advanced control timer instance. 233 /// Get counting mode.
200 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { 234 fn get_counting_mode(&self) -> CountingMode {
201 /// Get access to the advanced timer registers. 235 let cr1 = Self::regs_gp16().cr1().read();
202 fn regs_advanced() -> crate::pac::timer::TimAdv; 236 (cr1.cms(), cr1.dir()).into()
203 } 237 }
204 238
205 /// Capture/Compare 16-bit timer instance.
206 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
207 /// Set input capture filter. 239 /// Set input capture filter.
208 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { 240 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) {
209 let raw_channel = channel.index(); 241 let raw_channel = channel.index();
210 Self::regs_gp16() 242 Self::regs_gp16()
211 .ccmr_input(raw_channel / 2) 243 .ccmr_input(raw_channel / 2)
@@ -256,14 +288,11 @@ pub(crate) mod sealed {
256 }); 288 });
257 } 289 }
258 290
259 /// Enable timer outputs.
260 fn enable_outputs(&mut self);
261
262 /// Set output compare mode. 291 /// Set output compare mode.
263 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { 292 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
264 let r = Self::regs_gp16();
265 let raw_channel: usize = channel.index(); 293 let raw_channel: usize = channel.index();
266 r.ccmr_output(raw_channel / 2) 294 Self::regs_gp16()
295 .ccmr_output(raw_channel / 2)
267 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 296 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
268 } 297 }
269 298
@@ -294,11 +323,6 @@ pub(crate) mod sealed {
294 Self::regs_gp16().ccr(channel.index()).read().ccr() 323 Self::regs_gp16().ccr(channel.index()).read().ccr()
295 } 324 }
296 325
297 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
298 fn get_max_compare_value(&self) -> u16 {
299 Self::regs_gp16().arr().read().arr()
300 }
301
302 /// Get compare value for a channel. 326 /// Get compare value for a channel.
303 fn get_compare_value(&self, channel: Channel) -> u16 { 327 fn get_compare_value(&self, channel: Channel) -> u16 {
304 Self::regs_gp16().ccr(channel.index()).read().ccr() 328 Self::regs_gp16().ccr(channel.index()).read().ccr()
@@ -333,35 +357,46 @@ pub(crate) mod sealed {
333 } 357 }
334 } 358 }
335 359
336 /// Capture/Compare 16-bit timer instance with complementary pin support. 360 #[cfg(not(stm32l0))]
337 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { 361 /// Gneral-purpose 32-bit timer instance.
338 /// Set complementary output polarity. 362 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
339 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 363 /// Get access to the general purpose 32bit timer registers.
340 Self::regs_advanced() 364 ///
341 .ccer() 365 /// Note: This works even if the timer is more capable, because registers
342 .modify(|w| w.set_ccnp(channel.index(), polarity.into())); 366 /// for the less capable timers are a subset. This allows writing a driver
343 } 367 /// for a given set of capabilities, and having it transparently work with
368 /// more capable timers.
369 fn regs_gp32() -> crate::pac::timer::TimGp32;
344 370
345 /// Set clock divider for the dead time. 371 /// Set timer frequency.
346 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { 372 fn set_frequency(&mut self, frequency: Hertz) {
347 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 373 let f = frequency.0;
348 } 374 assert!(f > 0);
375 let timer_f = Self::frequency().0;
376 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
377 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
378 let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
349 379
350 /// Set dead time, as a fraction of the max duty value. 380 let regs = Self::regs_gp32();
351 fn set_dead_time_value(&mut self, value: u8) { 381 regs.psc().write(|r| r.set_psc(psc));
352 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 382 regs.arr().write(|r| r.set_arr(arr));
383
384 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
385 regs.egr().write(|r| r.set_ug(true));
386 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
353 } 387 }
354 388
355 /// Enable/disable a complementary channel. 389 /// Get timer frequency.
356 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 390 fn get_frequency(&self) -> Hertz {
357 Self::regs_advanced() 391 let timer_f = Self::frequency();
358 .ccer() 392
359 .modify(|w| w.set_ccne(channel.index(), enable)); 393 let regs = Self::regs_gp32();
394 let arr = regs.arr().read().arr();
395 let psc = regs.psc().read().psc();
396
397 timer_f / arr / (psc + 1)
360 } 398 }
361 }
362 399
363 /// Capture/Compare 32-bit timer instance.
364 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
365 /// Set comapre value for a channel. 400 /// Set comapre value for a channel.
366 fn set_compare_value(&mut self, channel: Channel, value: u32) { 401 fn set_compare_value(&mut self, channel: Channel, value: u32) {
367 Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); 402 Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value));
@@ -382,6 +417,70 @@ pub(crate) mod sealed {
382 Self::regs_gp32().ccr(channel.index()).read().ccr() 417 Self::regs_gp32().ccr(channel.index()).read().ccr()
383 } 418 }
384 } 419 }
420
421 #[cfg(not(stm32l0))]
422 /// Gneral-purpose 1 channel with one complementary 16-bit timer instance.
423 pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance {
424 /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
425 ///
426 /// Note: This works even if the timer is more capable, because registers
427 /// for the less capable timers are a subset. This allows writing a driver
428 /// for a given set of capabilities, and having it transparently work with
429 /// more capable timers.
430 fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp;
431
432 /// Set clock divider for the dead time.
433 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
434 Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
435 }
436
437 /// Set dead time, as a fraction of the max duty value.
438 fn set_dead_time_value(&mut self, value: u8) {
439 Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
440 }
441
442 /// Enable timer outputs.
443 fn enable_outputs(&mut self) {
444 Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true));
445 }
446 }
447
448 #[cfg(not(stm32l0))]
449 /// Gneral-purpose 2 channel with one complementary 16-bit timer instance.
450 pub trait GeneralPurpose2ChannelComplementaryInstance:
451 BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance
452 {
453 /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
454 ///
455 /// Note: This works even if the timer is more capable, because registers
456 /// for the less capable timers are a subset. This allows writing a driver
457 /// for a given set of capabilities, and having it transparently work with
458 /// more capable timers.
459 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp;
460 }
461
462 #[cfg(not(stm32l0))]
463 /// Advanced control timer instance.
464 pub trait AdvancedControlInstance:
465 GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance
466 {
467 /// Get access to the advanced timer registers.
468 fn regs_advanced() -> crate::pac::timer::TimAdv;
469
470 /// Set complementary output polarity.
471 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
472 Self::regs_advanced()
473 .ccer()
474 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
475 }
476
477 /// Enable/disable a complementary channel.
478 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
479 Self::regs_advanced()
480 .ccer()
481 .modify(|w| w.set_ccne(channel.index(), enable));
482 }
483 }
385} 484}
386 485
387/// Timer channel. 486/// Timer channel.
@@ -572,156 +671,281 @@ impl From<OutputPolarity> for bool {
572} 671}
573 672
574/// Basic 16-bit timer instance. 673/// Basic 16-bit timer instance.
575pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 674pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {}
576 675
577/// Gneral-purpose 16-bit timer instance. 676// It's just a General-purpose 16-bit timer instance.
578pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + Basic16bitInstance + 'static {} 677/// Capture Compare timer instance.
579
580/// Gneral-purpose 32-bit timer instance.
581pub trait GeneralPurpose32bitInstance:
582 sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static
583{
584}
585
586/// Advanced control timer instance.
587pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose16bitInstance + 'static {}
588
589/// Capture/Compare 16-bit timer instance.
590pub trait CaptureCompare16bitInstance: 678pub trait CaptureCompare16bitInstance:
591 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static 679 BasicInstance
680 + sealed::GeneralPurpose2ChannelInstance
681 + sealed::GeneralPurpose1ChannelInstance
682 + sealed::GeneralPurpose16bitInstance
683 + 'static
592{ 684{
593} 685}
594 686
595/// Capture/Compare 16-bit timer instance with complementary pin support. 687#[cfg(not(stm32l0))]
596pub trait ComplementaryCaptureCompare16bitInstance: 688// It's just a General-purpose 32-bit timer instance.
597 sealed::ComplementaryCaptureCompare16bitInstance + CaptureCompare16bitInstance + AdvancedControlInstance + 'static 689/// Capture Compare 32-bit timer instance.
690pub trait CaptureCompare32bitInstance:
691 CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static
598{ 692{
599} 693}
600 694
601/// Capture/Compare 32-bit timer instance. 695#[cfg(not(stm32l0))]
602pub trait CaptureCompare32bitInstance: 696// It's just a Advanced Control timer instance.
603 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static 697/// Complementary Capture Compare 32-bit timer instance.
698pub trait ComplementaryCaptureCompare16bitInstance:
699 CaptureCompare16bitInstance
700 + sealed::GeneralPurpose1ChannelComplementaryInstance
701 + sealed::GeneralPurpose2ChannelComplementaryInstance
702 + sealed::AdvancedControlInstance
703 + 'static
604{ 704{
605} 705}
606 706
607pin_trait!(Channel1Pin, CaptureCompare16bitInstance); 707pin_trait!(Channel1Pin, CaptureCompare16bitInstance);
608pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance);
609pin_trait!(Channel2Pin, CaptureCompare16bitInstance); 708pin_trait!(Channel2Pin, CaptureCompare16bitInstance);
610pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance);
611pin_trait!(Channel3Pin, CaptureCompare16bitInstance); 709pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
612pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance);
613pin_trait!(Channel4Pin, CaptureCompare16bitInstance); 710pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
614pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance);
615pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); 711pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
616pin_trait!(BreakInputPin, CaptureCompare16bitInstance); 712
617pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance); 713cfg_if::cfg_if! {
618pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); 714 if #[cfg(not(stm32l0))] {
619pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); 715 pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
620pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); 716 pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
621pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); 717 pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
718 pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
719
720 pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance);
721 pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance);
722
723 pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance);
724 pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance);
725
726 pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance);
727 pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance);
728 }
729}
622 730
623#[allow(unused)] 731#[allow(unused)]
624macro_rules! impl_basic_16bit_timer { 732macro_rules! impl_core_timer {
625 ($inst:ident, $irq:ident) => { 733 ($inst:ident, $irq:ident) => {
626 impl sealed::Basic16bitInstance for crate::peripherals::$inst { 734 impl sealed::CoreInstance for crate::peripherals::$inst {
627 type Interrupt = crate::interrupt::typelevel::$irq; 735 type Interrupt = crate::interrupt::typelevel::$irq;
628 736
629 fn regs() -> crate::pac::timer::TimBasic { 737 fn regs_core() -> crate::pac::timer::TimCore {
630 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } 738 unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) }
631 } 739 }
632 } 740 }
633 }; 741 };
634} 742}
635 743
636#[allow(unused)] 744#[allow(unused)]
637macro_rules! impl_32bit_timer { 745macro_rules! impl_basic_no_cr2_timer {
638 ($inst:ident) => { 746 ($inst:ident) => {
639 impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { 747 impl sealed::BasicNoCr2Instance for crate::peripherals::$inst {
640 fn regs_gp32() -> crate::pac::timer::TimGp32 { 748 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 {
641 crate::pac::$inst 749 unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) }
642 } 750 }
643 } 751 }
644 }; 752 };
645} 753}
646 754
647#[allow(unused)] 755#[allow(unused)]
648macro_rules! impl_compare_capable_16bit { 756macro_rules! impl_basic_timer {
649 ($inst:ident) => { 757 ($inst:ident) => {
650 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 758 impl sealed::BasicInstance for crate::peripherals::$inst {
651 fn enable_outputs(&mut self) {} 759 fn regs_basic() -> crate::pac::timer::TimBasic {
760 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
761 }
652 } 762 }
653 }; 763 };
654} 764}
655 765
656foreach_interrupt! { 766#[allow(unused)]
657 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 767macro_rules! impl_1ch_timer {
658 impl_basic_16bit_timer!($inst, $irq); 768 ($inst:ident) => {
659 impl Basic16bitInstance for crate::peripherals::$inst {} 769 impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst {
770 fn regs_1ch() -> crate::pac::timer::Tim1ch {
771 unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) }
772 }
773 }
660 }; 774 };
661 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 775}
662 impl_basic_16bit_timer!($inst, $irq);
663 impl_compare_capable_16bit!($inst);
664 impl Basic16bitInstance for crate::peripherals::$inst {}
665 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
666 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
667 776
668 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 777#[allow(unused)]
669 fn regs_gp16() -> crate::pac::timer::TimGp16 { 778macro_rules! impl_2ch_timer {
670 crate::pac::$inst 779 ($inst:ident) => {
780 impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst {
781 fn regs_2ch() -> crate::pac::timer::Tim2ch {
782 unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) }
671 } 783 }
672 } 784 }
673 }; 785 };
786}
674 787
675 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 788#[allow(unused)]
676 impl_basic_16bit_timer!($inst, $irq); 789macro_rules! impl_gp16_timer {
677 impl_32bit_timer!($inst); 790 ($inst:ident) => {
678 impl_compare_capable_16bit!($inst);
679 impl Basic16bitInstance for crate::peripherals::$inst {}
680 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
681 impl CaptureCompare32bitInstance for crate::peripherals::$inst {}
682 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
683 impl GeneralPurpose32bitInstance for crate::peripherals::$inst {}
684 impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {}
685
686 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 791 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
687 fn regs_gp16() -> crate::pac::timer::TimGp16 { 792 fn regs_gp16() -> crate::pac::timer::TimGp16 {
688 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } 793 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
689 } 794 }
690 } 795 }
691 }; 796 };
797}
692 798
693 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 799#[allow(unused)]
694 impl_basic_16bit_timer!($inst, $irq); 800macro_rules! impl_gp32_timer {
801 ($inst:ident) => {
802 impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst {
803 fn regs_gp32() -> crate::pac::timer::TimGp32 {
804 crate::pac::$inst
805 }
806 }
807 };
808}
695 809
696 impl Basic16bitInstance for crate::peripherals::$inst {} 810#[allow(unused)]
697 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} 811macro_rules! impl_1ch_cmp_timer {
698 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 812 ($inst:ident) => {
699 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 813 impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {
700 impl AdvancedControlInstance for crate::peripherals::$inst {} 814 fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp {
701 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 815 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
702 fn enable_outputs(&mut self) {
703 use crate::timer::sealed::AdvancedControlInstance;
704 let r = Self::regs_advanced();
705 r.bdtr().modify(|w| w.set_moe(true));
706 } 816 }
707 } 817 }
708 impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} 818 };
709 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 819}
710 fn regs_gp16() -> crate::pac::timer::TimGp16 { 820
711 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } 821#[allow(unused)]
822macro_rules! impl_2ch_cmp_timer {
823 ($inst:ident) => {
824 impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {
825 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp {
826 unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
712 } 827 }
713 } 828 }
829 };
830}
714 831
832#[allow(unused)]
833macro_rules! impl_adv_timer {
834 ($inst:ident) => {
715 impl sealed::AdvancedControlInstance for crate::peripherals::$inst { 835 impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
716 fn regs_advanced() -> crate::pac::timer::TimAdv { 836 fn regs_advanced() -> crate::pac::timer::TimAdv {
717 crate::pac::$inst 837 unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) }
718 } 838 }
719 } 839 }
720 }; 840 };
721} 841}
722 842
843foreach_interrupt! {
844
845 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
846 impl_core_timer!($inst, $irq);
847 impl_basic_no_cr2_timer!($inst);
848 impl_basic_timer!($inst);
849 impl BasicInstance for crate::peripherals::$inst {}
850 };
851
852 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
853 impl_core_timer!($inst, $irq);
854 impl_basic_no_cr2_timer!($inst);
855 impl_basic_timer!($inst);
856 impl_1ch_timer!($inst);
857 impl_2ch_timer!($inst);
858 impl_gp16_timer!($inst);
859 impl BasicInstance for crate::peripherals::$inst {}
860 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
861 };
862
863
864 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
865 impl_core_timer!($inst, $irq);
866 impl_basic_no_cr2_timer!($inst);
867 impl_basic_timer!($inst);
868 impl_1ch_timer!($inst);
869 impl_2ch_timer!($inst);
870 impl_gp16_timer!($inst);
871 impl BasicInstance for crate::peripherals::$inst {}
872 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
873 };
874
875 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
876 impl_core_timer!($inst, $irq);
877 impl_basic_no_cr2_timer!($inst);
878 impl_basic_timer!($inst);
879 impl_1ch_timer!($inst);
880 impl_2ch_timer!($inst);
881 impl_gp16_timer!($inst);
882 impl BasicInstance for crate::peripherals::$inst {}
883 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
884 };
885
886 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
887 impl_core_timer!($inst, $irq);
888 impl_basic_no_cr2_timer!($inst);
889 impl_basic_timer!($inst);
890 impl_1ch_timer!($inst);
891 impl_2ch_timer!($inst);
892 impl_gp16_timer!($inst);
893 impl_gp32_timer!($inst);
894 impl BasicInstance for crate::peripherals::$inst {}
895 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
896 impl CaptureCompare32bitInstance for crate::peripherals::$inst {}
897 };
898
899 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
900 impl_core_timer!($inst, $irq);
901 impl_basic_no_cr2_timer!($inst);
902 impl_basic_timer!($inst);
903 impl_1ch_timer!($inst);
904 impl_2ch_timer!($inst);
905 impl_gp16_timer!($inst);
906 impl_1ch_cmp_timer!($inst);
907 impl_2ch_cmp_timer!($inst);
908 impl_adv_timer!($inst);
909 impl BasicInstance for crate::peripherals::$inst {}
910 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
911 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
912 };
913
914
915 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
916 impl_core_timer!($inst, $irq);
917 impl_basic_no_cr2_timer!($inst);
918 impl_basic_timer!($inst);
919 impl_1ch_timer!($inst);
920 impl_2ch_timer!($inst);
921 impl_gp16_timer!($inst);
922 impl_1ch_cmp_timer!($inst);
923 impl_2ch_cmp_timer!($inst);
924 impl_adv_timer!($inst);
925 impl BasicInstance for crate::peripherals::$inst {}
926 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
927 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
928 };
929
930
931 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
932 impl_core_timer!($inst, $irq);
933 impl_basic_no_cr2_timer!($inst);
934 impl_basic_timer!($inst);
935 impl_1ch_timer!($inst);
936 impl_2ch_timer!($inst);
937 impl_gp16_timer!($inst);
938 impl_1ch_cmp_timer!($inst);
939 impl_2ch_cmp_timer!($inst);
940 impl_adv_timer!($inst);
941 impl BasicInstance for crate::peripherals::$inst {}
942 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
943 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
944 };
945}
946
723// Update Event trigger DMA for every timer 947// Update Event trigger DMA for every timer
724dma_trait!(UpDma, Basic16bitInstance); 948dma_trait!(UpDma, BasicInstance);
725 949
726dma_trait!(Ch1Dma, CaptureCompare16bitInstance); 950dma_trait!(Ch1Dma, CaptureCompare16bitInstance);
727dma_trait!(Ch2Dma, CaptureCompare16bitInstance); 951dma_trait!(Ch2Dma, CaptureCompare16bitInstance);
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 0b4c1225f..1acba504e 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -84,13 +84,12 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
84 this.set_frequency(freq); 84 this.set_frequency(freq);
85 this.inner.start(); 85 this.inner.start();
86 86
87 this.inner.enable_outputs();
88
89 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 87 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
90 .iter() 88 .iter()
91 .for_each(|&channel| { 89 .for_each(|&channel| {
92 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); 90 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
93 this.inner.set_output_compare_preload(channel, true) 91
92 this.inner.set_output_compare_preload(channel, true);
94 }); 93 });
95 94
96 this 95 this
@@ -202,7 +201,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
202 &mut dma, 201 &mut dma,
203 req, 202 req,
204 duty, 203 duty,
205 T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _, 204 T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _,
206 dma_transfer_option, 205 dma_transfer_option,
207 ) 206 )
208 .await 207 .await
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index f3abfddbc..851a3d721 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -50,7 +50,7 @@ async fn main(_spawner: Spawner) {
50 let nvmc = Nvmc::new(p.NVMC); 50 let nvmc = Nvmc::new(p.NVMC);
51 let nvmc = Mutex::new(BlockingAsync::new(nvmc)); 51 let nvmc = Mutex::new(BlockingAsync::new(nvmc));
52 52
53 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc); 53 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
54 let mut magic = [0; 4]; 54 let mut magic = [0; 4];
55 let mut updater = FirmwareUpdater::new(config, &mut magic); 55 let mut updater = FirmwareUpdater::new(config, &mut magic);
56 loop { 56 loop {
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index 3f0bf90e2..ede0c07da 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -36,7 +36,7 @@ async fn main(_s: Spawner) {
36 let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH); 36 let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH);
37 let flash = Mutex::new(RefCell::new(flash)); 37 let flash = Mutex::new(RefCell::new(flash));
38 38
39 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 39 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
40 let mut aligned = AlignedBuffer([0; 1]); 40 let mut aligned = AlignedBuffer([0; 1]);
41 let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0); 41 let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0);
42 42
diff --git a/examples/boot/application/stm32f3/memory.x b/examples/boot/application/stm32f3/memory.x
index f51875766..02ebe3ecf 100644
--- a/examples/boot/application/stm32f3/memory.x
+++ b/examples/boot/application/stm32f3/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 66K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index 3f9ebe5c8..8858ae3da 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 let mut led = Output::new(p.PA5, Level::Low, Speed::Low); 28 let mut led = Output::new(p.PA5, Level::Low, Speed::Low);
29 led.set_high(); 29 led.set_high();
30 30
31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
32 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 32 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
33 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 33 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
34 button.wait_for_falling_edge().await; 34 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index c57c29263..d3df11fe4 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
30 let mut led = Output::new(p.PB7, Level::Low, Speed::Low); 30 let mut led = Output::new(p.PB7, Level::Low, Speed::Low);
31 led.set_high(); 31 led.set_high();
32 32
33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
34 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
35 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0);
36 let writer = updater.prepare_update().unwrap(); 36 let writer = updater.prepare_update().unwrap();
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index a00d17408..f61ac1f71 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
30 let mut led = Output::new(p.PB14, Level::Low, Speed::Low); 30 let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
31 led.set_high(); 31 led.set_high();
32 32
33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
34 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
35 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0);
36 let writer = updater.prepare_update().unwrap(); 36 let writer = updater.prepare_update().unwrap();
diff --git a/examples/boot/application/stm32l0/memory.x b/examples/boot/application/stm32l0/memory.x
index a99330145..8866506a8 100644
--- a/examples/boot/application/stm32l0/memory.x
+++ b/examples/boot/application/stm32l0/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 66K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
9} 9}
10 10
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index dbec49d44..f066c1139 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
30 30
31 led.set_high(); 31 led.set_high();
32 32
33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
34 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
35 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
36 button.wait_for_falling_edge().await; 36 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32l1/memory.x b/examples/boot/application/stm32l1/memory.x
index a99330145..caa525278 100644
--- a/examples/boot/application/stm32l1/memory.x
+++ b/examples/boot/application/stm32l1/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 46K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08013800, LENGTH = 54K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
9} 9}
10 10
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index dbec49d44..f066c1139 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
30 30
31 led.set_high(); 31 led.set_high();
32 32
33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
34 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
35 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 35 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
36 button.wait_for_falling_edge().await; 36 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32l4/memory.x b/examples/boot/application/stm32l4/memory.x
index f51875766..e1d4e7fa8 100644
--- a/examples/boot/application/stm32l4/memory.x
+++ b/examples/boot/application/stm32l4/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index e946c3cdf..a0079ee33 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 let mut led = Output::new(p.PB14, Level::Low, Speed::Low); 28 let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
29 led.set_high(); 29 led.set_high();
30 30
31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
32 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 32 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
33 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 33 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
34 button.wait_for_falling_edge().await; 34 button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32wb-dfu/README.md b/examples/boot/application/stm32wb-dfu/README.md
index c8dce0387..7f656cde6 100644
--- a/examples/boot/application/stm32wb-dfu/README.md
+++ b/examples/boot/application/stm32wb-dfu/README.md
@@ -1,29 +1,9 @@
1# Examples using bootloader 1# Examples using bootloader
2 2
3Example for STM32WL demonstrating the bootloader. The example consists of application binaries, 'a' 3Example for STM32WB demonstrating the USB DFU application.
4which allows you to press a button to start the DFU process, and 'b' which is the updated
5application.
6
7
8## Prerequisites
9
10* `cargo-binutils`
11* `cargo-flash`
12* `embassy-boot-stm32`
13 4
14## Usage 5## Usage
15 6
16``` 7```
17# Flash bootloader 8cargo flash --release --chip STM32WB55RGVx
18cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4 --chip STM32WLE5JCIx
19# Build 'b'
20cargo build --release --bin b
21# Generate binary for 'b'
22cargo objcopy --release --bin b -- -O binary b.bin
23```
24
25# Flash `a` (which includes b.bin)
26
27```
28cargo flash --release --bin a --chip STM32WLE5JCIx
29``` 9```
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index b2ccb9e1a..37c3d7d90 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
30 let flash = Flash::new_blocking(p.FLASH); 30 let flash = Flash::new_blocking(p.FLASH);
31 let flash = Mutex::new(RefCell::new(flash)); 31 let flash = Mutex::new(RefCell::new(flash));
32 32
33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 33 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
34 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 34 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
35 let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0); 35 let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0);
36 firmware_state.mark_booted().expect("Failed to mark booted"); 36 firmware_state.mark_booted().expect("Failed to mark booted");
diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x
index f51875766..e1d4e7fa8 100644
--- a/examples/boot/application/stm32wl/memory.x
+++ b/examples/boot/application/stm32wl/memory.x
@@ -3,8 +3,8 @@ MEMORY
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K 4 BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 32K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08010000, LENGTH = 36K 7 DFU : ORIGIN = 0x08018000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index b582d8b25..2fb16bdc4 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 let mut led = Output::new(p.PB9, Level::Low, Speed::Low); 28 let mut led = Output::new(p.PB9, Level::Low, Speed::Low);
29 led.set_high(); 29 led.set_high();
30 30
31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash); 31 let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
32 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 32 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
33 let mut updater = FirmwareUpdater::new(config, &mut magic.0); 33 let mut updater = FirmwareUpdater::new(config, &mut magic.0);
34 button.wait_for_falling_edge().await; 34 button.wait_for_falling_edge().await;
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 74e2e293f..67c700437 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -31,7 +31,7 @@ fn main() -> ! {
31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); 31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
32 let flash = Mutex::new(RefCell::new(flash)); 32 let flash = Mutex::new(RefCell::new(flash));
33 33
34 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 34 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
35 let active_offset = config.active.offset(); 35 let active_offset = config.active.offset();
36 let bl: BootLoader = BootLoader::prepare(config); 36 let bl: BootLoader = BootLoader::prepare(config);
37 37
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
index c0e75d1ea..25b1657b8 100644
--- a/examples/boot/bootloader/rp/src/main.rs
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -27,7 +27,7 @@ fn main() -> ! {
27 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8)); 27 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8));
28 let flash = Mutex::new(RefCell::new(flash)); 28 let flash = Mutex::new(RefCell::new(flash));
29 29
30 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 30 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
31 let active_offset = config.active.offset(); 31 let active_offset = config.active.offset();
32 let bl: BootLoader = BootLoader::prepare(config); 32 let bl: BootLoader = BootLoader::prepare(config);
33 33
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
new file mode 100644
index 000000000..313187adc
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
@@ -0,0 +1,57 @@
1[package]
2edition = "2021"
3name = "stm32-bootloader-dual-bank-flash-example"
4version = "0.1.0"
5description = "Example bootloader for dual-bank flash STM32 chips"
6license = "MIT OR Apache-2.0"
7
8[dependencies]
9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true }
11
12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = [
15 "inline-asm",
16 "critical-section-single-core",
17] }
18embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
19cortex-m-rt = { version = "0.7" }
20embedded-storage = "0.3.1"
21embedded-storage-async = "0.4.0"
22cfg-if = "1.0.0"
23
24[features]
25defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"]
26debug = ["defmt-rtt", "defmt"]
27
28[profile.dev]
29debug = 2
30debug-assertions = true
31incremental = false
32opt-level = 'z'
33overflow-checks = true
34
35[profile.release]
36codegen-units = 1
37debug = 2
38debug-assertions = false
39incremental = false
40lto = 'fat'
41opt-level = 'z'
42overflow-checks = false
43
44# do not optimize proc-macro crates = faster builds from scratch
45[profile.dev.build-override]
46codegen-units = 8
47debug = false
48debug-assertions = false
49opt-level = 0
50overflow-checks = false
51
52[profile.release.build-override]
53codegen-units = 8
54debug = false
55debug-assertions = false
56opt-level = 0
57overflow-checks = false
diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md
new file mode 100644
index 000000000..3de3171cd
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/README.md
@@ -0,0 +1,44 @@
1# STM32 dual-bank flash Bootloader
2
3## Overview
4
5This bootloader leverages `embassy-boot` to interact with the flash.
6This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series.
7Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device.
8
9Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions.
10
11## Memory Configuration
12
13In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment.
14For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks.
15
16### Symbol Definitions
17
18The bootloader's state and active symbols are anchored to the flash origin of **bank 1**:
19
20- `__bootloader_state_start` and `__bootloader_state_end`
21- `__bootloader_active_start` and `__bootloader_active_end`
22
23In contrast, the Device Firmware Upgrade (DFU) symbols are aligned with the DFU flash origin in **bank 2**:
24
25- `__bootloader_dfu_start` and `__bootloader_dfu_end`
26
27```rust
28__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(**FLASH**);
29__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(**FLASH**);
30
31__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(**FLASH**);
32__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(**FLASH**);
33
34__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(**DFU**);
35__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(**DFU**);
36```
37
38## Flashing the Bootloader
39
40To flash the bootloader onto your STM32H747XI device, use the following command:
41
42```bash
43cargo flash --features embassy-stm32/stm32h747xi-cm7 --release --chip STM32H747XIHx
44```
diff --git a/examples/boot/bootloader/stm32-dual-bank/build.rs b/examples/boot/bootloader/stm32-dual-bank/build.rs
new file mode 100644
index 000000000..fd605991f
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/build.rs
@@ -0,0 +1,27 @@
1use std::env;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5
6fn main() {
7 // Put `memory.x` in our output directory and ensure it's
8 // on the linker search path.
9 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10 File::create(out.join("memory.x"))
11 .unwrap()
12 .write_all(include_bytes!("memory.x"))
13 .unwrap();
14 println!("cargo:rustc-link-search={}", out.display());
15
16 // By default, Cargo will re-run a build script whenever
17 // any file in the project changes. By specifying `memory.x`
18 // here, we ensure the build script is only re-run when
19 // `memory.x` is changed.
20 println!("cargo:rerun-if-changed=memory.x");
21
22 println!("cargo:rustc-link-arg-bins=--nmagic");
23 println!("cargo:rustc-link-arg-bins=-Tlink.x");
24 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
25 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
26 }
27}
diff --git a/examples/boot/bootloader/stm32-dual-bank/memory.x b/examples/boot/bootloader/stm32-dual-bank/memory.x
new file mode 100644
index 000000000..665da7139
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/memory.x
@@ -0,0 +1,18 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 128K
5 BOOTLOADER_STATE : ORIGIN = 0x08020000, LENGTH = 128K
6 ACTIVE : ORIGIN = 0x08040000, LENGTH = 512K
7 DFU : ORIGIN = 0x08100000, LENGTH = 640K
8 RAM (rwx) : ORIGIN = 0x24000000, LENGTH = 512K
9}
10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH);
12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH);
13
14__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH);
15__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH);
16
17__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(DFU);
18__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(DFU);
diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
new file mode 100644
index 000000000..4d2e82d26
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
@@ -0,0 +1,53 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use cortex_m_rt::{entry, exception};
7#[cfg(feature = "defmt")]
8use defmt_rtt as _;
9use embassy_boot_stm32::*;
10use embassy_stm32::flash::{Flash, BANK1_REGION};
11use embassy_sync::blocking_mutex::Mutex;
12
13#[entry]
14fn main() -> ! {
15 let p = embassy_stm32::init(Default::default());
16
17 // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
18 // as it prevents a hard fault when accessing flash 'too early' after boot.
19 /*
20 for i in 0..10000000 {
21 cortex_m::asm::nop();
22 }
23 */
24
25 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
26 let flash_bank1 = Mutex::new(RefCell::new(layout.bank1_region));
27 let flash_bank2 = Mutex::new(RefCell::new(layout.bank2_region));
28
29 let config = BootLoaderConfig::from_linkerfile_blocking(&flash_bank1, &flash_bank2, &flash_bank1);
30 let active_offset = config.active.offset();
31 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
32
33 unsafe { bl.load(BANK1_REGION.base + active_offset) }
34}
35
36#[no_mangle]
37#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
38unsafe extern "C" fn HardFault() {
39 cortex_m::peripheral::SCB::sys_reset();
40}
41
42#[exception]
43unsafe fn DefaultHandler(_: i16) -> ! {
44 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
45 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
46
47 panic!("DefaultHandler #{:?}", irqn);
48}
49
50#[panic_handler]
51fn panic(_info: &core::panic::PanicInfo) -> ! {
52 cortex_m::asm::udf();
53}
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 5fd9ea588..99a7a6a6b 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -25,7 +25,7 @@ fn main() -> ! {
25 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); 25 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
26 let flash = Mutex::new(RefCell::new(layout.bank1_region)); 26 let flash = Mutex::new(RefCell::new(layout.bank1_region));
27 27
28 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 28 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
29 let active_offset = config.active.offset(); 29 let active_offset = config.active.offset();
30 let bl = BootLoader::prepare::<_, _, _, 2048>(config); 30 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
31 31
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 96635afa2..854f94d85 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] } 12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } 13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md
index a82b730b9..d5c6ea57c 100644
--- a/examples/boot/bootloader/stm32wb-dfu/README.md
+++ b/examples/boot/bootloader/stm32wb-dfu/README.md
@@ -7,5 +7,5 @@ The bootloader uses `embassy-boot` to interact with the flash.
7Flash the bootloader 7Flash the bootloader
8 8
9``` 9```
10cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx 10cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx
11``` 11```
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index a7ab813b6..d989fbfdf 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -35,7 +35,7 @@ fn main() -> ! {
35 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); 35 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
36 let flash = Mutex::new(RefCell::new(layout.bank1_region)); 36 let flash = Mutex::new(RefCell::new(layout.bank1_region));
37 37
38 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 38 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
39 let active_offset = config.active.offset(); 39 let active_offset = config.active.offset();
40 let bl = BootLoader::prepare::<_, _, _, 2048>(config); 40 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
41 if bl.state == State::DfuDetach { 41 if bl.state == State::DfuDetach {
@@ -45,7 +45,7 @@ fn main() -> ! {
45 config.product = Some("USB-DFU Bootloader example"); 45 config.product = Some("USB-DFU Bootloader example");
46 config.serial_number = Some("1235678"); 46 config.serial_number = Some("1235678");
47 47
48 let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); 48 let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
49 let mut buffer = AlignedBuffer([0; WRITE_SIZE]); 49 let mut buffer = AlignedBuffer([0; WRITE_SIZE]);
50 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); 50 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]);
51 51
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index 8e5c41a43..d88bd838f 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::Basic16bitInstance; 11use embassy_stm32::timer::low_level::BasicInstance;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -75,9 +75,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
75 dac.enable(); 75 dac.enable();
76 76
77 TIM6::enable_and_reset(); 77 TIM6::enable_and_reset();
78 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 78 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
79 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 79 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
80 TIM6::regs().cr1().modify(|w| { 80 TIM6::regs_basic().cr1().modify(|w| {
81 w.set_opm(false); 81 w.set_opm(false);
82 w.set_cen(true); 82 w.set_cen(true);
83 }); 83 });
@@ -112,9 +112,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
112 } 112 }
113 113
114 TIM7::enable_and_reset(); 114 TIM7::enable_and_reset();
115 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 115 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
116 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 116 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
117 TIM7::regs().cr1().modify(|w| { 117 TIM7::regs_basic().cr1().modify(|w| {
118 w.set_opm(false); 118 w.set_opm(false);
119 w.set_cen(true); 119 w.set_cen(true);
120 }); 120 });
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs
new file mode 100644
index 000000000..adeaa208a
--- /dev/null
+++ b/examples/stm32l0/src/bin/adc.rs
@@ -0,0 +1,40 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, SampleTime};
7use embassy_stm32::peripherals::ADC;
8use embassy_stm32::{adc, bind_interrupts};
9use embassy_time::{Delay, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 ADC1_COMP => adc::InterruptHandler<ADC>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!");
20
21 let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
22 adc.set_sample_time(SampleTime::Cycles79_5);
23 let mut pin = p.PA1;
24
25 let mut vrefint = adc.enable_vref(&mut Delay);
26 let vrefint_sample = adc.read(&mut vrefint).await;
27 let convert_to_millivolts = |sample| {
28 // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
29 // 6.3.3 Embedded internal reference voltage
30 const VREFINT_MV: u32 = 1224; // mV
31
32 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
33 };
34
35 loop {
36 let v = adc.read(&mut pin).await;
37 info!("--> {} - {} mV", v, convert_to_millivolts(v));
38 Timer::after_millis(100).await;
39 }
40}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index 8e5098557..f227812cd 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::Basic16bitInstance; 11use embassy_stm32::timer::low_level::BasicInstance;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -46,9 +46,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
46 dac.enable(); 46 dac.enable();
47 47
48 TIM6::enable_and_reset(); 48 TIM6::enable_and_reset();
49 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 49 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
50 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 50 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
51 TIM6::regs().cr1().modify(|w| { 51 TIM6::regs_basic().cr1().modify(|w| {
52 w.set_opm(false); 52 w.set_opm(false);
53 w.set_cen(true); 53 w.set_cen(true);
54 }); 54 });
@@ -83,9 +83,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
83 } 83 }
84 84
85 TIM7::enable_and_reset(); 85 TIM7::enable_and_reset();
86 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); 86 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
87 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 87 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
88 TIM7::regs().cr1().modify(|w| { 88 TIM7::regs_basic().cr1().modify(|w| {
89 w.set_opm(false); 89 w.set_opm(false);
90 w.set_cen(true); 90 w.set_cen(true);
91 }); 91 });
diff --git a/tests/stm32/teleprobe.sh b/tests/stm32/teleprobe.sh
deleted file mode 100755
index 6eec6ca93..000000000
--- a/tests/stm32/teleprobe.sh
+++ /dev/null
@@ -1,12 +0,0 @@
1echo Running target=$1 elf=$2
2STATUSCODE=$(
3 curl \
4 -sS \
5 --output /dev/stderr \
6 --write-out "%{http_code}" \
7 -H "Authorization: Bearer $TELEPROBE_TOKEN" \
8 https://teleprobe.embassy.dev/targets/$1/run --data-binary @$2
9)
10echo
11echo HTTP Status code: $STATUSCODE
12test "$STATUSCODE" -eq 200