Compare commits

...

38 Commits

Author SHA1 Message Date
4051aead0f stm32: update stm32-metapac. Fixes USB on STM32WB. 2023-12-08 23:45:12 +01:00
6629c7525b Merge pull request #2267 from embassy-rs/e-h-internal-docs
docs: document all public apis of embedded-hal-internal
2023-12-08 21:45:12 +00:00
02b7a833d9 docs: document all public apis of embedded-hal-internal
* Make some fields and functions non-public where possible.
* Enable doc warnings for missing public API docs.
2023-12-08 22:37:39 +01:00
a4d53c7cb1 Merge pull request #2268 from embassy-rs/doc-bind-interrupts
Document how to bind multiple interrupts and handlers in `bind_interrupts!`.
2023-12-08 21:55:40 +01:00
6c746dcf39 Document how to bind multiple interrupts and handlers in bind_interrupts!. 2023-12-08 21:26:28 +01:00
3ef18ec133 Merge pull request #2263 from embassy-rs/jamesmunns-patch-2
Tweak FAQ size profile suggestions
2023-12-08 20:50:00 +01:00
4e7b855b2d Merge pull request #2265 from JuliDi/docs-best-practices
[Docs] Add best practices page
2023-12-08 20:49:45 +01:00
3f30e87cb5 Merge pull request #2251 from JuliDi/faq-performance-tweaks
[FAQ] Add section about speed optimization
2023-12-08 19:35:32 +00:00
a9ec623622 Merge pull request #2246 from CaptainMaso/adc_f3_v1_1
stm32: add ADC f3_v1_1
2023-12-08 19:30:50 +00:00
fe218ed978 tests/stm32: add L1 DAC/ADC test. 2023-12-08 20:24:15 +01:00
c27459c052 Update stm32-metapac. 2023-12-08 20:07:59 +01:00
881cb16d28 stm32/adc: move convert resolution from PAC to version-specific mod. 2023-12-08 20:07:06 +01:00
c05149e5e4 add best practices first draft 2023-12-08 13:00:21 +01:00
c94a9b8d75 Merge pull request #2260 from barnabywalters/main
Added Embassy in the wild docs page with links to some projects
2023-12-08 09:55:31 +00:00
d87864c6a5 Merge pull request #2261 from barnabywalters/installation
Added a step-by-step guide to starting a new embassy project
2023-12-08 07:09:37 +00:00
8fa5a6b282 Tweak FAQ size profile suggestions
If we want the smallest binary, we probably want codegen-units = 1, and disable incremental builds.
2023-12-07 14:27:09 +01:00
83138ce68e Merge pull request #2262 from embassy-rs/executor-macros
executor: rename macro crate to embassy-executor-macros, bump it.
2023-12-06 23:55:58 +00:00
16e31747cc Changed example project name 2023-12-07 00:54:39 +01:00
ac2aec4e7a executor: rename macro crate to embassy-executor-macros, bump it. 2023-12-07 00:48:30 +01:00
ad2d9040d9 Merge pull request #2254 from jessebraham/executor-040
embassy-executor 0.4
2023-12-06 23:31:06 +00:00
536e91d263 Added a step-by-step guide to starting a new embassy project
Based off an example, noting what to copy, what to change and why

Briefly summarizing how to require embassy crates via github

All steps tested and proven working at the time of writing
2023-12-06 23:51:13 +01:00
ecaa62aa42 Fixed merge conflict 2023-12-06 21:55:07 +01:00
7561696a57 Added lora-rs links 2023-12-06 21:47:52 +01:00
195b492158 Update docs/modules/ROOT/pages/embassy_in_the_wild.adoc
Co-authored-by: Dániel Buga <bugadani@gmail.com>
2023-12-06 21:13:56 +01:00
10c9e2e723 Added description for Card/IO 2023-12-06 21:11:34 +01:00
cd62d2cd84 Added embassy in the wild docs page with two projects 2023-12-06 21:10:16 +01:00
925f5cbc26 Update all references to embasy-executor to the latest version 2023-12-06 12:05:47 +01:00
c5e8a2e834 embassy-executor 0.4 2023-12-06 11:59:22 +01:00
7703f47c1e Merge pull request #2255 from badrbouslikhin/main
stm32/h7: fix h7 examples
2023-12-05 21:35:28 +00:00
0ffb35a2a1 stm32/eth: add host server command example 2023-12-05 19:50:11 +01:00
d2a7322978 stm32/eth: fix h7 examples
The STM32H7 examples enable `dhcpv4` and `dns` features. Both use one
socket, meaning that we need one extra socket for our firmware tcp
socket.
2023-12-05 19:48:03 +01:00
1f6ffdcdd2 fix Cargo.toml and config.toml keys 2023-12-05 10:10:47 +01:00
83bed7bca4 Merge pull request #2252 from barnabywalters/wiki2docs
Moved content from the wiki to the docs
2023-12-05 05:21:56 +00:00
a76dd2d70f Moved content from the wiki to the docs
New: delaying_a_task.adoc, copied as-is from the wiki and placed in the
navigation until we have a better place for it (or remove/replace it)

index: Tweaked the structure, added some content from the wiki, and made
some general copy edits to improve clarity.

getting_started.adoc: Corrected various out-of-date information, added
troubleshooting tips from the wiki, added some new information, various
other small edits.

basic_application.adoc: Corrected out-of-date information, various clarifications
and edits.

After these changes, IMO most of the content on the github wiki is no longer
necessary and can be removed for clarity. The few sections I didn‘t integrate
or copy over were either out of date or unfinished.
2023-12-05 01:01:50 +01:00
bf7115cb44 remove unnecessary backtick 2023-12-04 21:20:18 +01:00
0b0ca62a95 add speed optimization 2023-12-04 20:59:08 +01:00
85d5f42562 Merge pull request #2250 from embassy-rs/jamesmunns-patch-1
Add implementation note for embassy-stm32's time-driver
2023-12-04 16:05:30 +01:00
35f16c6003 stm32: add ADC f3_v1_1 2023-12-04 14:03:31 +11:00
94 changed files with 1141 additions and 141 deletions

View File

@ -6,7 +6,7 @@ version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-executor = { version = "0.4.0", path = "../../../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.2.0", path = "../../../../../embassy-time", features = ["defmt"] }
embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
cortex-m = "0.7"
cortex-m-rt = "0.7"
embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
embassy-executor = { version = "0.3.0", features = ["nightly", "arch-cortex-m", "executor-thread"] }
embassy-executor = { version = "0.4.0", features = ["nightly", "arch-cortex-m", "executor-thread"] }
defmt = "0.3.0"
defmt-rtt = "0.3.0"

View File

@ -1,14 +1,18 @@
* xref:getting_started.adoc[Getting started]
** xref:basic_application.adoc[Basic application]
** xref:project_structure.adoc[Project Structure]
** xref:new_project.adoc[Starting a new Embassy project]
** xref:best_practices.adoc[Best Practices]
* xref:layer_by_layer.adoc[Bare metal to async]
* xref:runtime.adoc[Executor]
* xref:delaying_a_task.adoc[Delaying a Task]
* xref:hal.adoc[HAL]
** xref:nrf.adoc[nRF]
** xref:stm32.adoc[STM32]
* xref:bootloader.adoc[Bootloader]
* xref:examples.adoc[Examples]
* xref:developer.adoc[Developer]
** xref:developer_stm32.adoc[Developer: STM32]
* xref:developer.adoc[Developer Docs]
** xref:developer_stm32.adoc[Developer Docs: STM32]
* xref:embassy_in_the_wild.adoc[Embassy in the wild]
* xref:faq.adoc[Frequently Asked Questions]

View File

