aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/modules/ROOT/nav.adoc1
-rw-r--r--docs/modules/ROOT/pages/basic_application.adoc9
-rw-r--r--docs/modules/ROOT/pages/delaying_a_task.adoc28
-rw-r--r--docs/modules/ROOT/pages/getting_started.adoc73
-rw-r--r--docs/modules/ROOT/pages/index.adoc50
5 files changed, 139 insertions, 22 deletions
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index 13459099f..8d7f6f411 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -3,6 +3,7 @@
3** xref:project_structure.adoc[Project Structure] 3** xref:project_structure.adoc[Project Structure]
4* xref:layer_by_layer.adoc[Bare metal to async] 4* xref:layer_by_layer.adoc[Bare metal to async]
5* xref:runtime.adoc[Executor] 5* xref:runtime.adoc[Executor]
6* xref:delaying_a_task.adoc[Delaying a Task]
6* xref:hal.adoc[HAL] 7* xref:hal.adoc[HAL]
7** xref:nrf.adoc[nRF] 8** xref:nrf.adoc[nRF]
8** xref:stm32.adoc[STM32] 9** xref:stm32.adoc[STM32]
diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
index 6d0d04383..95792d5a0 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -6,9 +6,11 @@ So you've got one of the xref:examples.adoc[examples] running, but what now? Let
6 6
7The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/modules/ROOT/examples/basic[here]. 7The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/modules/ROOT/examples/basic[here].
8 8
9NOTE: If you’re 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 we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
10
9=== Bare metal 11=== Bare metal
10 12
11The first thing you'll notice is a few declarations, two of which indicate that Embassy is suitable for bare metal development: 13The first thing you’ll 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).
12 14
13[source,rust] 15[source,rust]
14---- 16----
@@ -48,9 +50,9 @@ NOTE: Notice that there is no busy waiting going on in this task. It is using th
48 50
49=== Main 51=== Main
50 52
51The 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. 53The 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.
52 54
53The `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: 55We then initialize the HAL with a default config, which gives us a `Peripherals` struct we can use to access the MCU’s various peripherals. In this case, we want to configure one of the pins as a GPIO output driving the LED:
54 56
55[source,rust] 57[source,rust]
56---- 58----
@@ -60,7 +62,6 @@ include::example$basic/src/main.rs[lines="22..-1"]
60What 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: 62What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
61 63
62. Creates an Embassy Executor 64. Creates an Embassy Executor
63. Initializes the microcontroller HAL to get the `Peripherals`
64. Defines a main task for the entry point 65. Defines a main task for the entry point
65. Runs the executor spawning the main task 66. Runs the executor spawning the main task
66 67
diff --git a/docs/modules/ROOT/pages/delaying_a_task.adoc b/docs/modules/ROOT/pages/delaying_a_task.adoc
new file mode 100644
index 000000000..3171e3515
--- /dev/null
+++ b/docs/modules/ROOT/pages/delaying_a_task.adoc
@@ -0,0 +1,28 @@
1= Delaying a Task
2
3In 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
4that 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
5to delay the current task for a specified interval of time.
6
7Timing is serviced by the `embassy::time::Timer` struct, which provides two timing methods.
8
9`Timer::at` creates a future that completes at the specified `Instant`, relative to the system boot time.
10`Timer::after` creates a future that completes after the specified `Duration`, relative to when the future was created.
11
12An example of a delay is provided as follows:
13
14[,rust]
15----
16use embassy::executor::{task, Executor};
17use embassy::time::{Duration, Timer};
18
19#[task]
20/// Task that ticks periodically
21async fn tick_periodic() -> ! {
22 loop {
23 rprintln!("tick!");
24 // async sleep primitive, suspends the task for 500ms.
25 Timer::after(Duration::from_millis(500)).await;
26 }
27}
28---- \ No newline at end of file
diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc
index 2c6f4b1ee..ab819ac2a 100644
--- a/docs/modules/ROOT/pages/getting_started.adoc
+++ b/docs/modules/ROOT/pages/getting_started.adoc
@@ -9,7 +9,9 @@ If you don't have any supported board, don't worry: you can also run embassy on
9 9
10== Getting a board with examples 10== Getting a board with examples
11 11
12Embassy supports many microcontroller families, but the easiest ways to get started is if you have one of the more common development kits. 12Embassy supports many microcontroller families, but the quickest way to get started is by using a board which Embassy has existing example code for.
13
14This list is non-exhaustive. If your board isn’t 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.
13 15
14=== nRF kits 16=== nRF kits
15 17
@@ -36,7 +38,7 @@ Embassy supports many microcontroller families, but the easiest ways to get star
36 38
37== Running an example 39== Running an example
38 40
39First you need to clone the [github repository]; 41First you need to clone the link:https://github.com/embassy-rs/embassy[github repository];
40 42
41[source, bash] 43[source, bash]
42---- 44----
@@ -44,17 +46,80 @@ git clone https://github.com/embassy-rs/embassy.git
44cd embassy 46cd embassy
45---- 47----
46 48
47You can run an example by opening a terminal and entering the following commands: 49Once 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 world’s equivalent of “Hello World”.
48 50
49[source, bash] 51[source, bash]
50---- 52----
51cd examples/nrf52840 53cd examples/nrf52840
54cargo build --bin blinky --release
55----
56
57Once you’ve confirmed you can build the example, connect your computer to your board with a debug probe and run it on hardware:
58
59[source, bash]
60----
52cargo run --bin blinky --release 61cargo run --bin blinky --release
53---- 62----
54 63
64If everything worked correctly, you should see a blinking LED on your board, and debug output similar to this on your computer:
65
66[source]
67----
68 Finished dev [unoptimized + debuginfo] target(s) in 1m 56s
69 Running `probe-run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky`
70(HOST) INFO flashing program (71.36 KiB)
71(HOST) INFO success!
72────────────────────────────────────────────────────────────────────────────────
730 INFO Hello World!
74└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:18
751 INFO high
76└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:23
772 INFO low
78└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27
793 INFO high
80└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:23
814 INFO low
82└─ blinky::__embassy_main::task::{generator#0} @ src/bin/blinky.rs:27
83----
84
85NOTE: How does the `cargo run` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips.
86
87=== It didn’t work!
88
89If you hare having issues when running `cargo run --release`, please check the following:
90
91* You are specifying the correct `--chip on the command line``, OR
92* You have set `.cargo/config.toml`'s run line to the correct chip, AND
93* You have changed `examples/Cargo.toml`'s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature)
94
95At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin.
96
97If you are trying to run an example with `cargo run --release` and you see the following output:
98[source]
99----
1000.000000 INFO Hello World!
101└─ <invalid location: defmt frame-index: 14>
1020.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) }
103└─ <invalid location: defmt frame-index: 124>
1040.000061 TRACE allocating type=Interrupt mps=8 interval_ms=255, dir=In
105└─ <invalid location: defmt frame-index: 68>
1060.000091 TRACE index=1
107└─ <invalid location: defmt frame-index: 72>
108----
109
110To get rid of the frame-index error add the following to your `Cargo.toml`:
111
112[source,toml]
113----
114[profile.release]
115debug = 2
116----
117
118If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room].
119
55== What's next? 120== What's next?
56 121
57Congratulations, you have your first Embassy application running! Here are some alternatives on where to go from here: 122Congratulations, you have your first Embassy application running! Here are some suggestions for where to go from here:
58 123
59* Read more about the xref:runtime.adoc[executor]. 124* Read more about the xref:runtime.adoc[executor].
60* Read more about the xref:hal.adoc[HAL]. 125* Read more about the xref:hal.adoc[HAL].
diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc
index c6dead464..6fba80eda 100644
--- a/docs/modules/ROOT/pages/index.adoc
+++ b/docs/modules/ROOT/pages/index.adoc
@@ -4,34 +4,56 @@ Embassy is a project to make async/await a first-class option for embedded devel
4 4
5== What is async? 5== What is async?
6 6
7When 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. 7When 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.
8 8
9Async-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. 9Because 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.
10
11In 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.
12
13Compared 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.
10 14
11== What is Embassy? 15== What is Embassy?
12 16
13The Embassy project consists of several crates that you can use together or independently: 17The Embassy project consists of several crates that you can use together or independently:
14 18
15* **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. 19=== Executor
20The 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.
21
22=== Hardware Abstraction Layers
23HALs implement safe Rust API which let you use peripherals such as USART, UART, I2C, SPI, CAN, and USB without having to directly manipulate registers.
24
25Embassy 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.
26
27The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
28
29* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
30* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
31* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
32* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
16 33
17* **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.
18** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
19** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
20** link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
21** link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
22+
23NOTE: 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, 34NOTE: 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,
24as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits. 35as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
25 36
26* **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. 37=== Networking
38The 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.
39
40=== Bluetooth
41The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
42
43=== LoRa
44link: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.
45
46=== USB
47link: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.
27 48
28* **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. 49=== Bootloader and DFU
50link: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.
29 51
30* **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. 52== What is DMA?
31 53
32* **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. 54For 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.
33 55
34* **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. 56The 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.
35 57
36== Resources 58== Resources
37 59