diff options
58 files changed, 948 insertions, 351 deletions
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | Embassy 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. | 3 | Embassy 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 | ||
| 8 | The 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. | 8 | The 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. |
| @@ -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 @@ | |||
| 3 | Over 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. | 3 | Over 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 |
| 6 | It 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. | 6 | It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], |
| 7 | This, however, can easily blow up your stack if you are not careful. | 7 | to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't |
| 8 | want to spend resources on an allocator and end up placing buffers on the stack. This, however, can easily blow up | ||
| 9 | your stack if you are not careful. | ||
| 8 | 10 | ||
| 9 | Consider the following example: | 11 | Consider 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 | ||
| 30 | You are likely missing some features of the `embassy-executor` crate. | 30 | You are likely missing some features of the `embassy-executor` crate. |
| 31 | 31 | ||
| 32 | For Cortex-M targets, consider making sure that ALL of the following features are active in your `Cargo.toml` for the `embassy-executor` crate: | 32 | For 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 | ||
| 38 | For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. | 37 | For 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 | |||
| 125 | embassy crates are coming from crates.io, and some from git, each of them pulling in a different set | 124 | embassy crates are coming from crates.io, and some from git, each of them pulling in a different set |
| 126 | of dependencies. | 125 | of dependencies. |
| 127 | 126 | ||
| 128 | To resolve this issue, make sure to only use a single source for all your embassy crates! To do this, | 127 | To resolve this issue, make sure to only use a single source for all your embassy crates! |
| 129 | you should patch your dependencies to use git sources using `[patch.crates.io]` and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. | 128 | To do this, you should patch your dependencies to use git sources using `[patch.crates.io]` |
| 129 | and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. | ||
| 130 | 130 | ||
| 131 | Example: | 131 | Example: |
| 132 | 132 | ||
| 133 | [source,toml] | 133 | [source,toml] |
| 134 | ---- | 134 | ---- |
| 135 | [patch.crates-io] | 135 | [patch.crates-io] |
| 136 | embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } | 136 | embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } |
| 137 | embassy-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 | ||
| 139 | Note that the git revision should match any other embassy patches or git dependencies that you are using! | 141 | Note 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 | ||
| 3 | Once 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. | 3 | Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. |
| 4 | |||
| 5 | There 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 | |||
| 14 | But if you want to start from scratch: | ||
| 4 | 15 | ||
| 5 | As 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. | 16 | As 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 |
| 168 | 0.000000 TRACE BDCR configured: 00008200 | 179 | 0.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 |
| 170 | 0.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)) } | 181 | 0.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 |
| 172 | 0.000000 INFO Hello World! | 183 | 0.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 |
| 174 | 0.000091 INFO high | 185 | 0.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 |
| 176 | 0.300201 INFO low | 187 | 0.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 | ||
| 41 | This 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]. | 41 | This 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 | ||
| 45 | This is your manifest file, where you can configure all of the embassy components to use the features you need. | 45 | This is your manifest file, where you can configure all of the embassy components to use the features you need. |
| 46 | 46 | ||
| 47 | TODO: 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 | ||
| 52 | impl<'a, FLASH: NorFlash> | 52 | impl<'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")] |
| 19 | impl<'a, FLASH: NorFlash> | 19 | impl<'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")] |
| 19 | impl<'a, FLASH: NorFlash> | 19 | impl<'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. |
| 13 | pub struct FirmwareUpdaterConfig<DFU, STATE> { | 13 | pub 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")] |
| 582 | embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); | 582 | embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); |
| 583 | 583 | ||
| 584 | #[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))] | ||
| 585 | const 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")] |
| 585 | impl rtos_trace::RtosTraceOSCallbacks for Executor { | 594 | impl 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 | |||
| 13 | pub use pac::spim0::config::ORDER_A as BitOrder; | 13 | pub use pac::spim0::config::ORDER_A as BitOrder; |
| 14 | pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | 14 | pub use pac::spim0::frequency::FREQUENCY_A as Frequency; |
| 15 | 15 | ||
| 16 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | 16 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 17 | use crate::gpio::sealed::Pin as _; | 17 | use crate::gpio::sealed::Pin as _; |
| 18 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 18 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 19 | use crate::interrupt::typelevel::Interrupt; | 19 | use 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] |
| 27 | pub enum Error { | 27 | pub 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}; | |||
| 11 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 11 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 12 | pub use pac::spis0::config::ORDER_A as BitOrder; | 12 | pub use pac::spis0::config::ORDER_A as BitOrder; |
| 13 | 13 | ||
| 14 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | 14 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 15 | use crate::gpio::sealed::Pin as _; | 15 | use crate::gpio::sealed::Pin as _; |
| 16 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; | 16 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; |
| 17 | use crate::interrupt::typelevel::Interrupt; | 17 | use 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" | |||
| 68 | sdio-host = "0.5.0" | 68 | sdio-host = "0.5.0" |
| 69 | critical-section = "1.1" | 69 | critical-section = "1.1" |
| 70 | #stm32-metapac = { version = "15" } | 70 | #stm32-metapac = { version = "15" } |
| 71 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24" } | 71 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5bf4bec597bdf0d85402789b40c3a37b0f5a8e76" } |
| 72 | vcell = "0.1.3" | 72 | vcell = "0.1.3" |
| 73 | bxcan = "0.7.0" | 73 | bxcan = "0.7.0" |
| 74 | nb = "1.0.0" | 74 | nb = "1.0.0" |
| @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 89 | proc-macro2 = "1.0.36" | 89 | proc-macro2 = "1.0.36" |
| 90 | quote = "1.0.15" | 90 | quote = "1.0.15" |
| 91 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | 91 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} |
| 92 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24", default-features = false, features = ["metadata"]} | 92 | stm32-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 | ||
| 38 | pub(crate) mod sealed { | 39 | pub(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)))] |
| 82 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 83 | pub 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))] |
| 85 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 86 | pub 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))] |
| 6 | pub enum Resolution { | 6 | pub enum Resolution { |
| @@ -25,7 +25,7 @@ pub enum Resolution { | |||
| 25 | 25 | ||
| 26 | impl Default for Resolution { | 26 | impl 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))] |
| 87 | impl_sample_time!( | 87 | impl_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 | ||
| 5 | use embassy_hal_internal::into_ref; | 5 | use embassy_hal_internal::into_ref; |
| 6 | use embedded_hal_02::blocking::delay::DelayUs; | 6 | use embedded_hal_02::blocking::delay::DelayUs; |
| 7 | #[cfg(adc_l0)] | ||
| 8 | use stm32_metapac::adc::vals::Ckmode; | ||
| 7 | 9 | ||
| 8 | use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; | 10 | use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; |
| 9 | use crate::interrupt::typelevel::Interrupt; | 11 | use 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))] | ||
| 33 | pub struct Vbat; | 36 | pub struct Vbat; |
| 37 | |||
| 38 | #[cfg(not(adc_l0))] | ||
| 34 | impl AdcPin<ADC> for Vbat {} | 39 | impl AdcPin<ADC> for Vbat {} |
| 40 | |||
| 41 | #[cfg(not(adc_l0))] | ||
| 35 | impl super::sealed::AdcPin<ADC> for Vbat { | 42 | impl 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))] | ||
| 40 | pub struct OverrunError; | 41 | pub struct OverrunError; |
| 41 | 42 | ||
| 42 | pub trait DmaCtrl { | 43 | pub 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; | |||
| 14 | use crate::rcc::sealed::RccPeripheral; | 14 | use crate::rcc::sealed::RccPeripheral; |
| 15 | #[cfg(feature = "low-power")] | 15 | #[cfg(feature = "low-power")] |
| 16 | use crate::rtc::Rtc; | 16 | use crate::rtc::Rtc; |
| 17 | use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; | 17 | use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; |
| 18 | use crate::{interrupt, peripherals}; | 18 | use 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 | ||
| 24 | macro_rules! complementary_channel_impl { | 24 | macro_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))] | ||
| 3 | pub mod complementary_pwm; | 35 | pub mod complementary_pwm; |
| 4 | pub mod qei; | 36 | pub mod qei; |
| 5 | pub mod simple_pwm; | 37 | pub mod simple_pwm; |
| @@ -19,32 +51,32 @@ pub mod low_level { | |||
| 19 | pub(crate) mod sealed { | 51 | pub(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. |
| 575 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | 674 | pub 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. |
| 578 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + Basic16bitInstance + 'static {} | 677 | /// Capture Compare timer instance. |
| 579 | |||
| 580 | /// Gneral-purpose 32-bit timer instance. | ||
| 581 | pub trait GeneralPurpose32bitInstance: | ||
| 582 | sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static | ||
| 583 | { | ||
| 584 | } | ||
| 585 | |||
| 586 | /// Advanced control timer instance. | ||
| 587 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose16bitInstance + 'static {} | ||
| 588 | |||
| 589 | /// Capture/Compare 16-bit timer instance. | ||
| 590 | pub trait CaptureCompare16bitInstance: | 678 | pub 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))] |
| 596 | pub 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. |
| 690 | pub trait CaptureCompare32bitInstance: | ||
| 691 | CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static | ||
| 598 | { | 692 | { |
| 599 | } | 693 | } |
| 600 | 694 | ||
| 601 | /// Capture/Compare 32-bit timer instance. | 695 | #[cfg(not(stm32l0))] |
| 602 | pub 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. |
| 698 | pub trait ComplementaryCaptureCompare16bitInstance: | ||
| 699 | CaptureCompare16bitInstance | ||
| 700 | + sealed::GeneralPurpose1ChannelComplementaryInstance | ||
| 701 | + sealed::GeneralPurpose2ChannelComplementaryInstance | ||
| 702 | + sealed::AdvancedControlInstance | ||
| 703 | + 'static | ||
| 604 | { | 704 | { |
| 605 | } | 705 | } |
| 606 | 706 | ||
| 607 | pin_trait!(Channel1Pin, CaptureCompare16bitInstance); | 707 | pin_trait!(Channel1Pin, CaptureCompare16bitInstance); |
| 608 | pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance); | ||
| 609 | pin_trait!(Channel2Pin, CaptureCompare16bitInstance); | 708 | pin_trait!(Channel2Pin, CaptureCompare16bitInstance); |
| 610 | pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance); | ||
| 611 | pin_trait!(Channel3Pin, CaptureCompare16bitInstance); | 709 | pin_trait!(Channel3Pin, CaptureCompare16bitInstance); |
| 612 | pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance); | ||
| 613 | pin_trait!(Channel4Pin, CaptureCompare16bitInstance); | 710 | pin_trait!(Channel4Pin, CaptureCompare16bitInstance); |
| 614 | pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance); | ||
| 615 | pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); | 711 | pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); |
| 616 | pin_trait!(BreakInputPin, CaptureCompare16bitInstance); | 712 | |
| 617 | pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance); | 713 | cfg_if::cfg_if! { |
| 618 | pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); | 714 | if #[cfg(not(stm32l0))] { |
| 619 | pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); | 715 | pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); |
| 620 | pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); | 716 | pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); |
| 621 | pin_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)] |
| 624 | macro_rules! impl_basic_16bit_timer { | 732 | macro_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)] |
| 637 | macro_rules! impl_32bit_timer { | 745 | macro_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)] |
| 648 | macro_rules! impl_compare_capable_16bit { | 756 | macro_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 | ||
| 656 | foreach_interrupt! { | 766 | #[allow(unused)] |
| 657 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { | 767 | macro_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 { | 778 | macro_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); | 789 | macro_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); | 800 | macro_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 {} | 811 | macro_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)] |
| 822 | macro_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)] | ||
| 833 | macro_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 | ||
| 843 | foreach_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 |
| 724 | dma_trait!(UpDma, Basic16bitInstance); | 948 | dma_trait!(UpDma, BasicInstance); |
| 725 | 949 | ||
| 726 | dma_trait!(Ch1Dma, CaptureCompare16bitInstance); | 950 | dma_trait!(Ch1Dma, CaptureCompare16bitInstance); |
| 727 | dma_trait!(Ch2Dma, CaptureCompare16bitInstance); | 951 | dma_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 | ||
| 3 | Example for STM32WL demonstrating the bootloader. The example consists of application binaries, 'a' | 3 | Example for STM32WB demonstrating the USB DFU application. |
| 4 | which allows you to press a button to start the DFU process, and 'b' which is the updated | ||
| 5 | application. | ||
| 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 | 8 | cargo flash --release --chip STM32WB55RGVx |
| 18 | cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4 --chip STM32WLE5JCIx | ||
| 19 | # Build 'b' | ||
| 20 | cargo build --release --bin b | ||
| 21 | # Generate binary for 'b' | ||
| 22 | cargo objcopy --release --bin b -- -O binary b.bin | ||
| 23 | ``` | ||
| 24 | |||
| 25 | # Flash `a` (which includes b.bin) | ||
| 26 | |||
| 27 | ``` | ||
| 28 | cargo 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] | ||
| 2 | edition = "2021" | ||
| 3 | name = "stm32-bootloader-dual-bank-flash-example" | ||
| 4 | version = "0.1.0" | ||
| 5 | description = "Example bootloader for dual-bank flash STM32 chips" | ||
| 6 | license = "MIT OR Apache-2.0" | ||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | defmt = { version = "0.3", optional = true } | ||
| 10 | defmt-rtt = { version = "0.4", optional = true } | ||
| 11 | |||
| 12 | embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } | ||
| 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } | ||
| 14 | cortex-m = { version = "0.7.6", features = [ | ||
| 15 | "inline-asm", | ||
| 16 | "critical-section-single-core", | ||
| 17 | ] } | ||
| 18 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | ||
| 19 | cortex-m-rt = { version = "0.7" } | ||
| 20 | embedded-storage = "0.3.1" | ||
| 21 | embedded-storage-async = "0.4.0" | ||
| 22 | cfg-if = "1.0.0" | ||
| 23 | |||
| 24 | [features] | ||
| 25 | defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] | ||
| 26 | debug = ["defmt-rtt", "defmt"] | ||
| 27 | |||
| 28 | [profile.dev] | ||
| 29 | debug = 2 | ||
| 30 | debug-assertions = true | ||
| 31 | incremental = false | ||
| 32 | opt-level = 'z' | ||
| 33 | overflow-checks = true | ||
| 34 | |||
| 35 | [profile.release] | ||
| 36 | codegen-units = 1 | ||
| 37 | debug = 2 | ||
| 38 | debug-assertions = false | ||
| 39 | incremental = false | ||
| 40 | lto = 'fat' | ||
| 41 | opt-level = 'z' | ||
| 42 | overflow-checks = false | ||
| 43 | |||
| 44 | # do not optimize proc-macro crates = faster builds from scratch | ||
| 45 | [profile.dev.build-override] | ||
| 46 | codegen-units = 8 | ||
| 47 | debug = false | ||
| 48 | debug-assertions = false | ||
| 49 | opt-level = 0 | ||
| 50 | overflow-checks = false | ||
| 51 | |||
| 52 | [profile.release.build-override] | ||
| 53 | codegen-units = 8 | ||
| 54 | debug = false | ||
| 55 | debug-assertions = false | ||
| 56 | opt-level = 0 | ||
| 57 | overflow-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 | |||
| 5 | This bootloader leverages `embassy-boot` to interact with the flash. | ||
| 6 | This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. | ||
| 7 | Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device. | ||
| 8 | |||
| 9 | Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions. | ||
| 10 | |||
| 11 | ## Memory Configuration | ||
| 12 | |||
| 13 | In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. | ||
| 14 | For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. | ||
| 15 | |||
| 16 | ### Symbol Definitions | ||
| 17 | |||
| 18 | The 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 | |||
| 23 | In 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 | |||
| 40 | To flash the bootloader onto your STM32H747XI device, use the following command: | ||
| 41 | |||
| 42 | ```bash | ||
| 43 | cargo 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 @@ | |||
| 1 | use std::env; | ||
| 2 | use std::fs::File; | ||
| 3 | use std::io::Write; | ||
| 4 | use std::path::PathBuf; | ||
| 5 | |||
| 6 | fn 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 @@ | |||
| 1 | MEMORY | ||
| 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 | |||
| 4 | use core::cell::RefCell; | ||
| 5 | |||
| 6 | use cortex_m_rt::{entry, exception}; | ||
| 7 | #[cfg(feature = "defmt")] | ||
| 8 | use defmt_rtt as _; | ||
| 9 | use embassy_boot_stm32::*; | ||
| 10 | use embassy_stm32::flash::{Flash, BANK1_REGION}; | ||
| 11 | use embassy_sync::blocking_mutex::Mutex; | ||
| 12 | |||
| 13 | #[entry] | ||
| 14 | fn 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")] | ||
| 38 | unsafe extern "C" fn HardFault() { | ||
| 39 | cortex_m::peripheral::SCB::sys_reset(); | ||
| 40 | } | ||
| 41 | |||
| 42 | #[exception] | ||
| 43 | unsafe 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] | ||
| 51 | fn 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" | |||
| 9 | defmt = { version = "0.3", optional = true } | 9 | defmt = { version = "0.3", optional = true } |
| 10 | defmt-rtt = { version = "0.4", optional = true } | 10 | defmt-rtt = { version = "0.4", optional = true } |
| 11 | 11 | ||
| 12 | embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] } | 12 | embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } |
| 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } | 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } |
| 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 15 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 15 | embassy-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. | |||
| 7 | Flash the bootloader | 7 | Flash the bootloader |
| 8 | 8 | ||
| 9 | ``` | 9 | ``` |
| 10 | cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx | 10 | cargo 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; | |||
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::low_level::RccPeripheral; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::Basic16bitInstance; | 11 | use embassy_stm32::timer::low_level::BasicInstance; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {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 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 7 | use embassy_stm32::peripherals::ADC; | ||
| 8 | use embassy_stm32::{adc, bind_interrupts}; | ||
| 9 | use embassy_time::{Delay, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | ADC1_COMP => adc::InterruptHandler<ADC>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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; | |||
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::low_level::RccPeripheral; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::Basic16bitInstance; | 11 | use embassy_stm32::timer::low_level::BasicInstance; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {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 @@ | |||
| 1 | echo Running target=$1 elf=$2 | ||
| 2 | STATUSCODE=$( | ||
| 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 | ) | ||
| 10 | echo | ||
| 11 | echo HTTP Status code: $STATUSCODE | ||
| 12 | test "$STATUSCODE" -eq 200 | ||