@ -6,9 +6,11 @@ So you've got one of the xref:examples.adoc[examples] running, but what now? Let
The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/modules/ROOT/examples/basic[here].
NOTE: If youre using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project were working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
=== Bare metal
The first thing you'll notice is a few declarations, two of which indicate that Embassy is suitable for bare metal development:
The first thing youll notice are two attributes at the top of the file. These tells the compiler that program has no access to std, and that there is no main function (because it is not run by an OS).
[source,rust]
----
@ -48,9 +50,9 @@ NOTE: Notice that there is no busy waiting going on in this task. It is using th
=== Main
The main entry point of an Embassy application is defined using the `#[embassy_executor::main]` macro. The entry point is also required to take a `Spawner` and a `Peripherals` argument.
The main entry point of an Embassy application is defined using the `#[embassy_executor::main]` macro. The entry point is passed a `Spawner`, which it can use to spawn other tasks.
The `Spawner` is the way the main application spawns other tasks. The `Peripherals` type comes from the HAL and holds all peripherals that the application may use. In this case, we want to configure one of the pins as a GPIO output driving the LED:
We then initialize the HAL with a default config, which gives us a `Peripherals` struct we can use to access the MCUs various peripherals. In this case, we want to configure one of the pins as a GPIO output driving the LED:
[source,rust]
----
@ -60,7 +62,6 @@ include::example$basic/src/main.rs[lines="22..-1"]
What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
. Creates an Embassy Executor
. Initializes the microcontroller HAL to get the `Peripherals`
. Defines a main task for the entry point
. Runs the executor spawning the main task

View File

@ -0,0 +1,53 @@
= Best Practices
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.
== Passing Buffers by Reference
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.
This, however, can easily blow up your stack if you are not careful.
Consider the following example:
[,rust]
----
fn process_buffer(mut buf: [u8; 1024]) -> [u8; 1024] {
// do stuff and return new buffer
for elem in buf.iter_mut() {
*elem = 0;
}
buf
}
pub fn main() -> () {
let buf = [1u8; 1024];
let buf_new = process_buffer(buf);
// do stuff with buf_new
()
}
----
When calling `process_buffer` in your program, a copy of the buffer you pass to the function will be created,
consuming another 1024 bytes.
After the processing, another 1024 byte buffer will be placed on the stack to be returned to the caller.
(You can check the assembly, there will be two memcopy operations, e.g., `bl __aeabi_memcpy` when compiling for a Cortex-M processor.)
*Possible Solution:*
Pass the data by reference and not by value on both, the way in and the way out.
For example, you could return a slice of the input buffer as the output.
Requiring the lifetime of the input slice and the output slice to be the same, the memory safetly of this procedure will be enforced by the compiler.
[,rust]
----
fn process_buffer<'a>(buf: &'a mut [u8]) -> &'a mut[u8] {
for elem in buf.iter_mut() {
*elem = 0;
}
buf
}
pub fn main() -> () {
let mut buf = [1u8; 1024];
let buf_new = process_buffer(&mut buf);
// do stuff with buf_new
()
}
----

View File

@ -0,0 +1,28 @@
= Delaying a Task
In an embedded program, delaying a task is one of the most common actions taken. In an event loop, delays will need to be inserted to ensure
that other tasks have a chance to run before the next iteration of the loop is called, if no other I/O is performed. Embassy provides an abstraction
to delay the current task for a specified interval of time.
Timing is serviced by the `embassy::time::Timer` struct, which provides two timing methods.
`Timer::at` creates a future that completes at the specified `Instant`, relative to the system boot time.
`Timer::after` creates a future that completes after the specified `Duration`, relative to when the future was created.
An example of a delay is provided as follows:
[,rust]
----
use embassy::executor::{task, Executor};
use embassy::time::{Duration, Timer};
#[task]
/// Task that ticks periodically
async fn tick_periodic() -> ! {
loop {
rprintln!("tick!");
// async sleep primitive, suspends the task for 500ms.
Timer::after(Duration::from_millis(500)).await;
}
}
----

View File

@ -0,0 +1,9 @@
= Embassy in the wild!
Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/modules/ROOT/pages/embassy_in_the_wild.adoc[add more]!
* link:https://github.com/cbruiz/printhor/[Printhor: The highly reliable but not necessarily functional 3D printer firmware]
** Targets some STM32 MCUs
* link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device
** Targets the ESP32-S3 or ESP32-C6 MCU
* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL

View File

@ -47,7 +47,8 @@ The first step to managing your binary size is to set up your link:https://doc.r
debug = false
lto = true
opt-level = "s"
incremental = true
incremental = false
codegen-units = 1
----
All of these flags are elaborated on in the Rust Book page linked above.
@ -135,3 +136,20 @@ embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd
----
Note that the git revision should match any other embassy patches or git dependencies that you are using!
== How can I optimize the speed of my embassy-stm32 program?
* Make sure RCC is set up to go as fast as possible
* Make sure link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html[flash cache] is enabled
* build with `--release`
* Set the following keys for the release profile in your `Cargo.toml`:
** `opt-level = "s"`
** `lto = "fat"`
* Set the following keys in the `[unstable]` section of your `.cargo/config.toml`
** `build-std = ["core"]`
** `build-std-features = ["panic_immediate_abort"]`
* Enable feature `embassy-time/generic-queue`, disable feature `embassy-executor/integrated-timers`
* When using `InterruptExecutor`:
** disable `executor-thread`
** make `main`` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }`
** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor.

View File

@ -9,7 +9,9 @@ If you don't have any supported board, don't worry: you can also run embassy on
== Getting a board with examples
Embassy supports many microcontroller families, but the easiest ways to get started is if you have one of the more common development kits.
Embassy supports many microcontroller families, but the quickest way to get started is by using a board which Embassy has existing example code for.
This list is non-exhaustive. If your board isnt included here, check the link:https://github.com/embassy-rs/embassy/tree/main/examples[examples folder] to see if example code has been written for it.
=== nRF kits
@ -36,7 +38,7 @@ Embassy supports many microcontroller families, but the easiest ways to get star
== Running an example
First you need to clone the [github repository];
First you need to clone the link:https://github.com/embassy-rs/embassy[github repository];
[source, bash]
----
@ -44,17 +46,80 @@ git clone https://github.com/embassy-rs/embassy.git
cd embassy
----
You can run an example by opening a terminal and entering the following commands:
Once you have a copy of the repository, find examples folder for your board and, and build an example program. `blinky` is a good choice as all it does is blink an LED the embedded worlds equivalent of “Hello World”.
[source, bash]
----
cd examples/nrf52840
cargo build --bin blinky --release
----
Once youve confirmed you can build the example, connect your computer to your board with a debug probe and run it on hardware:
[source, bash]
----
cargo run --bin blinky --release
----
If everything worked correctly, you should see a blinking LED on your board, and debug output similar to this on your computer:
[source]
----
Finished dev [unoptimized + debuginfo] target(s) in 1m 56s
Running `probe-run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky`
(HOST) INFO flashing program (71.36 KiB)
(HOST) INFO success!
────────────────────────────────────────────────────────────────────────────────
0 INFO Hello World!
└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:18
1 INFO high
└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:23
2 INFO low
└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27
3 INFO high
└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:23
4 INFO low
└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27
----
NOTE: How does the `cargo run` command know how to connect to our board and program it? In each `examples` folder, theres a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip its programming, so youll have to edit this file if you want to run examples on other chips.
=== It didnt work!
If you hare having issues when running `cargo run --release`, please check the following:
* You are specifying the correct `--chip on the command line``, OR
* You have set `.cargo/config.toml`'s run line to the correct chip, AND
* You have changed `examples/Cargo.toml`'s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature)
At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin.
If you are trying to run an example with `cargo run --release` and you see the following output:
[source]
----
0.000000 INFO Hello World!
└─ <invalid location: defmt frame-index: 14>
0.000000 DEBUG rcc: Clocks { sys: Hertz(80000000), apb1: Hertz(80000000), apb1_tim: Hertz(80000000), apb2: Hertz(80000000), apb2_tim: Hertz(80000000), ahb1: Hertz(80000000), ahb2: Hertz(80000000), ahb3: Hertz(80000000) }
└─ <invalid location: defmt frame-index: 124>
0.000061 TRACE allocating type=Interrupt mps=8 interval_ms=255, dir=In
└─ <invalid location: defmt frame-index: 68>
0.000091 TRACE index=1
└─ <invalid location: defmt frame-index: 72>
----
To get rid of the frame-index error add the following to your `Cargo.toml`:
[source,toml]
----
[profile.release]
debug = 2
----
If youre still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room].
== What's next?
Congratulations, you have your first Embassy application running! Here are some alternatives on where to go from here:
Congratulations, you have your first Embassy application running! Here are some suggestions for where to go from here:
* Read more about the xref:runtime.adoc[executor].
* Read more about the xref:hal.adoc[HAL].

View File

@ -4,34 +4,56 @@ Embassy is a project to make async/await a first-class option for embedded devel
== What is async?
When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task, known as a thread, can be executed if available, or the CPU can be put to sleep until another such task is ready to perform more work. Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. But if tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. In Rust, these lightweight tasks, known as 'coroutines' or 'goroutines' in other languages, are implemented with async.
When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task (known as a thread”) can be executed if available, or the CPU can be put to sleep until another task is ready.
Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. If tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread.
In other programming languages, these lightweight tasks are known as “coroutines” or ”goroutines”. In Rust, they are implemented with async. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute.
Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
== What is Embassy?
The Embassy project consists of several crates that you can use together or independently:
* **Executor** - The link:https://docs.embassy.dev/embassy-executor/[embassy-executor] is an async/await executor that generally executes a fixed number of tasks, allocated at startup, though more can be added later. The HAL is an API that you can use to access peripherals, such as USART, UART, I2C, SPI, CAN, and USB. Embassy provides implementations of both async and blocking APIs where it makes sense. DMA (Direct Memory Access) is an example where async is a good fit, whereas GPIO states are a better fit for a blocking API. The executor may also provide a system timer that you can use for both async and blocking delays. For less than one microsecond, blocking delays should be used because the cost of context-switching is too high and the executor will be unable to provide accurate timing.
=== Executor
The link:https://docs.embassy.dev/embassy-executor/[embassy-executor] is an async/await executor that generally executes a fixed number of tasks, allocated at startup, though more can be added later. The executor may also provide a system timer that you can use for both async and blocking delays. For less than one microsecond, blocking delays should be used because the cost of context-switching is too high and the executor will be unable to provide accurate timing.
=== Hardware Abstraction Layers
HALs implement safe Rust API which let you use peripherals such as USART, UART, I2C, SPI, CAN, and USB without having to directly manipulate registers.
Embassy provides implementations of both async and blocking APIs where it makes sense. DMA (Direct Memory Access) is an example where async is a good fit, whereas GPIO states are a better fit for a blocking API.
The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
** link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
** link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
+
NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async,
as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. Several drivers for WiFi and Ethernet chips can be found.
=== Networking
The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. Several drivers for WiFi and Ethernet chips can be found.
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
=== Bluetooth
The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
* **LoRa** - link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation.
=== LoRa
link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation.
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
=== USB
link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
=== Bootloader and DFU
link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
== What is DMA?
For most I/O in embedded devices, the peripheral doesn't directly support the transmission of multiple bits at once, with CAN being a notable exception. Instead, the MCU must write each byte, one at a time, and then wait until the peripheral is ready to send the next. For high I/O rates, this can pose a problem if the MCU must devote an increasing portion of its time handling each byte. The solution to this problem is to use the Direct Memory Access controller.
The Direct Memory Access controller (DMA) is a controller that is present in MCUs that Embassy supports, including stm32 and nrf. The DMA allows the MCU to set up a transfer, either send or receive, and then wait for the transfer to complete. With DMA, once started, no MCU intervention is required until the transfer is complete, meaning that the MCU can perform other computation, or set up other I/O while the transfer is in progress. For high I/O rates, DMA can cut the time that the MCU spends handling I/O by over half. However, because DMA is more complex to set-up, it is less widely used in the embedded community. Embassy aims to change that by making DMA the first choice rather than the last. Using Embassy, there's no additional tuning required once I/O rates increase because your application is already set-up to handle them.
== Resources

View File

@ -0,0 +1,178 @@
= Starting a new Embassy project
Once youve 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 youre targeting.
As an example, lets create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes.
Run:
[source,bash]
----
cargo new stm32g474-example
cd stm32g474-example
----
to create an empty rust project:
[source]
----
stm32g474-example
├── Cargo.toml
└── src
└── main.rs
----
Looking in link:https://github.com/embassy-rs/embassy/tree/main/examples[the Embassy examples], we can see theres a `stm32g4` folder. Find `src/blinky.rs` and copy its contents into our `src/main.rs`.
== .cargo/config.toml
Currently, wed need to provide cargo with a target triple every time we run `cargo build` or `cargo run`. Lets spare ourselves that work by copying `.cargo/config.toml` from `examples/stm32g4` into our project.
[source]
----
stm32g474-example
├── .cargo
│   └── config.toml
├── Cargo.toml
└── src
└── main.rs
----
In addition to a target triple, `.cargo/config.toml` contains a `runner` key which allows us to conveniently run our project on hardware with `cargo run` via probe-rs. In order for this to work, we need to provide the correct chip ID. We can do this by checking `probe-rs chip list`:
[source,bash]
----
$ probe-rs chip list | grep -i stm32g474re
STM32G474RETx
----
and copying `STM32G474RETx` into `.cargo/config.toml` as so:
[source,toml]
----
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32G474RETx"
----
== Cargo.toml
Now that cargo knows what target to compile for (and probe-rs knows what chip to run it on), were ready to add some dependencies.
Looking in `examples/stm32g4/Cargo.toml`, we can see that the examples require a number of embassy crates. For blinky, well only need three of them: `embassy-stm32`, `embassy-executor` and `embassy-time`.
At the time of writing, the latest version of embassy isnt available on crates.io, so we need to install it straight from the git repository. The recommended way of doing so is as follows:
* Copy the required `embassy-*` lines from the example `Cargo.toml`
* Make any necessary changes to `features`, e.g. requiring the `stm32g474re` feature of `embassy-stm32`
* Remove the `path = ""` keys in the `embassy-*` entries
* Create a `[patch.crates-io]` section, with entries for each embassy crate we need. These should all contain identical values: a link to the git repository, and a reference to the commit were checking out. Assuming you want the latest commit, you can find it by running `git ls-remote https://github.com/embassy-rs/embassy.git HEAD`
NOTE: When using this method, its necessary that the `version` keys in `[dependencies]` match up with the versions defined in each crates `Cargo.toml` in the specificed `rev` under `[patch.crates.io]`. This means that when updating, you have to a pick a new revision, change everything in `[patch.crates.io]` to match it, and then correct any versions under `[dependencies]` which have changed. Hopefully this will no longer be necessary once embassy is released on crates.io!
At the time of writing, this method produces the following results:
[source,toml]
----
[dependencies]
embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]}
embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
[patch.crates-io]
embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "7703f47c1ecac029f603033b7977d9a2becef48c" }
embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "7703f47c1ecac029f603033b7977d9a2becef48c" }
embassy-stm32 = { git = "https://github.com/embassy-rs/embassy", rev = "7703f47c1ecac029f603033b7977d9a2becef48c" }
----
There are a few other dependencies we need to build the project, but fortunately theyre much simpler to install. Copy their lines from the example `Cargo.toml` to the the `[dependencies]` section in the new `Cargo.toml`:
[source,toml]
----
defmt = "0.3.5"
defmt-rtt = "0.4.0"
cortex-m = {version = "0.7.7", features = ["critical-section-single-core"]}
cortex-m-rt = "0.7.3"
panic-probe = "0.3.1"
----
These are the bare minimum dependencies required to run `blinky.rs`, but its worth taking a look at the other dependencies specified in the example `Cargo.toml`, and noting what features are required for use with embassy for example `futures = { version = "0.3.17", default-features = false, features = ["async-await"] }`.
Finally, copy the `[profile.release]` section from the example `Cargo.toml` into ours.
[source,toml]
----
[profile.release]
debug = 2
----
== rust-toolchain.toml
Before we can build our project, we need to add an additional file to tell cargo to use the nightly toolchain. Copy the `rust-toolchain.toml` from the embassy repo to ours, and trim the list of targets down to only the target triple relevent for our project — in this case, `thumbv7em-none-eabi`:
[source]
----
stm32g474-example
├── .cargo
│   └── config.toml
├── Cargo.toml
├── rust-toolchain.toml
└── src
└── main.rs
----
[source,toml]
----
# Before upgrading check that everything is available on all tier1 targets here:
# https://rust-lang.github.io/rustup-components-history
[toolchain]
channel = "nightly-2023-11-01"
components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
targets = ["thumbv7em-none-eabi"]
----
== build.rs
In order to produce a working binary for our target, cargo requires a custom build script. Copy `build.rs` from the example to our project:
[source]
----
stm32g474-example
├── build.rs
├── .cargo
│ └── config.toml
├── Cargo.toml
├── rust-toolchain.toml
└── src
└── main.rs
----
== Building and running
At this point, were finally ready to build and run our project! Connect your board via a debug probe and run:
[source,bash]
----
cargo run --release
----
should result in a blinking LED (if theres one attached to the pin in `src/main.rs` change it if not!) and the following output:
[source]
----
Compiling stm32g474-example v0.1.0 (/home/you/stm32g474-example)
Finished release [optimized + debuginfo] target(s) in 0.22s
Running `probe-rs run --chip STM32G474RETx target/thumbv7em-none-eabi/release/stm32g474-example`
Erasing sectors ✔ [00:00:00] [#########################################################] 18.00 KiB/18.00 KiB @ 54.09 KiB/s (eta 0s )
Programming pages ✔ [00:00:00] [#########################################################] 17.00 KiB/17.00 KiB @ 35.91 KiB/s (eta 0s ) Finished in 0.817s
0.000000 TRACE BDCR configured: 00008200
└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117
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)) }
└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130
0.000000 INFO Hello World!
└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14
0.000091 INFO high
└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19
0.300201 INFO low
└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23
----

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-macros"
version = "0.2.1"
name = "embassy-executor-macros"
version = "0.4.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "macros for creating the entry point and tasks for embassy-executor"

View File

@ -0,0 +1,15 @@
# embassy-executor-macros
An [Embassy](https://embassy.dev) project.
NOTE: Do not use this crate directly. The macros are re-exported by `embassy-executor`.
## License
This work is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.

View File

@ -7,7 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
- Removed `arch-xtensa`. Use the executor provided by the HAL crate (`esp-hal`, `esp32s3-hal`, etc...) instead.
## 0.4.0 - 2023-12-05
- Removed `arch-xtensa`. Use the executor provided by the HAL crate (`esp-hal`, `esp32s3-hal`, etc...) instead.
- Added an arena allocator for tasks, allowing using the `main` and `task` macros on Rust 1.75 stable. (it is only used if the `nightly` feature is not enabled. When `nightly` is enabled, `type_alias_impl_trait` is used to statically allocate tasks, as before).
## 0.3.3 - 2023-11-15

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-executor"
version = "0.3.3"
version = "0.4.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "async/await executor designed for embedded usage"
@ -32,7 +32,7 @@ defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
rtos-trace = { version = "0.1.2", optional = true }
embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" }
embassy-time = { version = "0.2", path = "../embassy-time", optional = true}
critical-section = "1.1"
@ -66,7 +66,7 @@ executor-thread = []
executor-interrupt = []
# Enable nightly-only features
nightly = ["embassy-macros/nightly"]
nightly = ["embassy-executor-macros/nightly"]
turbowakers = []

View File

@ -51,7 +51,7 @@ mod thread {
use core::arch::asm;
use core::marker::PhantomData;
pub use embassy_macros::main_cortex_m as main;
pub use embassy_executor_macros::main_cortex_m as main;
use crate::{raw, Spawner};

View File

@ -7,7 +7,7 @@ pub use thread::*;
mod thread {
use core::marker::PhantomData;
pub use embassy_macros::main_riscv as main;
pub use embassy_executor_macros::main_riscv as main;
use portable_atomic::{AtomicBool, Ordering};
use crate::{raw, Spawner};

View File

@ -8,7 +8,7 @@ mod thread {
use std::marker::PhantomData;
use std::sync::{Condvar, Mutex};
pub use embassy_macros::main_std as main;
pub use embassy_executor_macros::main_std as main;
use crate::{raw, Spawner};

View File

@ -8,7 +8,7 @@ mod thread {
use core::marker::PhantomData;
pub use embassy_macros::main_wasm as main;
pub use embassy_executor_macros::main_wasm as main;
use js_sys::Promise;
use wasm_bindgen::prelude::*;

View File

@ -6,7 +6,7 @@
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
pub use embassy_macros::task;
pub use embassy_executor_macros::task;
macro_rules! check_at_most_one {
(@amo [$($feats:literal)*] [] [$($res:tt)*]) => {

View File

@ -5,7 +5,7 @@
//! ## WARNING: here be dragons!
//!
//! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe
//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_executor_macros::task) macro, which are fully safe.
#[cfg_attr(target_has_atomic = "ptr", path = "run_queue_atomics.rs")]
#[cfg_attr(not(target_has_atomic = "ptr"), path = "run_queue_critical_section.rs")]
@ -97,7 +97,7 @@ impl TaskRef {
/// A `TaskStorage` must live forever, it may not be deallocated even after the task has finished
/// running. Hence the relevant methods require `&'static self`. It may be reused, however.
///
/// Internally, the [embassy_executor::task](embassy_macros::task) macro allocates an array of `TaskStorage`s
/// Internally, the [embassy_executor::task](embassy_executor_macros::task) macro allocates an array of `TaskStorage`s
/// in a `static`. The most common reason to use the raw `Task` is to have control of where
/// the memory for the task is allocated: on the stack, or on the heap with e.g. `Box::leak`, etc.

View File

@ -115,9 +115,9 @@ impl Spawner {
}
}
// Used by the `embassy_macros::main!` macro to throw an error when spawn
// Used by the `embassy_executor_macros::main!` macro to throw an error when spawn
// fails. This is here to allow conditional use of `defmt::unwrap!`
// without introducing a `defmt` feature in the `embassy_macros` package,
// without introducing a `defmt` feature in the `embassy_executor_macros` package,
// which would require use of `-Z namespaced-features`.
/// Spawn a task into an executor, panicking on failure.
///

View File

@ -1,3 +1,4 @@
//! Atomic reusable ringbuffer.
use core::slice;
use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
@ -14,8 +15,9 @@ use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
/// One concurrent writer and one concurrent reader are supported, even at
/// different execution priorities (like main and irq).
pub struct RingBuffer {
#[doc(hidden)]
pub buf: AtomicPtr<u8>,
pub len: AtomicUsize,
len: AtomicUsize,
// start and end wrap at len*2, not at len.
// This allows distinguishing "full" and "empty".
@ -24,11 +26,16 @@ pub struct RingBuffer {
//
// This avoids having to consider the ringbuffer "full" at len-1 instead of len.
// The usual solution is adding a "full" flag, but that can't be made atomic
#[doc(hidden)]
pub start: AtomicUsize,
#[doc(hidden)]
pub end: AtomicUsize,
}
/// A type which can only read from a ring buffer.
pub struct Reader<'a>(&'a RingBuffer);
/// A type which can only write to a ring buffer.
pub struct Writer<'a>(&'a RingBuffer);
impl RingBuffer {
@ -89,10 +96,12 @@ impl RingBuffer {
Writer(self)
}
/// Return length of buffer.
pub fn len(&self) -> usize {
self.len.load(Ordering::Relaxed)
}
/// Check if buffer is full.
pub fn is_full(&self) -> bool {
let len = self.len.load(Ordering::Relaxed);
let start = self.start.load(Ordering::Relaxed);
@ -101,6 +110,7 @@ impl RingBuffer {
self.wrap(start + len) == end
}
/// Check if buffer is empty.
pub fn is_empty(&self) -> bool {
let start = self.start.load(Ordering::Relaxed);
let end = self.end.load(Ordering::Relaxed);
@ -238,6 +248,7 @@ impl<'a> Writer<'a> {
[(unsafe { buf.add(end) }, n0), (buf, n1)]
}
/// Mark n bytes as written and advance the write index.
pub fn push_done(&mut self, n: usize) {
trace!(" ringbuf: push {:?}", n);
let end = self.0.end.load(Ordering::Relaxed);
@ -323,6 +334,7 @@ impl<'a> Reader<'a> {
(unsafe { buf.add(start) }, n)
}
/// Mark n bytes as read and allow advance the read index.
pub fn pop_done(&mut self, n: usize) {
trace!(" ringbuf: pop {:?}", n);

View File

@ -1,16 +1,20 @@
//! Types for controlling when drop is invoked.
use core::mem;
use core::mem::MaybeUninit;
#[must_use = "to delay the drop handler invokation to the end of the scope"]
/// A type to delay the drop handler invocation.
#[must_use = "to delay the drop handler invocation to the end of the scope"]
pub struct OnDrop<F: FnOnce()> {
f: MaybeUninit<F>,
}
impl<F: FnOnce()> OnDrop<F> {
/// Create a new instance.
pub fn new(f: F) -> Self {
Self { f: MaybeUninit::new(f) }
}
/// Prevent drop handler from running.
pub fn defuse(self) {
mem::forget(self)
}
@ -34,6 +38,7 @@ pub struct DropBomb {
}
impl DropBomb {
/// Create a new instance.
pub fn new() -> Self {
Self { _private: () }
}

View File

@ -1,6 +1,7 @@
#![no_std]
#![allow(clippy::new_without_default)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;

View File

@ -1,3 +1,4 @@
/// Types for the peripheral singletons.
#[macro_export]
macro_rules! peripherals_definition {
($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
@ -29,6 +30,7 @@ macro_rules! peripherals_definition {
};
}
/// Define the peripherals struct.
#[macro_export]
macro_rules! peripherals_struct {
($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
@ -87,6 +89,7 @@ macro_rules! peripherals_struct {
};
}
/// Defining peripheral type.
#[macro_export]
macro_rules! peripherals {
($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
@ -105,6 +108,7 @@ macro_rules! peripherals {
};
}
/// Convenience converting into reference.
#[macro_export]
macro_rules! into_ref {
($($name:ident),*) => {
@ -114,6 +118,7 @@ macro_rules! into_ref {
}
}
/// Implement the peripheral trait.
#[macro_export]
macro_rules! impl_peripheral {
($type:ident) => {

View File

@ -20,6 +20,7 @@ pub struct PeripheralRef<'a, T> {
}
impl<'a, T> PeripheralRef<'a, T> {
/// Create a new reference to a peripheral.
#[inline]
pub fn new(inner: T) -> Self {
Self {

View File

@ -1,3 +1,4 @@
//! Types for dealing with rational numbers.
use core::ops::{Add, Div, Mul};
use num_traits::{CheckedAdd, CheckedDiv, CheckedMul};

View File

@ -1,21 +0,0 @@
# embassy-macros
An [Embassy](https://embassy.dev) project.
Macros for creating the main entry point and tasks that can be spawned by `embassy-executor`.
NOTE: The macros are re-exported by the `embassy-executor` crate which should be used instead of adding a direct dependency on the `embassy-macros` crate.
## Minimum supported Rust version (MSRV)
The `task` and `main` macros require the type alias impl trait (TAIT) nightly feature in order to compile.
## License
This work is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.

View File

@ -97,6 +97,28 @@ mod chip;
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
///
/// Example of how to bind one interrupt:
///
/// ```rust,ignore
/// use embassy_nrf::{bind_interrupts, spim, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
/// });
/// ```
///
/// Example of how to bind multiple interrupts in a single macro invocation:
///
/// ```rust,ignore
/// use embassy_nrf::{bind_interrupts, spim, twim, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
/// SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
/// });
/// ```
// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {

View File

@ -87,5 +87,5 @@ pio = {version= "0.2.1" }
rp2040-boot2 = "0.3"
[dev-dependencies]
embassy-executor = { version = "0.3.3", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] }
embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] }
static_cell = { version = "2" }

View File

@ -86,6 +86,17 @@ embassy_hal_internal::interrupt_mod!(
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
///
/// Example of how to bind one interrupt:
///
/// ```rust,ignore
/// use embassy_rp::{bind_interrupts, usb, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// USBCTRL_IRQ => usb::InterruptHandler<peripherals::USB>;
/// });
/// ```
///
// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {

View File

@ -39,7 +39,7 @@ embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", fea
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
embassy-executor = { version = "0.3.3", path = "../embassy-executor", optional = true }
embassy-executor = { version = "0.4.0", path = "../embassy-executor", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" }
@ -58,7 +58,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8f5fcae8c289c1ad481cc3a2bb37db023a61599c" }
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7117ad49c06fa00c388130a34977e029910083bd", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8f5fcae8c289c1ad481cc3a2bb37db023a61599c", default-features = false, features = ["metadata"]}
[features]

View File

@ -930,6 +930,10 @@ fn main() {
} else if pin.signal.starts_with("INN") {
// TODO handle in the future when embassy supports differential measurements
None
} else if pin.signal.starts_with("IN") && pin.signal.ends_with("b") {
// we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63
let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix("b").unwrap();
Some(32u8 + signal.parse::<u8>().unwrap())
} else if pin.signal.starts_with("IN") {
Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap())
} else {

View File

@ -148,7 +148,7 @@ impl<'d, T: Instance> Adc<'d, T> {
reg.set_cont(false);
reg.set_exttrig(true);
reg.set_swstart(false);
reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
reg.set_extsel(7); // SWSTART
});
// Configure the channel to sample

View File

@ -0,0 +1,413 @@
use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_futures::yield_now;
use embassy_hal_internal::into_ref;
use embassy_time::Instant;
use super::Resolution;
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
use crate::interrupt::typelevel::Interrupt;
use crate::time::Hertz;
use crate::{interrupt, Peripheral};
const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
pub const VDDA_CALIB_MV: u32 = 3300;
pub const ADC_MAX: u32 = (1 << 12) - 1;
pub const VREF_INT: u32 = 1230;
pub enum AdcPowerMode {
AlwaysOn,
DelayOff,
IdleOff,
DelayIdleOff,
}
pub enum Prescaler {
Div1,
Div2,
Div3,
Div4,
}
/// Interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
if T::regs().sr().read().eoc() {
T::regs().cr1().modify(|w| w.set_eocie(false));
} else {
return;
}
T::state().waker.wake();
}
}
fn update_vref<T: Instance>(op: i8) {
static VREF_STATUS: core::sync::atomic::AtomicU8 = core::sync::atomic::AtomicU8::new(0);
if op > 0 {
if VREF_STATUS.fetch_add(1, core::sync::atomic::Ordering::SeqCst) == 0 {
T::regs().ccr().modify(|w| w.set_tsvrefe(true));
}
} else {
if VREF_STATUS.fetch_sub(1, core::sync::atomic::Ordering::SeqCst) == 1 {
T::regs().ccr().modify(|w| w.set_tsvrefe(false));
}
}
}
pub struct Vref<T: Instance>(core::marker::PhantomData<T>);
impl<T: Instance> AdcPin<T> for Vref<T> {}
impl<T: Instance> super::sealed::AdcPin<T> for Vref<T> {
fn channel(&self) -> u8 {
17
}
}
impl<T: Instance> Vref<T> {
/// The value that vref would be if vdda was at 3000mv
pub fn calibrated_value(&self) -> u16 {
crate::pac::VREFINTCAL.data().read().value()
}
pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration {
let vref_val = adc.read(self).await;
Calibration {
vref_cal: self.calibrated_value(),
vref_val,
}
}
}
pub struct Calibration {
vref_cal: u16,
vref_val: u16,
}
impl Calibration {
/// The millivolts that the calibration value was measured at
pub const CALIBRATION_UV: u32 = 3_000_000;
/// Returns the measured VddA in microvolts (uV)
pub fn vdda_uv(&self) -> u32 {
(Self::CALIBRATION_UV * self.vref_cal as u32) / self.vref_val as u32
}
/// Returns the measured VddA as an f32
pub fn vdda_f32(&self) -> f32 {
(Self::CALIBRATION_UV as f32 / 1_000.0) * (self.vref_cal as f32 / self.vref_val as f32)
}
/// Returns a calibrated voltage value as in microvolts (uV)
pub fn cal_uv(&self, raw: u16, resolution: super::Resolution) -> u32 {
(self.vdda_uv() / resolution.to_max_count()) * raw as u32
}
/// Returns a calibrated voltage value as an f32
pub fn cal_f32(&self, raw: u16, resolution: super::Resolution) -> f32 {
raw as f32 * self.vdda_f32() / resolution.to_max_count() as f32
}
}
impl<T: Instance> Drop for Vref<T> {
fn drop(&mut self) {
update_vref::<T>(-1)
}
}
pub struct Temperature<T: Instance>(core::marker::PhantomData<T>);
impl<T: Instance> AdcPin<T> for Temperature<T> {}
impl<T: Instance> super::sealed::AdcPin<T> for Temperature<T> {
fn channel(&self) -> u8 {
16
}
}
impl<T: Instance> Drop for Temperature<T> {
fn drop(&mut self) {
update_vref::<T>(-1)
}
}
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(
adc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
into_ref!(adc);
T::enable_and_reset();
//let r = T::regs();
//r.cr2().write(|w| w.set_align(true));
T::Interrupt::unpend();
unsafe {
T::Interrupt::enable();
}
Self { adc }
}
fn freq() -> Hertz {
let div = T::regs().ccr().read().adcpre() + 1;
ADC_FREQ / div as u32
}
pub async fn set_resolution(&mut self, res: Resolution) {
let was_on = Self::is_on();
if was_on {
self.stop_adc().await;
}
T::regs().cr1().modify(|w| w.set_res(res.into()));
if was_on {
self.start_adc().await;
}
}
pub fn resolution(&self) -> Resolution {
match T::regs().cr1().read().res() {
crate::pac::adc::vals::Res::TWELVEBIT => Resolution::TwelveBit,
crate::pac::adc::vals::Res::TENBIT => Resolution::TenBit,
crate::pac::adc::vals::Res::EIGHTBIT => Resolution::EightBit,
crate::pac::adc::vals::Res::SIXBIT => Resolution::SixBit,
}
}
pub fn enable_vref(&self) -> Vref<T> {
update_vref::<T>(1);
Vref(core::marker::PhantomData)
}
pub fn enable_temperature(&self) -> Temperature<T> {
T::regs().ccr().modify(|w| w.set_tsvrefe(true));
Temperature::<T>(core::marker::PhantomData)
}
/// Perform a single conversion.
async fn convert(&mut self) -> u16 {
let was_on = Self::is_on();
if !was_on {
self.start_adc().await;
}
self.wait_sample_ready().await;
T::regs().sr().write(|_| {});
T::regs().cr1().modify(|w| {
w.set_eocie(true);
w.set_scan(false);
});
T::regs().cr2().modify(|w| {
w.set_swstart(true);
w.set_cont(false);
}); // swstart cleared by HW
let res = poll_fn(|cx| {
T::state().waker.register(cx.waker());
if T::regs().sr().read().eoc() {
let res = T::regs().dr().read().rdata();
Poll::Ready(res)
} else {
Poll::Pending
}
})
.await;
if !was_on {
self.stop_adc().await;
}
res
}
#[inline(always)]
fn is_on() -> bool {
T::regs().sr().read().adons() || T::regs().cr2().read().adon()
}
pub async fn start_adc(&self) {
//defmt::trace!("Turn ADC on");
T::regs().cr2().modify(|w| w.set_adon(true));
//defmt::trace!("Waiting for ADC to turn on");
let mut t = Instant::now();
while !T::regs().sr().read().adons() {
yield_now().await;
if t.elapsed() > embassy_time::Duration::from_millis(1000) {
t = Instant::now();
//defmt::trace!("ADC still not on");
}
}
//defmt::trace!("ADC on");
}
pub async fn stop_adc(&self) {
if T::regs().cr2().read().adon() {
//defmt::trace!("ADC should be on, wait for it to start");
while !T::regs().csr().read().adons1() {
yield_now().await;
}
}
//defmt::trace!("Turn ADC off");
T::regs().cr2().modify(|w| w.set_adon(false));
//defmt::trace!("Waiting for ADC to turn off");
while T::regs().csr().read().adons1() {
yield_now().await;
}
}
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
self.set_sample_sequence(&[pin.channel()]).await;
self.convert().await
}
async fn wait_sample_ready(&self) {
//trace!("Waiting for sample channel to be ready");
while T::regs().sr().read().rcnr() {
yield_now().await;
}
}
pub async fn set_sample_time(&mut self, pin: &mut impl AdcPin<T>, sample_time: SampleTime) {
if Self::get_channel_sample_time(pin.channel()) != sample_time {
self.stop_adc().await;
unsafe {
Self::set_channel_sample_time(pin.channel(), sample_time);
}
self.start_adc().await;
}
}
pub fn get_sample_time(&self, pin: &impl AdcPin<T>) -> SampleTime {
Self::get_channel_sample_time(pin.channel())
}
/// Sets the channel sample time
///
/// ## SAFETY:
/// - ADON == 0 i.e ADC must not be enabled when this is called.
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
match ch {
0..=9 => T::regs().smpr3().modify(|reg| reg.set_smp(ch as _, sample_time)),
10..=19 => T::regs()
.smpr2()
.modify(|reg| reg.set_smp(ch as usize - 10, sample_time)),
20..=29 => T::regs()
.smpr1()
.modify(|reg| reg.set_smp(ch as usize - 20, sample_time)),
30..=31 => T::regs()
.smpr0()
.modify(|reg| reg.set_smp(ch as usize - 30, sample_time)),
_ => panic!("Invalid channel to sample"),
}
}
fn get_channel_sample_time(ch: u8) -> SampleTime {
match ch {
0..=9 => T::regs().smpr3().read().smp(ch as _),
10..=19 => T::regs().smpr2().read().smp(ch as usize - 10),
20..=29 => T::regs().smpr1().read().smp(ch as usize - 20),
30..=31 => T::regs().smpr0().read().smp(ch as usize - 30),
_ => panic!("Invalid channel to sample"),
}
.into()
}
/// Sets the sequence to sample the ADC. Must be less than 28 elements.
async fn set_sample_sequence(&self, sequence: &[u8]) {
assert!(sequence.len() <= 28);
let mut iter = sequence.iter();
T::regs().sqr1().modify(|w| w.set_l((sequence.len() - 1) as _));
for (idx, ch) in iter.by_ref().take(6).enumerate() {
T::regs().sqr5().modify(|w| w.set_sq(idx, *ch));
}
for (idx, ch) in iter.by_ref().take(6).enumerate() {
T::regs().sqr4().modify(|w| w.set_sq(idx, *ch));
}
for (idx, ch) in iter.by_ref().take(6).enumerate() {
T::regs().sqr3().modify(|w| w.set_sq(idx, *ch));
}
for (idx, ch) in iter.by_ref().take(6).enumerate() {
T::regs().sqr2().modify(|w| w.set_sq(idx, *ch));
}
for (idx, ch) in iter.by_ref().take(4).enumerate() {
T::regs().sqr1().modify(|w| w.set_sq(idx, *ch));
}
}
fn get_res_clks(res: Resolution) -> u32 {
match res {
Resolution::TwelveBit => 12,
Resolution::TenBit => 11,
Resolution::EightBit => 9,
Resolution::SixBit => 7,
}
}
fn get_sample_time_clks(sample_time: SampleTime) -> u32 {
match sample_time {
SampleTime::Cycles4 => 4,
SampleTime::Cycles9 => 9,
SampleTime::Cycles16 => 16,
SampleTime::Cycles24 => 24,
SampleTime::Cycles48 => 48,
SampleTime::Cycles96 => 96,
SampleTime::Cycles192 => 192,
SampleTime::Cycles384 => 384,
}
}
pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
let res_clks = Self::get_res_clks(self.resolution());
let us_clks = us * Self::freq().0 / 1_000_000;
let clks = us_clks.saturating_sub(res_clks);
match clks {
0..=4 => SampleTime::Cycles4,
5..=9 => SampleTime::Cycles9,
10..=16 => SampleTime::Cycles16,
17..=24 => SampleTime::Cycles24,
25..=48 => SampleTime::Cycles48,
49..=96 => SampleTime::Cycles96,
97..=192 => SampleTime::Cycles192,
193.. => SampleTime::Cycles384,
}
}
pub fn us_for_cfg(&self, res: Resolution, sample_time: SampleTime) -> u32 {
let res_clks = Self::get_res_clks(res);
let sample_clks = Self::get_sample_time_clks(sample_time);
(res_clks + sample_clks) * 1_000_000 / Self::freq().0
}
}
impl<'d, T: Instance> Drop for Adc<'d, T> {
fn drop(&mut self) {
while !T::regs().sr().read().adons() {}
T::regs().cr2().modify(|w| w.set_adon(false));
T::disable();
}
}

View File

@ -3,6 +3,7 @@
#[cfg(not(adc_f3_v2))]
#[cfg_attr(adc_f1, path = "f1.rs")]
#[cfg_attr(adc_f3, path = "f3.rs")]
#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
#[cfg_attr(adc_v1, path = "v1.rs")]
#[cfg_attr(adc_v2, path = "v2.rs")]
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
@ -26,20 +27,20 @@ use crate::peripherals;
pub struct Adc<'d, T: Instance> {
#[allow(unused)]
adc: crate::PeripheralRef<'d, T>,
#[cfg(not(adc_f3_v2))]
#[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))]
sample_time: SampleTime,
}
pub(crate) mod sealed {
#[cfg(any(adc_f1, adc_f3, adc_v1))]
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
use embassy_sync::waitqueue::AtomicWaker;
#[cfg(any(adc_f1, adc_f3, adc_v1))]
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
pub struct State {
pub waker: AtomicWaker,
}
#[cfg(any(adc_f1, adc_f3, adc_v1))]
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
impl State {
pub const fn new() -> Self {
Self {
@ -54,11 +55,11 @@ pub(crate) mod sealed {
pub trait Instance: InterruptableInstance {
fn regs() -> crate::pac::adc::Adc;
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon;
#[cfg(adc_f3)]
fn frequency() -> crate::time::Hertz;
#[cfg(any(adc_f1, adc_f3, adc_v1))]
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
fn state() -> &'static State;
}
@ -74,9 +75,9 @@ pub(crate) mod sealed {
}
}
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0)))]
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0))]
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
@ -89,7 +90,7 @@ foreach_adc!(
crate::pac::$inst
}
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon {
return crate::pac::$common_inst
}
@ -99,7 +100,7 @@ foreach_adc!(
unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
}
#[cfg(any(adc_f1, adc_f3, adc_v1))]
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
fn state() -> &'static sealed::State {
static STATE: sealed::State = sealed::State::new();
&STATE

View File

@ -1,5 +1,6 @@
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Resolution {
TwelveBit,
TenBit,
@ -9,6 +10,7 @@ pub enum Resolution {
#[cfg(adc_v4)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Resolution {
SixteenBit,
FourteenBit,
@ -19,7 +21,7 @@ pub enum Resolution {
impl Default for Resolution {
fn default() -> Self {
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
{
Self::TwelveBit
}
@ -40,7 +42,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
}
}
@ -56,7 +58,7 @@ impl Resolution {
Resolution::TwelveBit => (1 << 12) - 1,
Resolution::TenBit => (1 << 10) - 1,
Resolution::EightBit => (1 << 8) - 1,
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
Resolution::SixBit => (1 << 6) - 1,
}
}

View File

@ -3,6 +3,7 @@ macro_rules! impl_sample_time {
($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SampleTime {
$(
#[doc = concat!($doc, " ADC clock cycles.")]
@ -18,6 +19,14 @@ macro_rules! impl_sample_time {
}
}
impl From<crate::pac::adc::vals::SampleTime> for SampleTime {
fn from(sample_time: crate::pac::adc::vals::SampleTime) -> SampleTime {
match sample_time {
$(crate::pac::adc::vals::SampleTime::$pac_variant => SampleTime::$variant),*
}
}
}
impl Default for SampleTime {
fn default() -> Self {
Self::$default
@ -121,3 +130,19 @@ impl_sample_time!(
("601.5", Cycles601_5, CYCLES601_5)
)
);
#[cfg(any(adc_f3_v1_1))]
impl_sample_time!(
"4",
Cycles4,
(
("4", Cycles4, CYCLES4),
("9", Cycles9, CYCLES9),
("16", Cycles16, CYCLES16),
("24", Cycles24, CYCLES24),
("48", Cycles48, CYCLES48),
("96", Cycles96, CYCLES96),
("192", Cycles192, CYCLES192),
("384", Cycles384, CYCLES384)
)
);

View File

@ -1,6 +1,6 @@
#![macro_use]
#[cfg_attr(can_bxcan, path = "bxcan.rs")]
#[cfg_attr(can_fdcan, path = "fdcan.rs")]
#[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")]
mod _version;
pub use _version::*;

View File

@ -90,6 +90,29 @@ pub use crate::_generated::interrupt;
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
///
/// Example of how to bind one interrupt:
///
/// ```rust,ignore
/// use embassy_stm32::{bind_interrupts, usb_otg, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
/// });
/// ```
///
/// Example of how to bind multiple interrupts, and multiple handlers to each interrupt, in a single macro invocation:
///
/// ```rust,ignore
/// use embassy_stm32::{bind_interrupts, i2c, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
/// I2C2_3 => i2c::EventInterruptHandler<peripherals::I2C2>, i2c::ErrorInterruptHandler<peripherals::I2C2>,
/// i2c::EventInterruptHandler<peripherals::I2C3>, i2c::ErrorInterruptHandler<peripherals::I2C3>;
/// });
/// ```
// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {

View File

@ -308,6 +308,7 @@ pub(crate) unsafe fn init(config: Config) {
sys: sys_clk,
hclk1: ahb_freq,
hclk2: ahb_freq,
hclk3: ahb_freq,
pclk1: apb1_freq,
pclk1_tim: apb1_tim_freq,
pclk2: apb2_freq,
@ -315,6 +316,8 @@ pub(crate) unsafe fn init(config: Config) {
adc: adc12_ck,
adc34: adc345_ck,
pll1_p: None,
pll1_q: None, // TODO
hse: None, // TODO
rtc,
});
}

View File

@ -95,6 +95,7 @@ pub struct Clocks {
rcc_h7rm0433,
rcc_h7ab,
rcc_u5,
rcc_g4,
rcc_wb,
rcc_wl5,
rcc_wle
@ -119,7 +120,7 @@ pub struct Clocks {
#[cfg(any(stm32g4, rcc_l4))]
pub pll1_p: Option<Hertz>,
#[cfg(any(stm32h5, stm32h7, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_l4))]
#[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g4))]
pub pll1_q: Option<Hertz>,
#[cfg(any(stm32h5, stm32h7))]
pub pll2_p: Option<Hertz>,
@ -167,7 +168,7 @@ pub struct Clocks {
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0))]
pub lse: Option<Hertz>,
#[cfg(any(stm32h5, stm32h7))]
#[cfg(any(stm32h5, stm32h7, stm32g4))]
pub hse: Option<Hertz>,
#[cfg(stm32h5)]

View File

@ -251,4 +251,4 @@ wasm-timer = { version = "0.2.5", optional = true }
[dev-dependencies]
serial_test = "0.9"
critical-section = { version = "1.1", features = ["std"] }
embassy-executor = { version = "0.3.3", path = "../embassy-executor" }
embassy-executor = { version = "0.4.0", path = "../embassy-executor" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] }
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] }
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] }
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -16,7 +16,7 @@ log = [
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time" }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }

View File

@ -13,7 +13,7 @@ nightly = [
[dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "std", ] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32c031c6 to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
defmt = "0.3"

View File

@ -15,7 +15,7 @@ defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = "0.3"
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
static_cell = { version = "2", features = ["nightly"]}
portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32f103c8 to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32f207zg to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
defmt = "0.3"

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32f303ze to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32f429zi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32f767zi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
embedded-io-async = { version = "0.6.1" }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32g071rb to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
defmt = "0.3"

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32g491re to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32h563zi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32h743bi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -92,7 +92,7 @@ async fn main(spawner: Spawner) -> ! {
let stack = &*make_static!(Stack::new(
device,
config,
make_static!(StackResources::<2>::new()),
make_static!(StackResources::<3>::new()),
seed
));
@ -113,6 +113,7 @@ async fn main(spawner: Spawner) -> ! {
socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
// You need to start a server on the host machine, for example: `nc -l 8000`
let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
info!("connecting...");
let r = socket.connect(remote_endpoint).await;

View File

@ -93,7 +93,7 @@ async fn main(spawner: Spawner) -> ! {
let stack = &*make_static!(Stack::new(
device,
config,
make_static!(StackResources::<2>::new()),
make_static!(StackResources::<3>::new()),
seed
));
@ -109,6 +109,7 @@ async fn main(spawner: Spawner) -> ! {
let client = TcpClient::new(&stack, &state);
loop {
// You need to start a server on the host machine, for example: `nc -l 8000`
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(10, 42, 0, 1), 8000));
info!("connecting...");

View File

@ -12,7 +12,7 @@ nightly = ["embassy-executor/nightly"]
# Change stm32l072cz to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
defmt = "0.3"

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32l4s5vi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32l552ze to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32u585ai to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }

View File

@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
# Change stm32wl55jc-cm4 to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }

View File

@ -9,7 +9,7 @@ crate-type = ["cdylib"]
[dependencies]
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["log", "wasm", ] }
wasm-logger = "0.2.0"

View File

@ -9,7 +9,7 @@ teleprobe-meta = "1"
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt", ] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
critical-section = { version = "1.1.1", features = ["restore-state-bool"] }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync" }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] }
embassy-time = { version = "0.2", path = "../../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
teleprobe-meta = "1.1"
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", ] }
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }

View File

@ -10,14 +10,14 @@ stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"]
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"]
stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"]
stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin", "rng"]
stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac-adc-pin", "sdmmc"]
stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac-adc-pin"]
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"]
stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"]
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"]
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin", "rng"]
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"]
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"]
stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
@ -41,7 +41,7 @@ ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
embassy-stm32-wpan = []
not-gpdma = []
dac-adc-pin = []
dac = []
cm0 = ["portable-atomic/unsafe-assume-single-core"]
@ -49,7 +49,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"]
teleprobe-meta = "1"
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@ -84,7 +84,12 @@ required-features = [ "can",]
[[bin]]
name = "dac"
path = "src/bin/dac.rs"
required-features = [ "dac-adc-pin",]
required-features = [ "dac",]
[[bin]]
name = "dac_l1"
path = "src/bin/dac_l1.rs"
required-features = [ "stm32l152re",]
[[bin]]
name = "eth"

View File

@ -1,7 +1,7 @@
#![no_std]
#![no_main]
// required-features: dac-adc-pin
// required-features: dac
#[path = "../common.rs"]
mod common;
@ -22,12 +22,13 @@ async fn main(_spawner: Spawner) {
// Initialize the board and obtain a Peripherals instance
let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
let adc = peri!(p, ADC);
let dac = peri!(p, DAC);
let dac_pin = peri!(p, DAC_PIN);
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
let mut adc = Adc::new(p.ADC1, &mut Delay);
let mut adc = Adc::new(adc, &mut Delay);
#[cfg(feature = "stm32h755zi")]
let normalization_factor = 256;

View File

@ -0,0 +1,86 @@
#![no_std]
#![no_main]
// required-features: stm32l152re
#[path = "../common.rs"]
mod common;
use core::f32::consts::PI;
use common::*;
use defmt::assert;
use embassy_executor::Spawner;
use embassy_stm32::adc::Adc;
use embassy_stm32::dac::{DacCh1, Value};
use embassy_stm32::dma::NoDma;
use embassy_stm32::{bind_interrupts, peripherals};
use embassy_time::Timer;
use micromath::F32Ext;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
ADC1 => embassy_stm32::adc::InterruptHandler<peripherals::ADC>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
// Initialize the board and obtain a Peripherals instance
let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
let adc = peri!(p, ADC);
let dac = peri!(p, DAC);
let dac_pin = peri!(p, DAC_PIN);
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
let mut adc = Adc::new(adc, Irqs);
#[cfg(feature = "stm32h755zi")]
let normalization_factor = 256;
#[cfg(any(
feature = "stm32f429zi",
feature = "stm32f446re",
feature = "stm32g071rb",
feature = "stm32l152re",
))]
let normalization_factor: i32 = 16;
dac.set(Value::Bit8(0));
// Now wait a little to obtain a stable value
Timer::after_millis(30).await;
let offset = adc.read(&mut adc_pin).await;
for v in 0..=255 {
// First set the DAC output value
let dac_output_val = to_sine_wave(v);
dac.set(Value::Bit8(dac_output_val));
// Now wait a little to obtain a stable value
Timer::after_millis(30).await;
// Need to steal the peripherals here because PA4 is obviously in use already
let measured = adc.read(&mut unsafe { embassy_stm32::Peripherals::steal() }.PA4).await;
// Calibrate and normalize the measurement to get close to the dac_output_val
let measured_normalized = ((measured as i32 - offset as i32) / normalization_factor) as i16;
info!("value / measured: {} / {}", dac_output_val, measured_normalized);
// The deviations are quite enormous but that does not matter since this is only a quick test
assert!((dac_output_val as i16 - measured_normalized).abs() < 15);
}
info!("Test OK");
cortex_m::asm::bkpt();
}
fn to_sine_wave(v: u8) -> u8 {
if v >= 128 {
// top half
let r = PI * ((v - 128) as f32 / 128.0);
(r.sin() * 128.0 + 127.0) as u8
} else {
// bottom half
let r = PI + PI * (v as f32 / 128.0);
(r.sin() * 128.0 + 127.0) as u8
}
}

View File

@ -101,14 +101,14 @@ define_peris!(
define_peris!(
UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2,
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2,
DAC = DAC1, DAC_PIN = PA4,
ADC = ADC1, DAC = DAC1, DAC_PIN = PA4,
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
);
#[cfg(feature = "stm32f429zi")]
define_peris!(
UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1,
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2,
DAC = DAC, DAC_PIN = PA4,
ADC = ADC1, DAC = DAC, DAC_PIN = PA4,
CAN = CAN1, CAN_RX = PD0, CAN_TX = PD1,
@irq UART = {USART6 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART6>;},
);
@ -116,7 +116,7 @@ define_peris!(
define_peris!(
UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA2_CH7, UART_RX_DMA = DMA2_CH5,
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2,
DAC = DAC, DAC_PIN = PA4,
ADC = ADC1, DAC = DAC, DAC_PIN = PA4,
CAN = CAN1, CAN_RX = PA11, CAN_TX = PA12,
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
);
@ -130,7 +130,7 @@ define_peris!(
define_peris!(
UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1,
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1,
DAC = DAC1, DAC_PIN = PA4,
ADC = ADC1, DAC = DAC1, DAC_PIN = PA4,
@irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
);
#[cfg(feature = "stm32h7a3zi")]
@ -191,6 +191,7 @@ define_peris!(
define_peris!(
UART = USART3, UART_TX = PB10, UART_RX = PB11, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3,
SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
ADC = ADC, DAC = DAC, DAC_PIN = PA4,
@irq UART = {USART3 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART3>;},
);
#[cfg(feature = "stm32l552ze")]